You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
437 lines
14 KiB
437 lines
14 KiB
/*++
|
|
|
|
Copyright (c) 1997 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
gmoniker.cpp
|
|
|
|
Abstract:
|
|
|
|
This module contains the implementation of the
|
|
CSEOGenericMoniker object.
|
|
|
|
Author:
|
|
|
|
Andy Jacobs ([email protected])
|
|
|
|
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<IRunningObjectTable> pROT;
|
|
CComPtr<IUnknown> 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<IPropertyBag> 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<ISEOInitObject> 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<IRunningObjectTable> 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<IMalloc> 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<CSEOGenericMoniker> *pMoniker;
|
|
HRESULT hRes = CComObject<CSEOGenericMoniker>::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;
|
|
}
|
|
|