// This is a part of the Microsoft Foundation Classes C++ library. // Copyright (C) 1992-1998 Microsoft Corporation // All rights reserved. // // This source code is only intended as a supplement to the // Microsoft Foundation Classes Reference and related // electronic documentation provided with the library. // See these sources for detailed information regarding the // Microsoft Foundation Classes product. #include "stdafx.h" #ifdef AFX_OLE_SEG #pragma code_seg(AFX_OLE_SEG) #endif #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #define new DEBUG_NEW #pragma inline_depth(0) ///////////////////////////////////////////////////////////////////////////// // _AfxBindStatusCallback for CAsyncMonikerFile implementation class _AfxBindStatusCallback: public IBindStatusCallback { private: class CInnerUnknown : public IUnknown { protected: _AfxBindStatusCallback* m_pThis; friend class _AfxBindStatusCallback; public: inline CInnerUnknown() { } inline void SetpThis(_AfxBindStatusCallback* pThis) { ASSERT(pThis != NULL); m_pThis = pThis; } STDMETHOD_(ULONG, AddRef)() { return InterlockedIncrement((long*)&m_pThis->m_dwRef); } STDMETHOD_(ULONG, Release)() { unsigned long lResult = InterlockedDecrement((long*)&m_pThis->m_dwRef); if (lResult == 0) delete m_pThis; return lResult; } STDMETHOD(QueryInterface)(REFIID iid, void** ppvObject) { if (!ppvObject) return E_POINTER; // check for the interfaces this object knows about if (iid == IID_IUnknown) { *ppvObject = (IUnknown*)this; AddRef(); return S_OK; } if (iid == IID_IBindStatusCallback) { *ppvObject = (IBindStatusCallback*)m_pThis; m_pThis->AddRef(); return S_OK; } // otherwise, incorrect IID, and thus error return E_NOINTERFACE; } }; public: inline _AfxBindStatusCallback(CAsyncMonikerFile* pOwner, IUnknown* pUnkControlling) : m_pOwner(pOwner), m_dwRef(0) { m_UnkInner.SetpThis(this); ASSERT(pOwner); #ifdef _AFXDLL m_pModuleState = AfxGetModuleState(); ASSERT(m_pModuleState != NULL); #endif m_pUnkControlling = pUnkControlling ? pUnkControlling : (IUnknown*)&m_UnkInner; AfxOleLockApp(); } inline ~_AfxBindStatusCallback() { AFX_MANAGE_STATE(m_pModuleState); AfxOleUnlockApp(); } inline void Orphan() { m_pOwner = NULL; } STDMETHOD_(ULONG, AddRef)() { return m_pUnkControlling->AddRef(); } STDMETHOD_(ULONG, Release)() { return m_pUnkControlling->Release(); } STDMETHOD(QueryInterface)(REFIID iid, void** ppvObject) { return m_pUnkControlling->QueryInterface(iid, ppvObject); } const CAsyncMonikerFile* GetOwner() const{ return m_pOwner; } DWORD GetRefcount() const { return m_dwRef; } const IUnknown* GetControllingUnknown() const { return m_pUnkControlling; } IUnknown* GetControllingUnknown() { return m_pUnkControlling; } const IUnknown* GetInnerUnknown() const { return &m_UnkInner; } IUnknown* GetInnerUnknown() { return &m_UnkInner; } const _AfxBindStatusCallback* GetpThisOfInnerUnknown() const { return m_UnkInner.m_pThis; } #ifdef _AFXDLL const AFX_MODULE_STATE* GetModuleState() const { return m_pModuleState; } #endif protected: friend class CInnerUnknown; DWORD m_dwRef; private: IUnknown* m_pUnkControlling; CInnerUnknown m_UnkInner; CAsyncMonikerFile* m_pOwner; #ifdef _AFXDLL AFX_MODULE_STATE* m_pModuleState; #endif STDMETHOD(GetBindInfo)( DWORD __RPC_FAR *pgrfBINDF, BINDINFO __RPC_FAR *pbindinfo) { ASSERT(m_pOwner); if (!pgrfBINDF || !pbindinfo) return E_POINTER; if (pbindinfo->cbSizeszExtraInfo = NULL; TRY { *pgrfBINDF = m_pOwner->GetBindInfo(); } CATCH_ALL(e) { HRESULT hr = ResultFromScode(COleException::Process(e)); DELETE_EXCEPTION(e); return hr; } END_CATCH_ALL return S_OK; } STDMETHOD(OnStartBinding)( DWORD dwReserved, IBinding __RPC_FAR *pBinding) { ASSERT(m_pOwner); UNUSED_ALWAYS(dwReserved); if (!pBinding) return E_POINTER; if (!m_pOwner) return E_FAIL; AFX_MANAGE_STATE(m_pModuleState); TRY { m_pOwner->SetBinding(pBinding); m_pOwner->OnStartBinding(); } CATCH_ALL(e) { HRESULT hr = ResultFromScode(COleException::Process(e)); DELETE_EXCEPTION(e); return hr; } END_CATCH_ALL return S_OK; } STDMETHOD(GetPriority)(LONG __RPC_FAR *pnPriority) { ASSERT(m_pOwner); if (!pnPriority) return E_POINTER; if (!m_pOwner) return E_FAIL; AFX_MANAGE_STATE(m_pModuleState); TRY { *pnPriority = m_pOwner->GetPriority(); } CATCH_ALL(e) { HRESULT hr = ResultFromScode(COleException::Process(e)); DELETE_EXCEPTION(e); return hr; } END_CATCH_ALL return S_OK; } STDMETHOD(OnProgress)( ULONG ulProgress, ULONG ulProgressMax, ULONG ulStatusCode, LPCOLESTR szStatusText) { ASSERT(m_pOwner); if (!m_pOwner) return E_FAIL; USES_CONVERSION; AFX_MANAGE_STATE(m_pModuleState); TRY { m_pOwner->OnProgress(ulProgress, ulProgressMax, ulStatusCode, OLE2CT(szStatusText)); } CATCH_ALL(e) { HRESULT hr = ResultFromScode(COleException::Process(e)); DELETE_EXCEPTION(e); return hr; } END_CATCH_ALL return S_OK; } STDMETHOD(OnDataAvailable)( DWORD grfBSCF, DWORD dwSize, FORMATETC __RPC_FAR *pformatetc, STGMEDIUM __RPC_FAR *pstgmed) { ASSERT(m_pOwner); if (!m_pOwner) return E_FAIL; AFX_MANAGE_STATE(m_pModuleState); TRY { m_pOwner->SetFormatEtc(pformatetc); if (grfBSCF&BSCF_FIRSTDATANOTIFICATION) { if (!pstgmed || !pformatetc) return E_POINTER; if ((pstgmed->tymed != TYMED_ISTREAM) || !pstgmed->pstm) return E_UNEXPECTED; ASSERT(!m_pOwner->GetStream()); m_pOwner->COleStreamFile::Attach(pstgmed->pstm); pstgmed->pstm->AddRef(); } m_pOwner->OnDataAvailable(dwSize, grfBSCF); } CATCH_ALL(e) { m_pOwner->SetFormatEtc(NULL); HRESULT hr = ResultFromScode(COleException::Process(e)); DELETE_EXCEPTION(e); return hr; } END_CATCH_ALL m_pOwner->SetFormatEtc(NULL); return S_OK; } STDMETHOD(OnLowResource)(DWORD dwReserved) { ASSERT(m_pOwner); if (!m_pOwner) return E_FAIL; AFX_MANAGE_STATE(m_pModuleState); UNUSED_ALWAYS(dwReserved); TRY { m_pOwner->OnLowResource(); } CATCH_ALL(e) { HRESULT hr = ResultFromScode(COleException::Process(e)); DELETE_EXCEPTION(e); return hr; } END_CATCH_ALL return S_OK; } STDMETHOD(OnStopBinding)(HRESULT hresult, LPCOLESTR szError) { //Does not ASSERT(m_pOwner) because this can be called //after it has been Orphan()ed. if (!m_pOwner) return E_FAIL; USES_CONVERSION; AFX_MANAGE_STATE(m_pModuleState); ASSERT(m_pOwner->GetBinding()); TRY { m_pOwner->m_bStopBindingReceived = TRUE; m_pOwner->OnStopBinding(hresult, OLE2CT(szError)); if (m_pOwner) { // Calling EndCallbacks will result in a inner Release. Our // caller has an inner refcount on us, possibly through the // controlling unknown, and we have an inner refcount from // m_pOwner, so m_dwRef > 1 and it's safe to call EndCallbacks. ASSERT(m_dwRef > 1); m_pOwner->EndCallbacks(); } } CATCH_ALL(e) { HRESULT hr = ResultFromScode(COleException::Process(e)); DELETE_EXCEPTION(e); return hr; } END_CATCH_ALL return S_OK; } STDMETHOD(OnObjectAvailable)(REFIID riid, IUnknown __RPC_FAR *punk) { #ifdef _DEBUG AFX_MANAGE_STATE(m_pModuleState); ASSERT(FALSE); // This function should never be called. #endif //_DEBUG UNUSED_ALWAYS(riid); UNUSED_ALWAYS(punk); return E_UNEXPECTED; } }; ///////////////////////////////////////////////////////////////////////////// // Helper functions for CAsyncMonikerFile implementation AFX_STATIC inline IBindHost* AFXAPI _AfxTrySPForBindHost(IServiceProvider* pServiceProvider) { ASSERT(pServiceProvider); IBindHost* pBindHost; HRESULT hr=pServiceProvider->QueryService(SID_IBindHost, IID_IBindHost, (void**)&pBindHost); if (SUCCEEDED(hr)) return pBindHost; else return NULL; } AFX_STATIC inline IBindHost* AFXAPI _AfxTryQIForBindHost(IUnknown* pUnk) { ASSERT(pUnk); IPTR(IBindHost) pBindHost; HRESULT hr = pBindHost.QueryInterface(pUnk); if (SUCCEEDED(hr)) return pBindHost; else return NULL; } ///////////////////////////////////////////////////////////////////////////// // CAsyncMonikerFile implementation CAsyncMonikerFile::CAsyncMonikerFile() : m_pFormatEtc(NULL), m_pAfxBSCCurrent(NULL) { } CAsyncMonikerFile::~CAsyncMonikerFile() { CAsyncMonikerFile::Close(); } void CAsyncMonikerFile::EndCallbacks() { if (m_pAfxBSCCurrent) { m_pAfxBSCCurrent->Orphan(); IUnknown* pUnkInner = m_pAfxBSCCurrent->GetInnerUnknown(); ASSERT(pUnkInner != NULL); pUnkInner->Release(); m_pAfxBSCCurrent = NULL; } } UINT CAsyncMonikerFile::Read(void* lpBuf, UINT nCount) { ASSERT_VALID(this); ASSERT(m_lpStream != NULL); DWORD dwBytesRead; HRESULT hr = _AfxReadFromStream(m_lpStream, lpBuf, nCount, dwBytesRead); if ((hr != S_OK) && (hr != S_ASYNCHRONOUS) && (hr != E_PENDING)) _AfxThrowOleFileException(hr); // always return number of bytes read return (UINT)dwBytesRead; } void CAsyncMonikerFile::Close() { ASSERT_VALID(this); if (m_Binding.GetInterfacePtr()) { if (!m_bStopBindingReceived) m_Binding->Abort(); m_Binding.Release(); } EndCallbacks(); CMonikerFile::Close(); } BOOL CAsyncMonikerFile::Open(IMoniker* pMoniker, IBindHost* pBindHost, CFileException* pError) { if (!pBindHost) return CAsyncMonikerFile::Open(pMoniker, pError); Close(); IPTR(IBindCtx) pBindCtx(CreateBindContext(pError), FALSE); if (pError && (pError->m_cause != CFileException::none)) return FALSE; IPTR(IUnknown) pBSCUnk(CreateBindStatusCallback(NULL), FALSE); IPTR(IBindStatusCallback) pBSC; pBSC.QueryInterface(pBSCUnk); m_bStopBindingReceived = FALSE; return Attach(pMoniker, pBindHost, pBSC, pBindCtx, pError); } BOOL CAsyncMonikerFile::Open(LPCTSTR lpszURL, IBindHost* pBindHost, CFileException* pError) { if (!pBindHost) return CAsyncMonikerFile::Open(lpszURL, pError); Close(); IPTR(IBindCtx) pBindCtx(CreateBindContext(pError), FALSE); if (pError && (pError->m_cause != CFileException::none)) return FALSE; IPTR(IUnknown) pBSCUnk(CreateBindStatusCallback(NULL), FALSE); IPTR(IBindStatusCallback) pBSC; pBSC.QueryInterface(pBSCUnk); m_bStopBindingReceived = FALSE; return Attach(lpszURL, pBindHost, pBSC, pBindCtx, pError); } BOOL CAsyncMonikerFile::Open(LPCTSTR lpszURL, CFileException* pError) { IPTR(IBindHost) pBindHost(CreateBindHost(), FALSE); return Open(lpszURL, static_cast(pBindHost), pError); } BOOL CAsyncMonikerFile::Open(IMoniker* pMoniker, CFileException* pError) { IPTR(IBindHost) pBindHost(CreateBindHost(), FALSE); return Open(pMoniker, (IBindHost*)pBindHost, pError); } BOOL CAsyncMonikerFile::Open(LPCTSTR lpszURL, IServiceProvider* pServiceProvider, CFileException* pError) { if (!pServiceProvider) return CAsyncMonikerFile::Open(lpszURL, pError); IPTR(IBindHost) pBindHost; pBindHost = _AfxTrySPForBindHost(pServiceProvider); if (!pBindHost.GetInterfacePtr()) pBindHost = _AfxTryQIForBindHost(pServiceProvider); if (pBindHost.GetInterfacePtr()) return Open(lpszURL, (IBindHost*)pBindHost, pError); return CAsyncMonikerFile::Open(lpszURL, pError); } BOOL CAsyncMonikerFile::Open(LPCTSTR lpszURL, IUnknown* pUnknown, CFileException* pError) { if (!pUnknown) return CAsyncMonikerFile::Open(lpszURL, pError); IPTR(IBindHost) pBindHost; IPTR(IServiceProvider) pServiceProvider; HRESULT hr=pServiceProvider.QueryInterface(pUnknown); if (SUCCEEDED(hr) && pServiceProvider.GetInterfacePtr()) pBindHost = _AfxTrySPForBindHost(pServiceProvider); if (!pBindHost.GetInterfacePtr()) pBindHost = _AfxTryQIForBindHost(pUnknown); if (pBindHost.GetInterfacePtr()) return Open(lpszURL, (IBindHost*)pBindHost, pError); return CAsyncMonikerFile::Open(lpszURL, pError); } BOOL CAsyncMonikerFile::Open(IMoniker* pMoniker, IServiceProvider* pServiceProvider, CFileException* pError) { if (!pServiceProvider) return Open(pMoniker, pError); IPTR(IBindHost) pBindHost; pBindHost = _AfxTrySPForBindHost(pServiceProvider); if (!pBindHost.GetInterfacePtr()) pBindHost = _AfxTryQIForBindHost(pServiceProvider); if (pBindHost.GetInterfacePtr()) return Open(pMoniker, (IBindHost*)pBindHost, pError); return Open(pMoniker, pError); } BOOL CAsyncMonikerFile::Open(IMoniker* pMoniker, IUnknown* pUnknown, CFileException* pError) { if (!pUnknown) return Open(pMoniker, pError); IPTR(IBindHost) pBindHost; IPTR(IServiceProvider) pServiceProvider; HRESULT hr=pServiceProvider.QueryInterface(pUnknown); if (SUCCEEDED(hr) && pServiceProvider.GetInterfacePtr()) pBindHost = _AfxTrySPForBindHost(pServiceProvider); if (!pBindHost.GetInterfacePtr()) pBindHost = _AfxTryQIForBindHost(pServiceProvider); if (pBindHost.GetInterfacePtr()) return Open(pMoniker, (IBindHost*)pBindHost, pError); return Open(pMoniker, pError); } BOOL CAsyncMonikerFile::PostBindToStream(CFileException* pError) { if (S_OK == IsAsyncMoniker(GetMoniker())) return TRUE; return CMonikerFile::PostBindToStream(pError); } IUnknown* CAsyncMonikerFile::CreateBindStatusCallback(IUnknown* pUnkControlling) { ASSERT(NULL == m_pAfxBSCCurrent); // Set by Close() m_pAfxBSCCurrent = new _AfxBindStatusCallback(this, pUnkControlling); IUnknown* pUnkInner = m_pAfxBSCCurrent->GetInnerUnknown(); ASSERT(pUnkInner != NULL); //Reference inner unknown for m_pAfxBSCCurrent pUnkInner->AddRef(); //Reference inner unknown for return value. pUnkInner->AddRef(); return pUnkInner; } DWORD CAsyncMonikerFile::GetBindInfo() const { return BINDF_ASYNCHRONOUS|BINDF_ASYNCSTORAGE; } LONG CAsyncMonikerFile::GetPriority() const { return THREAD_PRIORITY_NORMAL; } void CAsyncMonikerFile::OnDataAvailable(DWORD dwSize, DWORD bscfFlag) { UNUSED_ALWAYS(dwSize); UNUSED_ALWAYS(bscfFlag); } void CAsyncMonikerFile::OnLowResource() { } void CAsyncMonikerFile::OnStartBinding() { } void CAsyncMonikerFile::OnStopBinding(HRESULT hresult, LPCTSTR szError) { UNUSED_ALWAYS(hresult); UNUSED_ALWAYS(szError); } void CAsyncMonikerFile::OnProgress(ULONG ulProgress, ULONG ulProgressMax, ULONG ulStatusCode, LPCTSTR szStatusText) { UNUSED_ALWAYS(ulProgress); UNUSED_ALWAYS(ulProgressMax); UNUSED_ALWAYS(ulStatusCode); UNUSED_ALWAYS(szStatusText); } ///////////////////////////////////////////////////////////////////////////// // CAsyncMonikerFile diagnostics #ifdef _DEBUG void CAsyncMonikerFile::AssertValid() const { if (m_pAfxBSCCurrent) { ASSERT(m_pAfxBSCCurrent->GetOwner() == this); ASSERT(m_pAfxBSCCurrent->GetRefcount() > 0); #ifdef _AFXDLL ASSERT(m_pAfxBSCCurrent->GetModuleState() == AfxGetModuleState()); #endif ASSERT(m_pAfxBSCCurrent->GetpThisOfInnerUnknown() == m_pAfxBSCCurrent); } CMonikerFile::AssertValid(); } void CAsyncMonikerFile::Dump(CDumpContext& dc) const { CMonikerFile::Dump(dc); dc << "\nm_Binding = " << m_Binding.GetInterfacePtr(); dc << "\nm_pFormatEtc = " << m_pFormatEtc; dc << "\nm_pAfxBSCCurrent = " << m_pAfxBSCCurrent; if (m_pAfxBSCCurrent) { dc << "\nm_pAfxBSCCurrent->GetOwner() = " << m_pAfxBSCCurrent->GetOwner(); dc << "\nm_pAfxBSCCurrent->GetRefcount() = " << m_pAfxBSCCurrent->GetRefcount(); dc << "\nm_pAfxBSCCurrent->GetControllingUnknown() = " << m_pAfxBSCCurrent->GetControllingUnknown(); dc << "\nm_pAfxBSCCurrent->GetInnerUnknown() = " << m_pAfxBSCCurrent->GetInnerUnknown(); dc << "\nm_pAfxBSCCurrent->GetpThisOfInnerUnknown() = " << m_pAfxBSCCurrent->GetpThisOfInnerUnknown(); #ifdef _AFXDLL dc << "\nm_pAfxBSCCurrent->GetModuleState() = " << m_pAfxBSCCurrent->GetModuleState(); #endif } dc << "\n"; } #endif //////////////////////////////////////////////////////////////////////////// #ifdef AFX_INIT_SEG #pragma code_seg(AFX_INIT_SEG) #endif IMPLEMENT_DYNAMIC(CAsyncMonikerFile, CMonikerFile) ////////////////////////////////////////////////////////////////////////////