/*++ Copyright (c) 1997 Microsoft Corporation Module Name: gmoniker.cpp Abstract: This module contains the implementation of the CSEOGenericMoniker object. Author: Andy Jacobs (andyj@microsoft.com) Revision History: andyj 04/11/97 created --*/ // GMONIKER.cpp : Implementation of CSEOGenericMoniker #include "stdafx.h" #include "seodefs.h" #include "GMONIKER.h" #ifndef CSTR_EQUAL #define CSTR_EQUAL (2) #endif LPCOLESTR szObjectType = OLESTR("MonikerType"); const WCHAR QUOTE_CHAR = L'\\'; const WCHAR NAME_SEP = L'='; const WCHAR ENTRY_SEP = L' '; const WCHAR PROGID_PREFIX = L'@'; const WCHAR PROGID_POSTFIX = L':'; IsPrefix(LPCOLESTR psPrefix, LPCOLESTR psString, int iLen) { return (CSTR_EQUAL == CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, psPrefix, iLen, psString, iLen)); } ///////////////////////////////////////////////////////////////////////////// // CSEOGenericMoniker // IPersist Members HRESULT STDMETHODCALLTYPE CSEOGenericMoniker::GetClassID(/* [out] */ CLSID __RPC_FAR *pClassID) { if(!pClassID) return E_POINTER; memcpy(pClassID, &CLSID_CSEOGenericMoniker, sizeof(CLSID)); _ASSERT(IsEqualCLSID(*pClassID, CLSID_CSEOGenericMoniker)); return S_OK; } // IPersistStream Members HRESULT STDMETHODCALLTYPE CSEOGenericMoniker::IsDirty(void) { return S_FALSE; // Shallow binding representation hasn't changed } HRESULT STDMETHODCALLTYPE CSEOGenericMoniker::Load( /* [unique][in] */ IStream __RPC_FAR *pStm) { return m_bstrMoniker.ReadFromStream(pStm); } HRESULT STDMETHODCALLTYPE CSEOGenericMoniker::Save( /* [unique][in] */ IStream __RPC_FAR *pStm, /* [in] */ BOOL fClearDirty) { return m_bstrMoniker.WriteToStream(pStm); } HRESULT STDMETHODCALLTYPE CSEOGenericMoniker::GetSizeMax( /* [out] */ ULARGE_INTEGER __RPC_FAR *pcbSize) { if(!pcbSize) return E_POINTER; // Conservitive size estimate of bytes needed to save object pcbSize->QuadPart = m_bstrMoniker.Length() * sizeof(WCHAR) * 2; return S_OK; } // IMoniker Members /* [local] */ HRESULT STDMETHODCALLTYPE CSEOGenericMoniker::BindToObject( /* [unique][in] */ IBindCtx __RPC_FAR *pbc, /* [unique][in] */ IMoniker __RPC_FAR *pmkToLeft, /* [in] */ REFIID riidResult, /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvResult) { if(!pbc || !ppvResult) return E_POINTER; *ppvResult = NULL; // First, get the Running Object Table BOOL bFoundInTable = TRUE; CComPtr pROT; CComPtr punkObject; HRESULT hRes = pbc->GetRunningObjectTable(&pROT); if(FAILED(hRes)) return hRes; _ASSERT(!!pROT); // operator!() is defined, so use !! to test for existance. if(!pROT) return E_UNEXPECTED; // GetRunningObjectTable() didn't work // Try to find in Running Object Table hRes = pROT->GetObject((IMoniker *) this, &punkObject); // If not currently running then create it if(FAILED(hRes) || !punkObject) { bFoundInTable = FALSE; CComPtr pBag; hRes = CoCreateInstance(CLSID_CSEOMemDictionary, NULL, CLSCTX_ALL, IID_IPropertyBag, (LPVOID *) &pBag); if(FAILED(hRes)) return hRes; _ASSERT(!!pBag); // operator!() is defined, so use !! to test for existance. SetPropertyBag(pBag); CComPtr pInitObject; hRes = CreateBoundObject(pBag, &pInitObject); if(FAILED(hRes)) return hRes; _ASSERT(!!pInitObject); // operator!() is defined, so use !! to test for existance. if(!pInitObject) return E_UNEXPECTED; // CreateBoundObject returned S_OK, but didn't Create an object hRes = pInitObject->Load(pBag, NULL); punkObject = pInitObject; // Save copy of pointer /* TBD: Register with the Running Object Table DWORD dwRegister; if(SUCCEEDED(hRes)) pROT->Register(0, pInitObject, (IMoniker *) this, &dwRegister); */ } // punkObject should have been set by one of the code paths before this _ASSERT(!!punkObject); // operator!() is defined, so use !! to test for existance. if(!punkObject) return E_UNEXPECTED; return punkObject->QueryInterface(riidResult, ppvResult); } /* [local] */ HRESULT STDMETHODCALLTYPE CSEOGenericMoniker::BindToStorage( /* [unique][in] */ IBindCtx __RPC_FAR *pbc, /* [unique][in] */ IMoniker __RPC_FAR *pmkToLeft, /* [in] */ REFIID riid, /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObj) { return MK_E_NOSTORAGE; // The object identified by this moniker does not have its own storage. } HRESULT STDMETHODCALLTYPE CSEOGenericMoniker::Reduce( /* [unique][in] */ IBindCtx __RPC_FAR *pbc, /* [in] */ DWORD dwReduceHowFar, /* [unique][out][in] */ IMoniker __RPC_FAR *__RPC_FAR *ppmkToLeft, /* [out] */ IMoniker __RPC_FAR *__RPC_FAR *ppmkReduced) { if(!ppmkReduced) return E_POINTER; *ppmkReduced = (IMoniker *) this; _ASSERT(!!*ppmkReduced); // operator!() is defined, so use !! to test for existance. if(!*ppmkReduced) return E_UNEXPECTED; // "this" not set... HRESULT hRes = (*ppmkReduced)->AddRef(); // Do this for self (the object being returned) if(SUCCEEDED(hRes)) hRes = MK_S_REDUCED_TO_SELF; // This moniker could not be reduced any further, so ppmkReduced indicates this moniker. return hRes; } HRESULT STDMETHODCALLTYPE CSEOGenericMoniker::ComposeWith( /* [unique][in] */ IMoniker __RPC_FAR *pmkRight, /* [in] */ BOOL fOnlyIfNotGeneric, /* [out] */ IMoniker __RPC_FAR *__RPC_FAR *ppmkComposite) { ATLTRACENOTIMPL(_T("CSEOGenericMoniker::ComposeWith")); } HRESULT STDMETHODCALLTYPE CSEOGenericMoniker::Enum( /* [in] */ BOOL fForward, /* [out] */ IEnumMoniker __RPC_FAR *__RPC_FAR *ppenumMoniker) { if(!ppenumMoniker) return E_POINTER; *ppenumMoniker = NULL; return S_OK; } HRESULT STDMETHODCALLTYPE CSEOGenericMoniker::IsEqual( /* [unique][in] */ IMoniker __RPC_FAR *pmkOtherMoniker) { ATLTRACENOTIMPL(_T("CSEOGenericMoniker::IsEqual")); // Return S_OK vs. S_FALSE } HRESULT STDMETHODCALLTYPE CSEOGenericMoniker::Hash( /* [out] */ DWORD __RPC_FAR *pdwHash) { if(!pdwHash) return E_POINTER; *pdwHash = 0; // ATLTRACENOTIMPL(_T("CSEOGenericMoniker::Hash")); return S_OK; } HRESULT STDMETHODCALLTYPE CSEOGenericMoniker::IsRunning( /* [unique][in] */ IBindCtx __RPC_FAR *pbc, /* [unique][in] */ IMoniker __RPC_FAR *pmkToLeft, /* [unique][in] */ IMoniker __RPC_FAR *pmkNewlyRunning) { HRESULT hRes = E_UNEXPECTED; // hRes not set to something else if(pmkToLeft) { // If something on the left, pass it to them hRes = pmkToLeft->IsRunning(pbc, NULL, pmkNewlyRunning); } else if(pbc) { // No Moniker to left, but have a BindCtx CComPtr pROT; hRes = pbc->GetRunningObjectTable(&pROT); if(FAILED(hRes)) return hRes; if(pROT) { // Try to find in Running Object Table hRes = pROT->IsRunning((IMoniker *) this); } } else { hRes = E_POINTER; // No BindCtx } return hRes; } HRESULT STDMETHODCALLTYPE CSEOGenericMoniker::GetTimeOfLastChange( /* [unique][in] */ IBindCtx __RPC_FAR *pbc, /* [unique][in] */ IMoniker __RPC_FAR *pmkToLeft, /* [out] */ FILETIME __RPC_FAR *pFileTime) { return MK_E_UNAVAILABLE; } HRESULT STDMETHODCALLTYPE CSEOGenericMoniker::Inverse( /* [out] */ IMoniker __RPC_FAR *__RPC_FAR *ppmk) { return MK_E_NOINVERSE; } HRESULT STDMETHODCALLTYPE CSEOGenericMoniker::CommonPrefixWith( /* [unique][in] */ IMoniker __RPC_FAR *pmkOther, /* [out] */ IMoniker __RPC_FAR *__RPC_FAR *ppmkPrefix) { return MK_E_NOPREFIX; } HRESULT STDMETHODCALLTYPE CSEOGenericMoniker::RelativePathTo( /* [unique][in] */ IMoniker __RPC_FAR *pmkOther, /* [out] */ IMoniker __RPC_FAR *__RPC_FAR *ppmkRelPath) { ATLTRACENOTIMPL(_T("CSEOGenericMoniker::RelativePathTo")); } HRESULT STDMETHODCALLTYPE CSEOGenericMoniker::GetDisplayName( /* [unique][in] */ IBindCtx __RPC_FAR *pbc, /* [unique][in] */ IMoniker __RPC_FAR *pmkToLeft, /* [out] */ LPOLESTR __RPC_FAR *ppszDisplayName) { if(!ppszDisplayName) return E_POINTER; *ppszDisplayName = NULL; CComPtr pMalloc; HRESULT hRes = CoGetMalloc(1, &pMalloc); if(SUCCEEDED(hRes)) { _ASSERT(!!pMalloc); // operator!() is defined, so use !! to test for existance. hRes = E_OUTOFMEMORY; int iSize = 5 + m_bstrMoniker.Length() + lstrlenW(GENERIC_MONIKER_VERPROGID); *ppszDisplayName = (LPOLESTR) pMalloc->Alloc(iSize * sizeof(WCHAR)); if(*ppszDisplayName) { **ppszDisplayName = 0; // Terminate string lstrcatW(*ppszDisplayName, L"@"); lstrcatW(*ppszDisplayName, GENERIC_MONIKER_VERPROGID); // Build the display name lstrcatW(*ppszDisplayName, L": "); lstrcatW(*ppszDisplayName, m_bstrMoniker); hRes = S_OK; } } return hRes; } HRESULT STDMETHODCALLTYPE CSEOGenericMoniker::ParseDisplayName( /* [unique][in] */ IBindCtx __RPC_FAR *pbc, /* [unique][in] */ IMoniker __RPC_FAR *pmkToLeft, /* [in] */ LPOLESTR pszDisplayName, /* [out] */ ULONG __RPC_FAR *pchEaten, /* [out] */ IMoniker __RPC_FAR *__RPC_FAR *ppmkOut) { // Deligate!!! return ParseDisplayName(pbc, pszDisplayName, pchEaten, ppmkOut); } HRESULT STDMETHODCALLTYPE CSEOGenericMoniker::IsSystemMoniker( /* [out] */ DWORD __RPC_FAR *pdwMksys) { if(!pdwMksys) return E_POINTER; *pdwMksys = MKSYS_NONE; return S_FALSE; // Not a system moniker } // IParseDisplayName Members HRESULT STDMETHODCALLTYPE CSEOGenericMoniker::ParseDisplayName( /* [unique][in] */ IBindCtx __RPC_FAR *pbc, /* [in] */ LPOLESTR pszDisplayName, /* [out] */ ULONG __RPC_FAR *pchEaten, /* [out] */ IMoniker __RPC_FAR *__RPC_FAR *ppmkOut) { if(!pszDisplayName || !pchEaten || !ppmkOut) return E_POINTER; *pchEaten = 0; // Nothing parsed so far CComBSTR bstrMoniker; CComBSTR bstrProgID(GENERIC_MONIKER_PROGID); CComBSTR bstrVerProgID(GENERIC_MONIKER_VERPROGID); // The Ver string should completely contain the non-Ver string _ASSERT(bstrProgID.Length() > 0); // Something should be there _ASSERT(bstrProgID.Length() <= bstrVerProgID.Length()); _ASSERT(IsPrefix(bstrProgID, bstrVerProgID, bstrProgID.Length())); if(PROGID_PREFIX == pszDisplayName[*pchEaten]) { ++(*pchEaten); } if(IsPrefix(bstrProgID, pszDisplayName + *pchEaten, bstrProgID.Length())) { if(IsPrefix(bstrVerProgID, pszDisplayName + *pchEaten, bstrVerProgID.Length())) { *pchEaten += bstrVerProgID.Length(); } else { // Non-version string matched *pchEaten += bstrProgID.Length(); } if(pszDisplayName[*pchEaten] && (PROGID_POSTFIX == pszDisplayName[*pchEaten])) { ++(*pchEaten); } while(pszDisplayName[*pchEaten] && (pszDisplayName[*pchEaten] == ENTRY_SEP)) { ++(*pchEaten); } if(pszDisplayName[*pchEaten]) { // If still something left bstrMoniker = &pszDisplayName[*pchEaten]; *pchEaten += bstrMoniker.Length(); } } CComObject *pMoniker; HRESULT hRes = CComObject::CreateInstance(&pMoniker); if(FAILED(hRes)) return hRes; _ASSERT(!!pMoniker); // operator!() is defined, so use !! to test for existance. if(!pMoniker) return E_UNEXPECTED; // CreateInstance failed (but returned S_OK) pMoniker->SetMonikerString(bstrMoniker); *ppmkOut = (IMoniker *) pMoniker; return pMoniker->AddRef(); } HRESULT CSEOGenericMoniker::FinalConstruct() { HRESULT hrRes; hrRes = CoCreateFreeThreadedMarshaler(GetControllingUnknown(),&m_pUnkMarshaler.p); _ASSERTE(!SUCCEEDED(hrRes)||m_pUnkMarshaler); return (SUCCEEDED(hrRes)?S_OK:hrRes); } void CSEOGenericMoniker::FinalRelease() { m_pUnkMarshaler.Release(); } void CSEOGenericMoniker::SetPropertyBag(IPropertyBag *pBag) { if(!pBag) return; int iStringLength = m_bstrMoniker.Length(); int iCurrentPos = 0; while(iCurrentPos < iStringLength) { CComBSTR bstrName; CComBSTR bstrValue; // Eat up multiple spaces for entry separators while((iCurrentPos < iStringLength) && (m_bstrMoniker.m_str[iCurrentPos] == ENTRY_SEP)) { ++iCurrentPos; } // Read in the Name while((iCurrentPos < iStringLength) && (m_bstrMoniker.m_str[iCurrentPos] != NAME_SEP)) { if((iCurrentPos < iStringLength - 1) && (m_bstrMoniker.m_str[iCurrentPos] == QUOTE_CHAR)) { ++iCurrentPos; } bstrName.Append(&m_bstrMoniker.m_str[iCurrentPos], 1); ++iCurrentPos; } BOOL bFoundSep = FALSE; if((iCurrentPos < iStringLength) && (m_bstrMoniker.m_str[iCurrentPos] == NAME_SEP)) { bFoundSep = TRUE; ++iCurrentPos; } // Read in the value while((iCurrentPos < iStringLength) && (m_bstrMoniker.m_str[iCurrentPos] != ENTRY_SEP)) { if((iCurrentPos < iStringLength - 1) && (m_bstrMoniker.m_str[iCurrentPos] == QUOTE_CHAR)) { ++iCurrentPos; } bstrValue.Append(&m_bstrMoniker.m_str[iCurrentPos], 1); ++iCurrentPos; } if(bFoundSep) { // If it's a real entry CComVariant varValue = bstrValue; // Convert BSTR to Variant pBag->Write(bstrName, &varValue); // Even if error occurs in Write(), continue processing } // Eat up multiple spaces for entry separators while((iCurrentPos < iStringLength) && (m_bstrMoniker.m_str[iCurrentPos] == ENTRY_SEP)) { ++iCurrentPos; } } } HRESULT CSEOGenericMoniker::CreateBoundObject(IPropertyBag *pBag, ISEOInitObject **ppResult) { _ASSERT(ppResult); *ppResult = NULL; if(!pBag) return E_POINTER; CComVariant varPROGID; CLSID clsid; varPROGID.vt = VT_BSTR; // Request type from Read() varPROGID.bstrVal = NULL; HRESULT hRes = pBag->Read(szObjectType, &varPROGID, NULL); if(SUCCEEDED(hRes)) { _ASSERT(varPROGID.vt == VT_BSTR); hRes = CLSIDFromProgID(varPROGID.bstrVal, &clsid); } if(SUCCEEDED(hRes)) { hRes = CoCreateInstance(clsid, NULL, CLSCTX_ALL, IID_ISEOInitObject, (LPVOID *) ppResult); } return hRes; }