///////////////////////////////////////////////////////////////////// // MyMoniker.cpp - Marvelous Moniker Demo // // // // Jim Fawcett, CSE775 - Distributed Objects, Spring 2006 // // based on an example by // // Inside Distributed COM, Eddon and Eddon, Microsoft Press, 1998 // ///////////////////////////////////////////////////////////////////// // MyMoniker.cpp #define _WIN32_DCOM #include #include #include #include "registry.h" using namespace std; const CLSID CLSID_MarvelousMoniker = {0x10000022,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}}; long g_cComponents = 0; long g_cServerLocks = 0; class CMarvyMoniker : public IMoniker, public IClassActivator { friend class CClassObject; public: // IUnknown ULONG __stdcall AddRef(); ULONG __stdcall Release(); HRESULT __stdcall QueryInterface(REFIID riid, void** ppv); // IPersist HRESULT __stdcall GetClassID(CLSID* pClassID); // IPersistStream HRESULT __stdcall IsDirty(); HRESULT __stdcall Load(IStream* pStm); HRESULT __stdcall Save(IStream* pStm, BOOL fClearDirty); HRESULT __stdcall GetSizeMax(ULARGE_INTEGER *pcbSize); // IMoniker HRESULT __stdcall BindToObject(IBindCtx *pbc, IMoniker *pmkToLeft, REFIID riidResult, void **ppvResult); HRESULT __stdcall BindToStorage(IBindCtx *pbc, IMoniker *pmkToLeft, REFIID riid, void **ppvObj); HRESULT __stdcall Reduce(IBindCtx *pbc, DWORD dwReduceHowFar, IMoniker **ppmkToLeft, IMoniker **ppmkReduced); HRESULT __stdcall ComposeWith(IMoniker *pmkRight, BOOL fOnlyIfNotGeneric, IMoniker **ppmkComposite); HRESULT __stdcall Enum(BOOL fForward, IEnumMoniker **ppenumMoniker); HRESULT __stdcall IsEqual(IMoniker *pmkOtherMoniker); HRESULT __stdcall Hash(DWORD *pdwHash); HRESULT __stdcall IsRunning(IBindCtx *pbc, IMoniker *pmkToLeft, IMoniker *pmkNewlyRunning); HRESULT __stdcall GetTimeOfLastChange(IBindCtx *pbc, IMoniker *pmkToLeft, FILETIME *pFileTime); HRESULT __stdcall Inverse(IMoniker **ppmk); HRESULT __stdcall CommonPrefixWith(IMoniker *pmkOther, IMoniker **ppmkPrefix); HRESULT __stdcall RelativePathTo(IMoniker *pmkOther, IMoniker **ppmkRelPath); HRESULT __stdcall GetDisplayName(IBindCtx *pbc, IMoniker *pmkToLeft, LPOLESTR *ppszDisplayName); HRESULT __stdcall ParseDisplayName(IBindCtx *pbc, IMoniker *pmkToLeft, LPOLESTR pszDisplayName, ULONG *pchEaten, IMoniker **ppmkOut); HRESULT __stdcall IsSystemMoniker(DWORD *pdwMksys); // IClassActivator HRESULT __stdcall GetClassObject(REFCLSID pClassID, DWORD dwClsContext, LCID locale, REFIID riid, void** ppv); CMarvyMoniker(); CMarvyMoniker(REFCLSID clsid, COSERVERINFO* pCSI); ~CMarvyMoniker(); private: ULONG m_cRef; wchar_t m_hostname[255]; CLSID m_clsid; COSERVERINFO m_CoServerInfo; }; CMarvyMoniker::CMarvyMoniker(REFCLSID clsid, COSERVERINFO* pCSI) { CMarvyMoniker(); m_clsid = clsid; m_CoServerInfo.pwszName = wcscpy(m_hostname, pCSI->pwszName); } CMarvyMoniker::CMarvyMoniker() : m_cRef(1) { g_cComponents++; m_CoServerInfo.dwReserved1 = 0; m_CoServerInfo.pwszName = 0; m_CoServerInfo.pAuthInfo = 0; m_CoServerInfo.dwReserved2 = 0; } CMarvyMoniker::~CMarvyMoniker() { g_cComponents--; } HRESULT CMarvyMoniker::GetClassObject(REFCLSID pClassID, DWORD dwClsContext, LCID locale, REFIID riid, void** ppv) { wprintf(L"IClassActivator::GetClassObject connecting to %s\n", m_CoServerInfo.pwszName); HRESULT hr = CoGetClassObject(pClassID, CLSCTX_SERVER, &m_CoServerInfo, riid, ppv); if(FAILED(hr)) printf("CoCreateInstance failed %0x\n", hr); return hr; } HRESULT CMarvyMoniker::GetClassID(CLSID* pClassID) { *pClassID = CLSID_MarvelousMoniker; return S_OK; } HRESULT CMarvyMoniker::IsDirty() { return S_FALSE; } HRESULT CMarvyMoniker::Load(IStream* pStm) { return E_NOTIMPL; } HRESULT CMarvyMoniker::Save(IStream* pStm, BOOL fClearDirty) { return E_NOTIMPL; } HRESULT CMarvyMoniker::GetSizeMax(ULARGE_INTEGER *pcbSize) { return E_NOTIMPL; } HRESULT CMarvyMoniker::BindToObject(IBindCtx *pbc, IMoniker *pmkToLeft, REFIID riidResult, void **ppvResult) { // This catches the recursive call by the class moniker if(riidResult == IID_IClassActivator) { *ppvResult = (IClassActivator*)this; return S_OK; } // An AddRef a day keeps the doctor away AddRef(); IMoniker* pClassMoniker; HRESULT hr = CreateClassMoniker(m_clsid, &pClassMoniker); if(FAILED(hr)) return hr; // Bind the class moniker hr = pClassMoniker->BindToObject(pbc, (IMoniker*)this, riidResult, ppvResult); pClassMoniker->Release(); return hr; } HRESULT CMarvyMoniker::BindToStorage(IBindCtx *pbc, IMoniker *pmkToLeft, REFIID riid, void **ppvObj) { return MK_E_NOSTORAGE; } HRESULT CMarvyMoniker::Reduce(IBindCtx *pbc, DWORD dwReduceHowFar, IMoniker **ppmkToLeft, IMoniker **ppmkReduced) { *ppmkReduced = (IMoniker*)this; return MK_S_REDUCED_TO_SELF; } HRESULT CMarvyMoniker::ComposeWith(IMoniker *pmkRight, BOOL fOnlyIfNotGeneric, IMoniker **ppmkComposite) { if(fOnlyIfNotGeneric) { *ppmkComposite = NULL; return MK_E_NEEDGENERIC; } return CreateGenericComposite((IMoniker*)this, pmkRight, ppmkComposite); } HRESULT CMarvyMoniker::Enum(BOOL fForward, IEnumMoniker **ppenumMoniker) { *ppenumMoniker = NULL; return S_OK; } HRESULT CMarvyMoniker::IsEqual(IMoniker *pmkOtherMoniker) { return E_NOTIMPL; } HRESULT CMarvyMoniker::Hash(DWORD *pdwHash) { return E_NOTIMPL; } HRESULT CMarvyMoniker::IsRunning(IBindCtx *pbc, IMoniker *pmkToLeft, IMoniker *pmkNewlyRunning) { return E_NOTIMPL; } HRESULT CMarvyMoniker::GetTimeOfLastChange(IBindCtx *pbc, IMoniker *pmkToLeft, FILETIME *pFileTime) { return MK_E_UNAVAILABLE; } HRESULT CMarvyMoniker::Inverse(IMoniker **ppmk) { return CreateAntiMoniker(ppmk); } HRESULT CMarvyMoniker::CommonPrefixWith(IMoniker *pmkOther, IMoniker **ppmkPrefix) { return E_NOTIMPL; } HRESULT CMarvyMoniker::RelativePathTo(IMoniker *pmkOther, IMoniker **ppmkRelPath) { return MonikerRelativePathTo((IMoniker*)this, pmkOther, ppmkRelPath, TRUE); } HRESULT CMarvyMoniker::GetDisplayName(IBindCtx *pbc, IMoniker *pmkToLeft, LPOLESTR *ppszDisplayName) { *ppszDisplayName = (wchar_t*)CoTaskMemAlloc(512); wchar_t ppsz[39]; StringFromGUID2(m_clsid, ppsz, 39); ppsz[37] = 0; swprintf(*ppszDisplayName, L"host:%s!clsid:%s", m_hostname, wcstok(ppsz, L"{")); return S_OK; } HRESULT CMarvyMoniker::ParseDisplayName(IBindCtx *pbc, IMoniker *pmkToLeft, LPOLESTR pszDisplayName, ULONG *pchEaten, IMoniker **ppmkOut) { return E_NOTIMPL; } HRESULT CMarvyMoniker::IsSystemMoniker(DWORD *pdwMksys) { *pdwMksys = MKSYS_NONE; return S_OK; } ULONG CMarvyMoniker::AddRef() { cout << "Moniker::AddRef() m_cRef = " << m_cRef + 1 << endl; return ++m_cRef; } ULONG CMarvyMoniker::Release() { cout << "Moniker::Release() m_cRef = " << m_cRef - 1 << endl; if(--m_cRef != 0) return m_cRef; delete this; return 0; } HRESULT CMarvyMoniker::QueryInterface(REFIID riid, void** ppv) { if(riid == IID_IUnknown) { cout << "Moniker::QueryInterface() for IUnknown" << endl; *ppv = reinterpret_cast(this); } else if(riid == IID_IMoniker) { cout << "Moniker::QueryInterface() for IMoniker" << endl; *ppv = (IMoniker*)this; } else { *ppv = NULL; return E_NOINTERFACE; } AddRef(); return S_OK; } class CClassObject : public IParseDisplayName { public: // IUnknown ULONG __stdcall AddRef(); ULONG __stdcall Release(); HRESULT __stdcall QueryInterface(REFIID riid, void** ppv); // IParseDisplayName HRESULT __stdcall ParseDisplayName(IBindCtx *pbc, LPOLESTR pszDisplayName, ULONG *pchEaten, IMoniker **ppmkOut); CClassObject() : m_cRef(1) { } ~CClassObject() { } private: ULONG m_cRef; }; ULONG CClassObject::AddRef() { return ++m_cRef; } ULONG CClassObject::Release() { if(--m_cRef != 0) return m_cRef; delete this; return 0; } HRESULT CClassObject::QueryInterface(REFIID riid, void** ppv) { if(riid == IID_IUnknown) *ppv = (IUnknown*)this; else if(riid == IID_IParseDisplayName) { cout << "CClassObject::QueryInterface() for IParseDisplayName" << endl; *ppv = (IParseDisplayName*)this; } else { *ppv = NULL; return E_NOINTERFACE; } AddRef(); return S_OK; } HRESULT CClassObject::ParseDisplayName(IBindCtx *pbc, LPOLESTR pszDisplayName, ULONG *pchEaten, IMoniker **ppmkOut) { // Instantiate the moniker CMarvyMoniker* pCMarvyMoniker = new CMarvyMoniker(); // Parse and check display name // It must have the following format: // host:hostname!clsid:????????-????-????-????-???????????? if(_wcsicmp(wcstok(pszDisplayName, L":"), L"host") == 0) { pCMarvyMoniker->m_CoServerInfo.pwszName = wcscpy(pCMarvyMoniker->m_hostname, wcstok(NULL, L"!")); if(_wcsicmp(wcstok(NULL, L":"), L"clsid") == 0) { wchar_t clsid_with_braces[39] = L"{"; wcscat(wcscat(clsid_with_braces, wcstok(NULL, L"!")), L"}"); CLSIDFromString(clsid_with_braces, &pCMarvyMoniker->m_clsid); } } // Get IMoniker* to return to caller pCMarvyMoniker->QueryInterface(IID_IMoniker, (void**)ppmkOut); pCMarvyMoniker->Release(); // Indicate that we have digested the entire display name. *pchEaten = (ULONG)wcslen(pszDisplayName); return S_OK; } HRESULT __stdcall DllCanUnloadNow() { cout << "Moniker: DllCanUnloadNow() " << (g_cServerLocks == 0 && g_cComponents == 0 ? "Yes" : "No") << endl; if(g_cServerLocks == 0 && g_cComponents == 0) return S_OK; else return S_FALSE; } HRESULT __stdcall DllGetClassObject(REFCLSID clsid, REFIID riid, void** ppv) { cout << "Moniker: DllGetClassObject" << endl; if(clsid != CLSID_MarvelousMoniker) return CLASS_E_CLASSNOTAVAILABLE; CClassObject* pClassObject = new CClassObject; if(pClassObject == NULL) return E_OUTOFMEMORY; // QueryInterface probably for IClassFactory HRESULT hr = pClassObject->QueryInterface(riid, ppv); pClassObject->Release(); return hr; } HRESULT __stdcall DllRegisterServer() { // The progid "Host" must be registered in order for the moniker to work return RegisterServer("moniker.dll", CLSID_MarvelousMoniker, "Marvelous Moniker", "Host", "Host", NULL); } HRESULT __stdcall DllUnregisterServer() { return UnregisterServer(CLSID_MarvelousMoniker, "Host", "Host"); } HRESULT __stdcall CreateMarvelousMoniker(REFCLSID clsid, COSERVERINFO* pCSI, IMoniker** ppMoniker) { CMarvyMoniker *pCMarvyMoniker = new CMarvyMoniker(clsid, pCSI); if(pCMarvyMoniker == NULL) return E_OUTOFMEMORY; HRESULT hr = pCMarvyMoniker->QueryInterface(IID_IMoniker, (void**)ppMoniker); pCMarvyMoniker->Release(); return hr; }