/*++ Copyright (c) 1997 Microsoft Corporation Module Name: metabag.h Abstract: This module contains the definition for the ISEODictionary object on the Metabase. Author: Andy Jacobs (andyj@microsoft.com) Revision History: andyj 03/11/97 created --*/ // METABAG.h : Declaration of the CSEOMetaDictionary //#define TIMEOUT 15000 #define ALWAYS_LOCK 0 #define SafeStrlen(x) ((x)?wcslen(x):0) class CGlobalInterfaceImpl { public: void Init() { m_pUnkObject = NULL; m_piGIT = NULL; }; void Term() { if (m_pUnkObject) { m_pUnkObject->Release(); m_pUnkObject = NULL; } if (m_piGIT) { HRESULT hrRes = m_piGIT->RevokeInterfaceFromGlobal(m_dwCookie); _ASSERTE(SUCCEEDED(hrRes)); m_piGIT->Release(); m_piGIT = NULL; } }; bool operator!() { return (!m_pUnkObject&&!m_piGIT); }; operator bool() { return (m_pUnkObject||m_piGIT); }; protected: HRESULT Load(REFCLSID rclsid, REFIID riid) { return (LoadImpl(rclsid,riid,NULL)); }; HRESULT Load(REFIID riid, IUnknown *pUnkObject) { if (!pUnkObject) { return (E_POINTER); } return (LoadImpl(GUID_NULL,riid,pUnkObject)); }; HRESULT GetInterface(REFIID riid, IUnknown **ppUnkObject) { if (ppUnkObject) { *ppUnkObject = NULL; } if (!ppUnkObject) { return (E_POINTER); } _ASSERTE(m_pUnkObject||m_piGIT); // Not loaded. _ASSERTE(!m_pUnkObject||!m_piGIT); // Internal error. if (m_pUnkObject) { *ppUnkObject = m_pUnkObject; (*ppUnkObject)->AddRef(); return (S_OK); } if (m_piGIT) { return (m_piGIT->GetInterfaceFromGlobal(m_dwCookie,riid,(LPVOID *) ppUnkObject)); } return (E_FAIL); }; HRESULT GetInterfaceQI(REFIID riid, REFIID riidDesired, LPVOID *ppvObject) { CComPtr pUnkObject; HRESULT hrRes; if (ppvObject) { *ppvObject = NULL; } if (!ppvObject) { return (E_POINTER); } hrRes = GetInterface(riid,&pUnkObject); if (!SUCCEEDED(hrRes)) { return (hrRes); } return (pUnkObject->QueryInterface(riidDesired,ppvObject)); }; private: HRESULT LoadImpl(REFCLSID rclsid, REFIID riid, IUnknown *pUnkObject) { HRESULT hrRes; hrRes = CoCreateInstance(CLSID_StdGlobalInterfaceTable, NULL, CLSCTX_ALL, IID_IGlobalInterfaceTable, (LPVOID *) &m_piGIT); _ASSERTE(SUCCEEDED(hrRes)); // Should always succeed on NT4 SP3 and later. if (!SUCCEEDED(hrRes) && (hrRes != REGDB_E_CLASSNOTREG)) { return (hrRes); } if (!pUnkObject) { hrRes = CoCreateInstance(rclsid,NULL,CLSCTX_ALL,riid,(LPVOID *) &m_pUnkObject); if (!SUCCEEDED(hrRes)) { if (m_piGIT) { m_piGIT->Release(); m_piGIT = NULL; } return (hrRes); } } else { m_pUnkObject = pUnkObject; m_pUnkObject->AddRef(); } if (m_piGIT) { hrRes = m_piGIT->RegisterInterfaceInGlobal(m_pUnkObject,riid,&m_dwCookie); m_pUnkObject->Release(); m_pUnkObject = NULL; if (!SUCCEEDED(hrRes)) { m_piGIT->Release(); m_piGIT = NULL; return (hrRes); } } return (S_OK); }; IUnknown *m_pUnkObject; DWORD m_dwCookie; IGlobalInterfaceTable *m_piGIT; }; template class CGlobalInterface : public CGlobalInterfaceImpl { public: HRESULT Load(REFCLSID rclsid) { return (CGlobalInterfaceImpl::Load(rclsid,*pIID)); }; HRESULT Load(T *pT) { if (!pT) { return (E_POINTER); } return (CGlobalInterfaceImpl::Load(*pIID,(IUnknown *) pT)); }; HRESULT GetInterface(T **ppT) { return (CGlobalInterfaceImpl::GetInterface(*pIID,(IUnknown **) ppT)); }; HRESULT GetInterfaceQI(REFIID riidDesired,LPVOID *ppv) { return (CGlobalInterfaceImpl::GetInterfaceQI(*pIID,riidDesired,ppv)); }; }; struct IMSAdminBaseW; class CSEOMetabaseLock; enum LockStatus {Closed, Read, Write, Error, DontCare, InitError}; class CSEOMetabase { // Wrapper for Metabase funcitons public: CSEOMetabase() { m_mhHandle = METADATA_MASTER_ROOT_HANDLE; m_eStatus = Closed; // Closed until we delegate m_pszPath = (LPWSTR) MyMalloc(sizeof(*m_pszPath)); m_pmbDefer = NULL; if(!m_pszPath) { m_hrInitRes = E_OUTOFMEMORY; goto Exit; } *m_pszPath = 0; m_hrInitRes = InitializeMetabase(); Exit: if(!SUCCEEDED(m_hrInitRes)) { m_eStatus = InitError; } }; ~CSEOMetabase() { if(!m_pmbDefer) SetStatus(Closed); // Close self on cleanup if (SUCCEEDED(m_hrInitRes)) { TerminateMetabase(); } if(m_pszPath) MyFree(m_pszPath); m_pszPath = NULL; m_pmbDefer = NULL; }; void operator=(const CSEOMetabase &mbMetabase) { SetPath(mbMetabase.m_pszPath); }; HRESULT InitShare(CSEOMetabase *pmbOther, LPCWSTR pszPath, LPUNKNOWN punkOwner = NULL) { LPWSTR pszTmp = NULL; m_punkDeferOwner = punkOwner; m_pmbDefer = pmbOther; if (pszPath) { pszTmp = (LPWSTR) MyMalloc(sizeof(*pszPath)*(SafeStrlen(pszPath) + 1)); if(!pszTmp) return E_OUTOFMEMORY; wcscpy(pszTmp, pszPath); } if(m_pszPath) MyFree(m_pszPath); m_pszPath = pszTmp; return S_OK; }; LockStatus Status() const { return (m_pmbDefer ? m_pmbDefer->Status() : m_eStatus); }; HRESULT SetStatus(LockStatus ls, long lTimeout=15000); HRESULT EnumKeys(LPCWSTR pszPath, DWORD dwNum, LPWSTR pszName); HRESULT AddKey(LPCWSTR pszPathBuf); HRESULT DeleteKey(LPCWSTR pszPathBuf); HRESULT GetData(LPCWSTR path, DWORD &dwType, DWORD &dwLen, PBYTE pbData); HRESULT SetData(LPCWSTR path, DWORD dwType, DWORD dwLen, PBYTE pbData); HRESULT SetDWord(LPCWSTR path, DWORD dwData) { return SetData(path, DWORD_METADATA, sizeof(DWORD), (PBYTE) &dwData); }; HRESULT SetString(LPCWSTR path, LPCWSTR psData, int iLen = -1) { if(iLen < 0) iLen = sizeof(*psData) * (SafeStrlen(psData) + 1); return SetData(path, STRING_METADATA, iLen, (PBYTE) psData); }; METADATA_HANDLE GetHandle() { if(m_pmbDefer) { return m_pmbDefer->GetHandle(); } else { return m_mhHandle; // Not defering, so use our handle } }; int GetPathLength() { int iRet = SafeStrlen(m_pszPath); if(m_pmbDefer) { iRet += (3 + m_pmbDefer->GetPathLength()); } return iRet; }; LPCWSTR GetRelPath(LPWSTR psRet) { // Get the Relative Path from the original deferer if(!psRet) return psRet; if(m_pmbDefer) { LPWSTR psBuf = (LPWSTR) alloca(sizeof(*psBuf)*(m_pmbDefer->GetPathLength() + 1)); m_pmbDefer->GetRelPath(psBuf); ConcatinatePaths(psRet,psBuf,m_pszPath); } else { *psRet = 0; // Empty string } return psRet; }; LPCWSTR GetPath(LPWSTR psRet) { if(!psRet) return psRet; if(m_pmbDefer) { LPWSTR psBuf = (LPWSTR) alloca(sizeof(*psBuf)*(m_pmbDefer->GetPathLength() + 1)); m_pmbDefer->GetPath(psBuf); ConcatinatePaths(psRet, psBuf,m_pszPath); } else { wcscpy(psRet,m_pszPath); } return psRet; }; void AppendPath(LPCWSTR pszPathParam) { LPWSTR pszPath = (LPWSTR) alloca(sizeof(*pszPath)*(SafeStrlen(m_pszPath)+SafeStrlen(pszPathParam)+3)); ConcatinatePaths(pszPath,m_pszPath,pszPathParam); SetPath(pszPath); }; void SetPath(LPCWSTR pszPath) { LPWSTR pszTmp = NULL; SetStatus(Closed); // Make sure we're closed if (pszPath) { pszTmp = (LPWSTR) MyMalloc((sizeof(*pszTmp))*(SafeStrlen(pszPath)+3)); if(!pszTmp) return; ConcatinatePaths(pszTmp,pszPath,NULL); } if(m_pszPath) MyFree(m_pszPath); m_pszPath = pszTmp; }; static HRESULT InitializeMetabase(); static HRESULT TerminateMetabase(); protected: void ConcatinatePaths(LPWSTR pszResult, LPCWSTR pszP1, LPCWSTR pszP2); HRESULT OpenPath(CSEOMetabaseLock &mbLocker, LPCWSTR pszPath, LPWSTR pszPathBuf, DWORD &dwId, LockStatus lsOpen = Read); private: LPWSTR m_pszPath; METADATA_HANDLE m_mhHandle; LockStatus m_eStatus; CSEOMetabase *m_pmbDefer; // Defer to this object if set CComPtr m_punkDeferOwner; // Keep reference count HRESULT m_hrInitRes; static CGlobalInterface m_MetabaseHandle; static CGlobalInterface m_MetabaseChangeHandle; static int m_iCount; // Number of calls to InitializeMetabase() }; class CSEOMetabaseLock { public: CSEOMetabaseLock(CSEOMetabase *piObject, LockStatus ls = DontCare) { m_bChanged = FALSE; m_piObject = piObject; if(DontCare != ls) SetStatus(ls); }; ~CSEOMetabaseLock() { if(m_bChanged) SetStatus(m_lsPrevious); }; HRESULT SetStatus(LockStatus ls) { if(!m_piObject) return E_FAIL; // Not initialized m_lsPrevious = m_piObject->Status(); HRESULT hRes = m_piObject->SetStatus(ls); LockStatus lsNewStatus = m_piObject->Status(); if((lsNewStatus != m_lsPrevious) && (hRes != S_FALSE)) m_bChanged = TRUE; if(lsNewStatus == Closed) m_bChanged = FALSE; return hRes; }; private: CSEOMetabase *m_piObject; BOOL m_bChanged; // True if we are responsible for restoring in our destructor LockStatus m_lsPrevious; }; // The following macro may be inserted in a method to support // reading/writing from just that method if handle not already opened. // The object will take care of closing the handle if needed, etc. #define METABASE_HELPER(x,y) CSEOMetabaseLock mbHelper(x, y) ///////////////////////////////////////////////////////////////////////////// // CSEOMetaDictionary class ATL_NO_VTABLE CSEOMetaDictionary : public CComObjectRootEx, public CComCoClass, public ISEOInitObject, public IDispatchImpl, public IPropertyBag, public IDispatchImpl, public IDispatchImpl, public IConnectionPointContainerImpl, // public IConnectionPointImpl public CSEOConnectionPointImpl { friend class CSEOMetaDictionaryEnum; // Helper class public: HRESULT FinalConstruct(); void FinalRelease(); HRESULT OnChange(LPCWSTR *apszPath); HRESULT GetVariantA(LPCSTR pszName, VARIANT *pvarResult, BOOL bCreate); HRESULT GetVariantW(LPCWSTR pszName, VARIANT *pvarResult, BOOL bCreate); DECLARE_PROTECT_FINAL_CONSTRUCT(); DECLARE_REGISTRY_RESOURCEID_EX(IDR_StdAfx, L"SEOMetaDictionary Class", L"SEO.SEOMetaDictionary.1", L"SEO.SEOMetaDictionary"); BEGIN_COM_MAP(CSEOMetaDictionary) COM_INTERFACE_ENTRY(ISEODictionary) COM_INTERFACE_ENTRY(ISEOInitObject) COM_INTERFACE_ENTRY_AGGREGATE(IID_IMarshal, m_pUnkMarshaler.p) COM_INTERFACE_ENTRY(IPropertyBag) COM_INTERFACE_ENTRY(IEventPropertyBag) COM_INTERFACE_ENTRY_IID(IID_IDispatch, IEventPropertyBag) COM_INTERFACE_ENTRY(IEventLock) COM_INTERFACE_ENTRY_IMPL(IConnectionPointContainer) END_COM_MAP() BEGIN_CONNECTION_POINT_MAP(CSEOMetaDictionary) CONNECTION_POINT_ENTRY(IID_IEventNotifyBindingChange) END_CONNECTION_POINT_MAP() // CSEOConnectionPointImp<> public: void AdviseCalled(IUnknown *pUnk, DWORD *pdwCookie, REFIID riid, DWORD dwCount); void UnadviseCalled(DWORD dwCookie, REFIID riid, DWORD dwCount); // ISEODictionary public: virtual /* [id][propget][helpstring] */ HRESULT STDMETHODCALLTYPE get_Item( /* [in] */ VARIANT __RPC_FAR *pvarName, /* [retval][out] */ VARIANT __RPC_FAR *pvarResult); virtual /* [propput][helpstring] */ HRESULT STDMETHODCALLTYPE put_Item( /* [in] */ VARIANT __RPC_FAR *pvarName, /* [in] */ VARIANT __RPC_FAR *pvarValue); virtual /* [hidden][id][propget][helpstring] */ HRESULT STDMETHODCALLTYPE get__NewEnum( /* [retval][out] */ IUnknown __RPC_FAR *__RPC_FAR *ppunkResult); virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE GetVariantA( /* [in] */ LPCSTR pszName, /* [retval][out] */ VARIANT __RPC_FAR *pvarResult); virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE GetVariantW( /* [in] */ LPCWSTR pszName, /* [retval][out] */ VARIANT __RPC_FAR *pvarResult); virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE SetVariantA( /* [in] */ LPCSTR pszName, /* [in] */ VARIANT __RPC_FAR *pvarValue); virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE SetVariantW( /* [in] */ LPCWSTR pszName, /* [in] */ VARIANT __RPC_FAR *pvarValue); virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE GetStringA( /* [in] */ LPCSTR pszName, /* [out][in] */ DWORD __RPC_FAR *pchCount, /* [retval][size_is][out] */ LPSTR pszResult); virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE GetStringW( /* [in] */ LPCWSTR pszName, /* [out][in] */ DWORD __RPC_FAR *pchCount, /* [retval][size_is][out] */ LPWSTR pszResult); virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE SetStringA( /* [in] */ LPCSTR pszName, /* [in] */ DWORD chCount, /* [size_is][in] */ LPCSTR pszValue); virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE SetStringW( /* [in] */ LPCWSTR pszName, /* [in] */ DWORD chCount, /* [size_is][in] */ LPCWSTR pszValue); virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE GetDWordA( /* [in] */ LPCSTR pszName, /* [retval][out] */ DWORD __RPC_FAR *pdwResult); virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE GetDWordW( /* [in] */ LPCWSTR pszName, /* [retval][out] */ DWORD __RPC_FAR *pdwResult); virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE SetDWordA( /* [in] */ LPCSTR pszName, /* [in] */ DWORD dwValue); virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE SetDWordW( /* [in] */ LPCWSTR pszName, /* [in] */ DWORD dwValue); virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE GetInterfaceA( /* [in] */ LPCSTR pszName, /* [in] */ REFIID iidDesired, /* [retval][iid_is][out] */ IUnknown __RPC_FAR *__RPC_FAR *ppunkResult); virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE GetInterfaceW( /* [in] */ LPCWSTR pszName, /* [in] */ REFIID iidDesired, /* [retval][iid_is][out] */ IUnknown __RPC_FAR *__RPC_FAR *ppunkResult); virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE SetInterfaceA( /* [in] */ LPCSTR pszName, /* [in] */ IUnknown __RPC_FAR *punkValue); virtual /* [helpstring] */ HRESULT STDMETHODCALLTYPE SetInterfaceW( /* [in] */ LPCWSTR pszName, /* [in] */ IUnknown __RPC_FAR *punkValue); // ISEOInitObject (IPersistPropertyBag) public: virtual HRESULT STDMETHODCALLTYPE GetClassID(/* [out] */ CLSID __RPC_FAR *pClassID); virtual HRESULT STDMETHODCALLTYPE InitNew(void); virtual HRESULT STDMETHODCALLTYPE Load( /* [in] */ IPropertyBag __RPC_FAR *pPropBag, /* [in] */ IErrorLog __RPC_FAR *pErrorLog); virtual HRESULT STDMETHODCALLTYPE Save( /* [in] */ IPropertyBag __RPC_FAR *pPropBag, /* [in] */ BOOL fClearDirty, /* [in] */ BOOL fSaveAllProperties); // IPropertyBag public: HRESULT STDMETHODCALLTYPE Read(LPCOLESTR pszPropName, VARIANT *pVar, IErrorLog *pErrorLog); HRESULT STDMETHODCALLTYPE Write(LPCOLESTR pszPropName, VARIANT *pVar); // IEventPropertyBag public: HRESULT STDMETHODCALLTYPE Item(VARIANT *pvarPropDesired, VARIANT *pvarPropValue); HRESULT STDMETHODCALLTYPE Name(long lPropIndex, BSTR *pbstrPropName); HRESULT STDMETHODCALLTYPE Add(BSTR pszPropName, VARIANT *pvarPropValue); HRESULT STDMETHODCALLTYPE Remove(VARIANT *pvarPropDesired); HRESULT STDMETHODCALLTYPE get_Count(long *plCount); /* Just use the get__NewEnum from ISEODictionary HRESULT STDMETHODCALLTYPE get__NewEnum(IUnknown **ppUnkEnum); */ DECLARE_GET_CONTROLLING_UNKNOWN(); // IEventLock public: HRESULT STDMETHODCALLTYPE LockRead(int iTimeoutMS); HRESULT STDMETHODCALLTYPE UnlockRead(); HRESULT STDMETHODCALLTYPE LockWrite(int iTimeoutMS); HRESULT STDMETHODCALLTYPE UnlockWrite(); protected: HRESULT CopyDictionary(LPCWSTR pszName, ISEODictionary *pBag); HRESULT Init(const CSEOMetabase &pmbOther, LPCWSTR pszPath) { m_mbHelper = pmbOther; m_mbHelper.AppendPath(pszPath); return S_OK; }; HRESULT InitShare(CSEOMetabase &pmbOther, LPCWSTR pszPath) { return m_mbHelper.InitShare(&pmbOther, pszPath, this->GetControllingUnknown()); }; private: // Private data CSEOMetabase m_mbHelper; // The master helper CComPtr m_pUnkMarshaler; };