// 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) ///////////////////////////////////////////////////////////////////////////// // _AfxBindHost for CMonikerFile implementation class _AfxBindHost: public IBindHost { private: long m_dwRef; public: inline _AfxBindHost() : m_dwRef(0) {} inline ~_AfxBindHost() { ASSERT(m_dwRef == 0); } STDMETHOD_(ULONG, AddRef)() { return InterlockedIncrement(&m_dwRef); } STDMETHOD_(ULONG, Release)() { unsigned long lResult = InterlockedDecrement(&m_dwRef); if (lResult == 0) delete this; 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 || iid == IID_IBindHost) { *ppvObject = (IBindHost*)this; InterlockedIncrement(&m_dwRef); return S_OK; } // otherwise, incorrect IID, and thus error return E_NOINTERFACE; } STDMETHOD(CreateMoniker)( /* [in] */ LPOLESTR szName, /* [in] */ IBindCtx __RPC_FAR *pBC, /* [out] */ IMoniker __RPC_FAR *__RPC_FAR *ppmk, /* [in] */ DWORD dwReserved) { UNUSED_ALWAYS(dwReserved); UNUSED_ALWAYS(pBC); if (!szName || !ppmk) return E_POINTER; if (!*szName) return E_INVALIDARG; *ppmk = NULL; HRESULT hr = S_OK; hr = CreateURLMoniker(NULL, szName, ppmk); if (SUCCEEDED(hr) && !*ppmk) hr = E_FAIL; return hr; } STDMETHOD(MonikerBindToStorage)( /* [in] */ IMoniker __RPC_FAR *pMk, /* [in] */ IBindCtx __RPC_FAR *pBC, /* [in] */ IBindStatusCallback __RPC_FAR *pBSC, /* [in] */ REFIID riid, /* [out] */ void __RPC_FAR *__RPC_FAR *ppvObj) { if (!pMk || !ppvObj) return E_POINTER; *ppvObj = NULL; HRESULT hr = S_OK; IPTR(IBindCtx) BindCtx; if (pBC) { BindCtx = pBC; if (pBSC) { #ifdef _DEBUG IPTR(IBindStatusCallback) pBSCPrev; #endif hr = RegisterBindStatusCallback(BindCtx, pBSC, #ifdef _DEBUG &pBSCPrev, #else NULL, #endif 0); ASSERT(!pBSCPrev); if (FAILED(hr)) return hr; } } else { if (pBSC) hr = CreateAsyncBindCtx(0, pBSC, NULL, &BindCtx); else hr = CreateBindCtx(0, &BindCtx); if (SUCCEEDED(hr) && !BindCtx) hr = E_FAIL; if (FAILED(hr)) return hr; } return pMk->BindToStorage(BindCtx, NULL, riid, ppvObj); } private: STDMETHOD(MonikerBindToObject)( /* [in] */ IMoniker __RPC_FAR *pMk, /* [in] */ IBindCtx __RPC_FAR *pBC, /* [in] */ IBindStatusCallback __RPC_FAR *pBSC, /* [in] */ REFIID riid, /* [out] */ void __RPC_FAR *__RPC_FAR *ppvObj) { ASSERT(FALSE); UNUSED_ALWAYS(pMk); UNUSED_ALWAYS(pBC); UNUSED_ALWAYS(pBSC); UNUSED_ALWAYS(riid); UNUSED_ALWAYS(ppvObj); return E_NOTIMPL; } }; ///////////////////////////////////////////////////////////////////////////// // CMonikerFile implementation CMonikerFile::~CMonikerFile() { ASSERT_VALID(this); Close(); } void CMonikerFile::Flush() { ASSERT_VALID(this); ASSERT(GetStream() != NULL); GetStream()->Commit(0); } BOOL CMonikerFile::Open(LPCTSTR lpszUrl, IBindHost* pBindHost, IBindStatusCallback* pBSC, IBindCtx* pBindCtx, CFileException* pError) { ASSERT_VALID(this); Close(); // These objects are reopenable return Attach(lpszUrl, pBindHost, pBSC, pBindCtx, pError); } BOOL CMonikerFile::Attach(LPCTSTR lpszUrl, IBindHost* pBindHost, IBindStatusCallback* pBSC, IBindCtx* pBindCtx, CFileException* pError) { ASSERT(!m_Moniker); ASSERT(!GetStream()); USES_CONVERSION; ASSERT(NULL == lpszUrl || AfxIsValidString(lpszUrl)); ASSERT(NULL == pError || AfxIsValidAddress(pError, sizeof(CFileException))); ASSERT(NULL != pBindHost); // Check for empty path if (!lpszUrl || !*lpszUrl) { if (pError) { pError->m_cause=CFileException::badPath; pError->m_strFileName=lpszUrl; } return FALSE; } // Create the moniker HRESULT hr; IPTR(IMoniker) pMoniker; hr = pBindHost->CreateMoniker(T2OLE((LPTSTR) lpszUrl), pBindCtx, reinterpret_cast(&pMoniker), 0); if (FAILED(hr)) { if (pError) _AfxFillOleFileException(pError, hr); return FALSE; } return Attach(pMoniker, pBindHost, pBSC, pBindCtx, pError); } BOOL CMonikerFile::Open(LPCTSTR lpszUrl, CFileException* pError) { IPTR(IBindHost) pBindHost(CreateBindHost(), FALSE); IPTR(IBindCtx) pBindCtx(CreateBindContext(pError), FALSE); return Open(lpszUrl, pBindHost, NULL, pBindCtx, pError); } BOOL CMonikerFile::Open(IMoniker* pMoniker, CFileException* pError) { Close(); // These objects are reopenable IPTR(IBindHost) pBindHost(CreateBindHost(), FALSE); IPTR(IBindCtx) pBindCtx(CreateBindContext(pError), FALSE); return Attach(pMoniker, pBindHost, NULL, pBindCtx, pError); } BOOL CMonikerFile::Open(IMoniker* pMoniker, IBindHost* pBindHost, IBindStatusCallback* pBSC, IBindCtx* pBindCtx, CFileException* pError) { Close(); return Attach(pMoniker, pBindHost, pBSC, pBindCtx, pError); } BOOL CMonikerFile::Attach(IMoniker* pMoniker, IBindHost* pBindHost, IBindStatusCallback* pBSC, IBindCtx* pBindCtx, CFileException* pError) { ASSERT_VALID(this); ASSERT(pMoniker); ASSERT(!m_Moniker); ASSERT(!GetStream()); m_Moniker=pMoniker; IPTR(IStream) pStream; HRESULT hr=pBindHost->MonikerBindToStorage(pMoniker, pBindCtx, pBSC, IID_IStream, reinterpret_cast(&pStream)); if (FAILED(hr)) { if (pError) _AfxFillOleFileException(pError, hr); return FALSE; } // If this is really a CAsyncMonikerFile, then we may have attached to the stream // within MonikerBindToStorage, in which case we want to avoid doing so here. if (pStream.GetInterfacePtr() && !GetStream()) { // Attach this to the stream, transferring the reference // COleStreamFile::Attach doesn't increment pStream's refcount COleStreamFile::Attach(pStream); pStream.Detach(); } return PostBindToStream(pError); } void CMonikerFile::Close() { if (m_Moniker.GetInterfacePtr()) m_Moniker.Release(); COleStreamFile::Close(); } BOOL CMonikerFile::Detach(CFileException* pError) { ASSERT_VALID(this); ASSERT(!!m_Moniker); TRY { Close(); } CATCH (CFileException, e) { if (pError) { pError->m_cause=e->m_cause; pError->m_lOsError=e->m_lOsError; pError->m_strFileName=e->m_strFileName; } DELETE_EXCEPTION(e); return FALSE; } END_CATCH; return TRUE; } IBindHost* CMonikerFile::CreateBindHost() { IBindHost* pBindHost = new _AfxBindHost(); pBindHost->AddRef(); return pBindHost; } IBindCtx* CMonikerFile::CreateBindContext(CFileException* pError) { UNUSED_ALWAYS(pError); return NULL; } // So that CMonikerFile can check for a null pStream and CAsyncMonikerFile can ignore it BOOL CMonikerFile::PostBindToStream(CFileException* pError) { if (!GetStream()) { if (pError) _AfxFillOleFileException(pError, E_UNEXPECTED); TRY { Close(); } CATCH_ALL(e) { DELETE_EXCEPTION(e); } END_CATCH_ALL return FALSE; } return TRUE; } ///////////////////////////////////////////////////////////////////////////// // CMonikerFile diagnostics #ifdef _DEBUG void CMonikerFile::AssertValid() const { COleStreamFile::AssertValid(); } void CMonikerFile::Dump(CDumpContext& dc) const { COleStreamFile::Dump(dc); dc << "\nm_Moniker = " << m_Moniker.GetInterfacePtr(); dc << "\n"; } #endif //////////////////////////////////////////////////////////////////////////// #ifndef _AFX_ENABLE_INLINES // expand inlines for OLE general APIs static char _szAfxOleInl[] = "afxole.inl"; #undef THIS_FILE #define THIS_FILE _szAfxOleInl #define _AFXOLEMONIKER_INLINE #include "afxole.inl" #endif //!_AFX_ENABLE_INLINES #ifdef AFX_INIT_SEG #pragma code_seg(AFX_INIT_SEG) #endif IMPLEMENT_DYNAMIC(CMonikerFile, COleStreamFile) ////////////////////////////////////////////////////////////////////////////