/*++ Copyright (c) 1997 Microsoft Corporation Module Name: metabag.cpp Abstract: This module contains the implementation for an ISEODicitonary Object on the Metabase. Author: Andy Jacobs (andyj@microsoft.com) Revision History: andyj 03/11/97 created --*/ // METABAG.cpp : Implementation of CSEOMetaDictionary #include "stdafx.h" #include "seodefs.h" #include "IADMW.H" #include "METABAG.h" #include #include #ifdef DEBUG #define MY_OUTPUT_DEBUG_STRING(x) OutputDebugString("SEO.DLL: " x); #define MY_OUTPUT_DEBUG_STRING_HR(hr,x) if (FAILED(hr)) { MY_OUTPUT_DEBUG_STRING(x) } #else #define MY_OUTPUT_DEBUG_STRING(x) #define MY_OUTPUT_DEBUG_STRING_HR(hr,x) #endif #if 1 #define MY_ASSERTE(x) _ASSERTE(x) #define MY_ASSERTE_CHK_HR(hr,chk) MY_ASSERTE(chk(hr)) #else #ifdef DEBUG inline BOOL __assert_output(LPCSTR pszFile, DWORD dwLine, LPCSTR pszFmt, ...) { CHAR szOutput[512]; LPSTR pszOutput; DWORD dwLen; _snprintf(szOutput,510,"ASSERT: %s(%u): \r\n",pszFile,dwLine); dwLen = lstrlen(szOutput); if (dwLen < 508) { va_list valArgs; va_start(valArgs,pszFmt); pszOutput = szOutput + dwLen - 2; _vsnprintf(pszOutput,508-dwLen,pszFmt,valArgs); lstrcat(szOutput,"\r\n"); va_end(valArgs); } OutputDebugString(szOutput); DebugBreak(); return (FALSE); } #define MY_ASSERTE(x) ((x)?1:__assert_output(__FILE__,__LINE__,#x)) #define MY_ASSERTE_CHK_HR(hr,chk) (chk(hr)?1:__assert_output(__FILE__,__LINE__,"hr=0x%x",(hr))) #else #define MY_ASSERTE(X) #define MY_ASSERTE_CHK_HR(hr,chk) #endif #endif #define MY_ASSERTE_HR(hr) MY_ASSERTE_CHK_HR(hr,SUCCEEDED) #define MY_CHK_RPC_HR(hr) (SUCCEEDED(hr) || \ (HRESULT_FACILITY(hr)==FACILITY_RPC) || \ ((hr)==HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE)) || \ ((hr)==HRESULT_FROM_WIN32(RPC_S_CALL_FAILED_DNE))) #define MY_ASSERTE_RPC_HR(hr) MY_ASSERTE_CHK_HR(hr,MY_CHK_RPC_HR) ///////////////////////////////////////////////////////////////////////////// // CChangeNotify class ATL_NO_VTABLE CChangeNotify : public CComObjectRootEx, // public CComCoClass, public IMSAdminBaseSinkW { public: HRESULT FinalConstruct(); void FinalRelease(); HRESULT Advise(CGlobalInterface *pMetabaseHandle); HRESULT Unadvise(); HRESULT AddNotify(CSEOMetaDictionary *pNotify); HRESULT RemoveNotify(CSEOMetaDictionary *pNotify); DECLARE_PROTECT_FINAL_CONSTRUCT(); DECLARE_NOT_AGGREGATABLE(CChangeNotify); // DECLARE_REGISTRY_RESOURCEID_EX(IDR_StdAfx, // L"ChangeNotify Class", // L"Metabag.ChangeNotify.1", // L"Metabag.ChangeNotify"); DECLARE_GET_CONTROLLING_UNKNOWN(); BEGIN_COM_MAP(CChangeNotify) COM_INTERFACE_ENTRY_IID(IID_IMSAdminBaseSink_W, IMSAdminBaseSinkW) COM_INTERFACE_ENTRY_AGGREGATE(IID_IMarshal, m_pUnkMarshaler.p) END_COM_MAP() // IMSAdminBaseSinkW public: HRESULT STDMETHODCALLTYPE SinkNotify(DWORD dwMDNumElements, MD_CHANGE_OBJECT_W pcoChangeList[]); HRESULT STDMETHODCALLTYPE ShutdownNotify(void); private: CComPtr m_pLock; DWORD m_dwNotifyCount; CSEOMetaDictionary **m_apNotify; DWORD m_dwCookie; CGlobalInterface *m_pMetabaseHandle; BOOL m_bConnected; CComPtr m_pUnkMarshaler; }; ///////////////////////////////////////////////////////////////////////////// // CChangeNotify HRESULT CChangeNotify::FinalConstruct() { TraceFunctEnter("CChangeNotify::FinalConstruct"); HRESULT hrRes = S_OK; m_dwNotifyCount = 0; m_apNotify = NULL; m_pMetabaseHandle = NULL; m_bConnected = FALSE; hrRes = CoCreateInstance(CLSID_CEventLock,NULL,CLSCTX_ALL,IID_IEventLock,(LPVOID *) &m_pLock); MY_OUTPUT_DEBUG_STRING_HR(hrRes,"CChangeNotify::FinalConstruct - CoCreateInstance failed.\n") if (SUCCEEDED(hrRes)) { hrRes = CoCreateFreeThreadedMarshaler(GetControllingUnknown(),&m_pUnkMarshaler.p); MY_OUTPUT_DEBUG_STRING_HR(hrRes,"CChangeNotify::FinalConstruct - CoCreateFreeThreadedMarshaler failed.\n") _ASSERTE(!SUCCEEDED(hrRes)||m_pUnkMarshaler); } TraceFunctLeave(); return (SUCCEEDED(hrRes)?S_OK:hrRes); } void CChangeNotify::FinalRelease() { TraceFunctEnter("CChangeNotify::FinalRelease"); _ASSERTE(!m_apNotify); _ASSERTE(!m_pMetabaseHandle); _ASSERTE(!m_bConnected); m_pLock.Release(); m_pUnkMarshaler.Release(); TraceFunctLeave(); } HRESULT CChangeNotify::Advise(CGlobalInterface *pMetabaseHandle) { HRESULT hrRes; CComPtr pCPC; CComPtr pCP; CComQIPtr pThis = this; _ASSERTE(pThis); hrRes = m_pLock->LockWrite(5000); if (!SUCCEEDED(hrRes)) { return (hrRes); } _ASSERTE(!m_apNotify); _ASSERTE(!m_pMetabaseHandle); if (!pMetabaseHandle) { m_pLock->UnlockWrite(); return (E_POINTER); } m_pMetabaseHandle = pMetabaseHandle; hrRes = m_pMetabaseHandle->GetInterfaceQI(IID_IConnectionPointContainer,(LPVOID *) &pCPC); if (!SUCCEEDED(hrRes)) { m_pMetabaseHandle = NULL; m_pLock->UnlockWrite(); MY_ASSERTE_RPC_HR(hrRes); // expected metabase to implement IConnectionPointContainer return (S_OK); } hrRes = pCPC->FindConnectionPoint(IID_IMSAdminBaseSink_W,&pCP); _ASSERTE(!SUCCEEDED(hrRes)||pCP); if (!SUCCEEDED(hrRes)) { m_pMetabaseHandle = NULL; m_pLock->UnlockWrite(); MY_ASSERTE_RPC_HR(hrRes); // expected metabase to source IMSAdminBaseSink_W return (S_OK); } m_pLock->UnlockWrite(); return (S_OK); } HRESULT CChangeNotify::Unadvise() { HRESULT hrRes; CComPtr pCPC; CComPtr pCP; if (!m_pMetabaseHandle) { return (S_OK); } hrRes = m_pLock->LockWrite(5000); if (!SUCCEEDED(hrRes)) { return (hrRes); } if (m_apNotify) { CoTaskMemFree(m_apNotify); m_apNotify = NULL; } hrRes = m_pMetabaseHandle->GetInterfaceQI(IID_IConnectionPointContainer,(LPVOID *) &pCPC); if (!SUCCEEDED(hrRes)) { m_pMetabaseHandle = NULL; m_pLock->UnlockWrite(); MY_ASSERTE_RPC_HR(hrRes); // expected metabase to implement IConnectionPointContainer return (hrRes); } hrRes = pCPC->FindConnectionPoint(IID_IMSAdminBaseSink_W,&pCP); _ASSERTE(!SUCCEEDED(hrRes)||pCP); if (!SUCCEEDED(hrRes)) { m_pMetabaseHandle = NULL; m_pLock->UnlockWrite(); MY_ASSERTE_RPC_HR(hrRes); // expected metabase to source IMSAdminBaseSink_W return (hrRes); } if (m_dwNotifyCount) { _ASSERTE(FALSE); // Object leak detected! hrRes = pCP->Unadvise(m_dwCookie); MY_ASSERTE_RPC_HR(hrRes); } m_pMetabaseHandle = NULL; m_pLock->UnlockWrite(); return (S_OK); } HRESULT CChangeNotify::AddNotify(CSEOMetaDictionary *pNotify) { HRESULT hrRes; CSEOMetaDictionary **apNotify; if (!pNotify) { return (E_POINTER); } if (!m_pMetabaseHandle) { return (S_OK); } hrRes = m_pLock->LockWrite(5000); if (!SUCCEEDED(hrRes)) { return (hrRes); } apNotify = (CSEOMetaDictionary **) CoTaskMemRealloc(m_apNotify,sizeof(CSEOMetaDictionary *)*(m_dwNotifyCount+1)); if (!apNotify) { m_pLock->UnlockWrite(); return (E_OUTOFMEMORY); } m_apNotify = apNotify; m_apNotify[m_dwNotifyCount] = pNotify; m_dwNotifyCount++; if (!m_bConnected) { CComPtr pCPC; CComPtr pCP; CComQIPtr pThis = this; _ASSERTE(m_dwNotifyCount==1); m_bConnected = TRUE; m_pLock->UnlockWrite(); _ASSERTE(pThis); hrRes = m_pMetabaseHandle->GetInterfaceQI(IID_IConnectionPointContainer,(LPVOID *) &pCPC); if (SUCCEEDED(hrRes)) { hrRes = pCPC->FindConnectionPoint(IID_IMSAdminBaseSink_W,&pCP); MY_ASSERTE_RPC_HR(hrRes); if (SUCCEEDED(hrRes)) { hrRes = pCP->Advise(pThis,&m_dwCookie); _ASSERTE(SUCCEEDED(hrRes)); } } } else { m_pLock->UnlockWrite(); } return (S_OK); } HRESULT CChangeNotify::RemoveNotify(CSEOMetaDictionary *pNotify) { HRESULT hrRes; DWORD dwIdx; if (!pNotify) { return (E_POINTER); } if (!m_pMetabaseHandle) { return (S_OK); } hrRes = m_pLock->LockWrite(5000); if (!SUCCEEDED(hrRes)) { return (hrRes); } if (!m_apNotify) { m_pLock->UnlockWrite(); return (S_FALSE); } for (dwIdx=0;dwIdxUnlockWrite(); return (S_FALSE); } m_apNotify[dwIdx] = m_apNotify[m_dwNotifyCount-1]; m_apNotify[m_dwNotifyCount-1] = NULL; m_dwNotifyCount--; if (!m_dwNotifyCount) { CComPtr pCPC; CComPtr pCP; DWORD dwCookie = m_dwCookie; _ASSERTE(m_bConnected); m_bConnected = FALSE; m_pLock->UnlockWrite(); hrRes = m_pMetabaseHandle->GetInterfaceQI(IID_IConnectionPointContainer,(LPVOID *) &pCPC); MY_ASSERTE_RPC_HR(hrRes); if (SUCCEEDED(hrRes)) { hrRes = pCPC->FindConnectionPoint(IID_IMSAdminBaseSink_W,&pCP); MY_ASSERTE_RPC_HR(hrRes); if (SUCCEEDED(hrRes)) { hrRes = pCP->Unadvise(dwCookie); MY_ASSERTE_RPC_HR(hrRes); } } } else { m_pLock->UnlockWrite(); } return (S_OK); } HRESULT STDMETHODCALLTYPE CChangeNotify::SinkNotify(DWORD dwMDNumElements, MD_CHANGE_OBJECT_W pcoChangeList[]) { HRESULT hrRes; CComPtr pLock = m_pLock; CSEOMetaDictionary **apNotify; DWORD dwIdx; LPCWSTR *apszChange; _ASSERTE(dwMDNumElements&&pcoChangeList); if (!pcoChangeList) { return (E_POINTER); } if (!dwMDNumElements) { return (S_OK); } hrRes = pLock->LockRead(5000); if (!SUCCEEDED(hrRes)) { return (hrRes); } if (!m_apNotify || !m_dwNotifyCount) { pLock->UnlockRead(); return (S_OK); } apNotify = (CSEOMetaDictionary **) _alloca(sizeof(CSEOMetaDictionary *)*(m_dwNotifyCount+1)); if (!apNotify) { _ASSERTE(FALSE); pLock->UnlockRead(); return (E_OUTOFMEMORY); } apszChange = (LPCWSTR *) _alloca(sizeof(LPWSTR)*(dwMDNumElements+1)); if (!apszChange) { _ASSERTE(FALSE); pLock->UnlockRead(); return (E_OUTOFMEMORY); } memcpy(apNotify,m_apNotify,sizeof(CSEOMetaDictionary *)*m_dwNotifyCount); apNotify[m_dwNotifyCount] = NULL; for (dwIdx=0;apNotify[dwIdx];dwIdx++) { apNotify[dwIdx]->GetControllingUnknown()->AddRef(); } pLock->UnlockRead(); pLock.Release(); for (dwIdx=0;dwIdxOnChange(apszChange); _ASSERTE(SUCCEEDED(hrRes)); apNotify[dwIdx]->GetControllingUnknown()->Release(); } return (S_OK); } HRESULT STDMETHODCALLTYPE CChangeNotify::ShutdownNotify(void) { // tbd return (S_OK); } ///////////////////////////////////////////////////////////////////////////// LPCWSTR szSeparator = L"/"; LPCOLESTR szSaveKey = OLESTR("MetabasePath"); static CComObject *g_pChangeNotify; HRESULT ResolveVariant(IEventPropertyBag *pBag, VARIANT *pvarPropDesired, CComVariant &varResult); // Static member variables CGlobalInterface CSEOMetabase::m_MetabaseHandle; CGlobalInterface CSEOMetabase::m_MetabaseChangeHandle; int CSEOMetabase::m_iCount = 0; HRESULT CSEOMetabase::InitializeMetabase() { EnterCriticalSection(&_Module.m_csWindowCreate); if (m_iCount++) { LeaveCriticalSection(&_Module.m_csWindowCreate); return S_OK; // Already initialized } m_MetabaseHandle.Init(); m_MetabaseChangeHandle.Init(); HRESULT hRes = m_MetabaseHandle.Load(CLSID_MSAdminBase_W); if (FAILED(hRes)) { MY_OUTPUT_DEBUG_STRING("CSEOMetabase::InitializeMetabase - m_MetabaseHandle.Load failed.\n") TerminateMetabase(); LeaveCriticalSection(&_Module.m_csWindowCreate); return hRes; } hRes = m_MetabaseChangeHandle.Load(CLSID_MSAdminBase_W); if (FAILED(hRes)) { MY_OUTPUT_DEBUG_STRING("CSEOMetabase::InitializeMetabase - m_MetabaseChangeHandle.Load failed.\n") TerminateMetabase(); LeaveCriticalSection(&_Module.m_csWindowCreate); return hRes; } hRes = CComObject::CreateInstance(&g_pChangeNotify); if (!SUCCEEDED(hRes)) { MY_OUTPUT_DEBUG_STRING("CSEOMetabase::InitializeMetabase - CComObject::CreateInstance failed.\n") TerminateMetabase(); LeaveCriticalSection(&_Module.m_csWindowCreate); return (hRes); } g_pChangeNotify->GetControllingUnknown()->AddRef(); hRes = g_pChangeNotify->Advise(&m_MetabaseChangeHandle); if (!SUCCEEDED(hRes)) { MY_OUTPUT_DEBUG_STRING("CSEOMetabase::InitializeMetabase - g_pChangeNotify->Advise failed.\n") TerminateMetabase(); LeaveCriticalSection(&_Module.m_csWindowCreate); return (hRes); } LeaveCriticalSection(&_Module.m_csWindowCreate); return hRes; } HRESULT CSEOMetabase::TerminateMetabase() { EnterCriticalSection(&_Module.m_csWindowCreate); --m_iCount; if(m_iCount > 0) { LeaveCriticalSection(&_Module.m_csWindowCreate); return S_OK; // More copies still using it } if (g_pChangeNotify) { g_pChangeNotify->Unadvise(); g_pChangeNotify->GetControllingUnknown()->Release(); g_pChangeNotify = NULL; } if(m_MetabaseHandle) { m_MetabaseHandle.Term(); } if(m_MetabaseChangeHandle) { m_MetabaseChangeHandle.Term(); } LeaveCriticalSection(&_Module.m_csWindowCreate); return S_OK; } HRESULT CSEOMetabase::SetStatus(LockStatus ls, long lTimeout) { if (InitError == m_eStatus) { return (m_hrInitRes); } if(m_pmbDefer) { return m_pmbDefer->SetStatus(ls, lTimeout); } if(!m_MetabaseHandle) return E_FAIL; CComPtr piMetabase; HRESULT hRes = m_MetabaseHandle.GetInterface(&piMetabase); if (!SUCCEEDED(hRes)) { return (hRes); } // tbd: Do we need to count open requests, and wait for same number of close requests? if(m_eStatus == Error) return E_FAIL; if(m_eStatus == ls) return S_OK; // Already in desired state hRes = E_FAIL; if(m_eStatus == Closed) { if((ls == Read) || (ls == Write)) { DWORD dwAccess = ((ls == Write) ? METADATA_PERMISSION_WRITE|METADATA_PERMISSION_READ : METADATA_PERMISSION_READ); hRes = piMetabase->OpenKey(METADATA_MASTER_ROOT_HANDLE, m_pszPath, dwAccess, lTimeout, &m_mhHandle); // If it failed, and we're trying to write, try to create it if(FAILED(hRes) && (ls == Write)) { METADATA_HANDLE mhTemp; hRes = piMetabase->OpenKey(METADATA_MASTER_ROOT_HANDLE, NULL, dwAccess, lTimeout, &mhTemp); if(SUCCEEDED(hRes)) { piMetabase->AddKey(mhTemp, m_pszPath); // Create Path piMetabase->CloseKey(mhTemp); // Close the temp handle // And try one more time hRes = piMetabase->OpenKey(METADATA_MASTER_ROOT_HANDLE, m_pszPath, dwAccess, lTimeout, &m_mhHandle); } } if(SUCCEEDED(hRes)) { m_eStatus = ls; } } // Else unknown request } else if(ls == Closed) { // if(m_eStatus == Write) piMetabase->SaveData(); // I'm not sure if CloseKey() does this hRes = piMetabase->CloseKey(m_mhHandle); m_eStatus = Closed; m_mhHandle = METADATA_MASTER_ROOT_HANDLE; } else if ((ls == Read) && (m_eStatus == Write)) { hRes = S_FALSE; } // Else trying to change state while already opened return hRes; } // Opens the specified path and returns a new string to use as the path HRESULT CSEOMetabase::OpenPath(CSEOMetabaseLock &mbLocker, LPCWSTR pszPath, LPWSTR pszPathBuf, DWORD &dwId, LockStatus lsOpen) { HRESULT hRes = S_OK; if (InitError == m_hrInitRes) { return (m_hrInitRes); } if(m_pmbDefer) { // If we're defering hRes = mbLocker.SetStatus(lsOpen); // Open the master LPWSTR pszPathTmp = (LPWSTR) GetRelPath((LPWSTR) alloca(sizeof(*pszPath)*(GetPathLength() + 1))); ConcatinatePaths(pszPathBuf,pszPathTmp,pszPath); } else { hRes = mbLocker.SetStatus(lsOpen); if(pszPath) { // If there's something to copy wcscpy(pszPathBuf,pszPath); } else { pszPathBuf[0] = 0; // Treat null string like an empty string } } // Future: parse path for //# to indicate a specific entry for dwId dwId = 0; return hRes; } HRESULT CSEOMetabase::EnumKeys(LPCWSTR pszPath, DWORD dwNum, LPWSTR pszName) { if (InitError == m_eStatus) { return (m_hrInitRes); } if(Error == Status()) { return MD_ERROR_NOT_INITIALIZED; // or E_FAIL; } CComPtr piMetabase; HRESULT hRes = m_MetabaseHandle.GetInterface(&piMetabase); if (!SUCCEEDED(hRes)) { return (hRes); } CSEOMetabaseLock mbLocker(this); LPWSTR pszPathBuf = (LPWSTR) alloca(sizeof(*pszPathBuf)*(4 + GetPathLength() + SafeStrlen(pszPath))); DWORD dwDummyId = 0; // Not used in Enum hRes = OpenPath(mbLocker, pszPath, pszPathBuf, dwDummyId); if(FAILED(hRes)) return hRes; return piMetabase->EnumKeys(GetHandle(), pszPathBuf, pszName, dwNum); } HRESULT CSEOMetabase::GetData(LPCWSTR pszPath, DWORD &dwType, DWORD &dwLen, PBYTE pbData) { if (InitError == m_eStatus) { return (m_hrInitRes); } if(Error == Status()) { return MD_ERROR_NOT_INITIALIZED; // or E_FAIL; } CComPtr piMetabase; HRESULT hRes = m_MetabaseHandle.GetInterface(&piMetabase); if (!SUCCEEDED(hRes)) { return (hRes); } METADATA_RECORD mdrData; DWORD dwRequiredDataLen = 0; CSEOMetabaseLock mbLocker(this); LPWSTR pszPathBuf = (LPWSTR) alloca(sizeof(*pszPathBuf)*(4 + GetPathLength() + SafeStrlen(pszPath))); hRes = OpenPath(mbLocker, pszPath, pszPathBuf, mdrData.dwMDIdentifier); if(FAILED(hRes)) return hRes; // Initialize data mdrData.dwMDAttributes = METADATA_NO_ATTRIBUTES; mdrData.dwMDUserType = 0; mdrData.dwMDDataType = 0; mdrData.dwMDDataLen = dwLen; mdrData.pbMDData = (PBYTE) alloca(dwLen); mdrData.dwMDDataTag = 0; hRes = piMetabase->GetData(GetHandle(), pszPathBuf, &mdrData, &dwRequiredDataLen); // Set values for return dwType = mdrData.dwMDDataType; if(dwType == EXPANDSZ_METADATA) { // It needs environment string substitutions // Save the new size in mdrData.dwMDDataLen mdrData.dwMDDataLen = ExpandEnvironmentStringsW((LPCWSTR) mdrData.pbMDData, (LPWSTR) pbData, dwLen); dwType = STRING_METADATA; // Don't need to expand anymore if(!mdrData.dwMDDataLen && *pbData) hRes = E_FAIL; } else { memcpy(pbData, mdrData.pbMDData, min(dwLen, mdrData.dwMDDataLen)); } // if(mdrData.dwMDDataTag) m_piMetabase->ReleaseReferenceData(mdrData.dwMDDataTag); - No longer needed dwLen = ((HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) == hRes) ? dwRequiredDataLen : mdrData.dwMDDataLen); switch (hRes) { // Translate return code case ERROR_PATH_NOT_FOUND: case MD_ERROR_DATA_NOT_FOUND: hRes = SEO_E_NOTPRESENT; break; case HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER): hRes = SEO_S_MOREDATA; break; case ERROR_SUCCESS: hRes = S_OK; break; } return hRes; } // Add path if it doesn't exist already HRESULT CSEOMetabase::AddKey(LPCWSTR pszPath) { if (InitError == m_eStatus) { return (m_hrInitRes); } CComPtr piMetabase; HRESULT hRes = m_MetabaseHandle.GetInterface(&piMetabase); if (!SUCCEEDED(hRes)) { return (hRes); } CSEOMetabaseLock mbLocker(this); LPWSTR pszPathBuf = (LPWSTR) alloca(sizeof(*pszPathBuf)*(4 + GetPathLength() + SafeStrlen(pszPath))); DWORD dwDummyId = 0; // Not needed for AddKey() hRes = OpenPath(mbLocker, pszPath, pszPathBuf, dwDummyId, Write); if(FAILED(hRes)) return hRes; if(Status() != Write) return E_FAIL; // Couldn't open for Writing hRes = piMetabase->AddKey(GetHandle(), pszPathBuf); // Make sure path exists if (hRes == HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS)) { hRes = S_OK; } return (hRes); } HRESULT CSEOMetabase::DeleteKey(LPCWSTR pszPath) { if (InitError == m_eStatus) { return (m_hrInitRes); } CComPtr piMetabase; HRESULT hRes = m_MetabaseHandle.GetInterface(&piMetabase); if (!SUCCEEDED(hRes)) { return (hRes); } CSEOMetabaseLock mbLocker(this); LPWSTR pszPathBuf = (LPWSTR) alloca(sizeof(*pszPathBuf)*(4 + GetPathLength() + SafeStrlen(pszPath))); DWORD dwDummyId = 0; // Not needed for DeleyeKey() hRes = OpenPath(mbLocker, pszPath, pszPathBuf, dwDummyId, Write); if(FAILED(hRes)) return hRes; if(Status() != Write) return E_FAIL; // Couldn't open for Writing hRes = piMetabase->DeleteKey(GetHandle(), pszPathBuf); // Make sure path does not exist if (hRes == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND)) { hRes = S_OK; } return (hRes); } HRESULT CSEOMetabase::SetData(LPCWSTR pszPath, DWORD dwType, DWORD dwLen, PBYTE pbData) { if (InitError == m_eStatus) { return (m_hrInitRes); } CComPtr piMetabase; HRESULT hRes = m_MetabaseHandle.GetInterface(&piMetabase); if (!SUCCEEDED(hRes)) { return (hRes); } METADATA_RECORD mdrData; DWORD dwRequiredDataLen = 0; CSEOMetabaseLock mbLocker(this); LPWSTR pszPathBuf = (LPWSTR) alloca(sizeof(*pszPathBuf)*(4 + GetPathLength() + SafeStrlen(pszPath))); hRes = OpenPath(mbLocker, pszPath, pszPathBuf, mdrData.dwMDIdentifier, Write); if(FAILED(hRes)) return hRes; if(Status() != Write) return E_FAIL; // Couldn't open for Writing // Initialize data mdrData.dwMDAttributes = 0; mdrData.dwMDUserType = 0; mdrData.dwMDDataType = dwType; mdrData.dwMDDataLen = dwLen; mdrData.pbMDData = pbData; mdrData.dwMDDataTag = 0; if(pbData) { // If it's a non-NULL pointer PBYTE pbTemp = (PBYTE) alloca(dwLen + 1); // Make sure string is null-terminated if((dwType == STRING_METADATA) && // If it's a string ((dwLen < 1) || pbData[dwLen - 1])) { // And it's not null-terminated memcpy(pbTemp, pbData, dwLen); pbTemp[dwLen] = 0; // Terminate new string ++dwLen; // Include null terminator in length mdrData.dwMDDataLen = dwLen; // New Length mdrData.pbMDData = pbTemp; // Point to new string } piMetabase->AddKey(GetHandle(), pszPathBuf); // Make sure path exists return piMetabase->SetData(GetHandle(), pszPathBuf, &mdrData); } else { // NULL pointer, so delete it // m_piMetabase->DeleteData(GetHandle(), pbPathBuf, 0, ALL_METADATA); return piMetabase->DeleteKey(GetHandle(), pszPathBuf); } } void CSEOMetabase::ConcatinatePaths(LPWSTR pszResult, LPCWSTR pszP1, LPCWSTR pszP2) { pszResult[0] = 0; if(pszP1 && *pszP1) { //if(szSeparator[0] != pszP1[0]) lstrcat(pszResult, szSeparator); wcscat(pszResult, pszP1); } if(pszP2) { // && *pszP2) { if(szSeparator[0] != pszResult[wcslen(pszResult) - 1]) wcscat(pszResult, szSeparator); if(!*pszP2) { wcscat(pszResult, szSeparator); } else { //lstrcat(pszResult, pszP2 + ((szSeparator[0] != pszP2[0]) ? 0 : lstrlen(szSeparator))); wcscat(pszResult, pszP2); } } //int iLast = lstrlen(pszResult) - 1; //if((iLast >= 0) && (szSeparator[0] == pszResult[iLast])) pszResult[iLast] = 0; } ///////////////////////////////////////////////////////////////////////////// // CSEOMetaDictionaryEnum class CSEOMetaDictionaryEnum : public CComObjectRootEx, public IDispatchImpl { public: HRESULT FinalConstruct(); void FinalRelease(); HRESULT STDMETHODCALLTYPE Next(DWORD, LPVARIANT, LPDWORD); HRESULT STDMETHODCALLTYPE Skip(DWORD); HRESULT STDMETHODCALLTYPE Reset(void); HRESULT STDMETHODCALLTYPE Clone(IEnumVARIANT **); // Not Exported HRESULT STDMETHODCALLTYPE Init(CSEOMetaDictionary *, DWORD dwIndex = 0); BEGIN_COM_MAP(CSEOMetaDictionaryEnum) COM_INTERFACE_ENTRY(IEnumVARIANT) END_COM_MAP() private: // Data members CSEOMetaDictionary *m_dictionary; DWORD m_dwIndex; }; HRESULT CSEOMetaDictionaryEnum::FinalConstruct() { m_dictionary = NULL; m_dwIndex = 0; return S_OK; } void CSEOMetaDictionaryEnum::FinalRelease() { if(m_dictionary) m_dictionary->GetControllingUnknown()->Release(); m_dictionary = NULL; } STDMETHODIMP CSEOMetaDictionaryEnum::Init(CSEOMetaDictionary *pDict, DWORD dwIndex) { if(m_dictionary) m_dictionary->GetControllingUnknown()->Release(); m_dictionary = pDict; m_dwIndex = dwIndex; if(m_dictionary) { m_dictionary->GetControllingUnknown()->AddRef(); } return S_OK; } STDMETHODIMP CSEOMetaDictionaryEnum::Next(DWORD dwCount, LPVARIANT varDest, LPDWORD pdwResultParam) { if(!m_dictionary) return E_FAIL; // Hasn't been properly initialized if(!varDest) return E_POINTER; WCHAR szName[METADATA_MAX_NAME_LEN]; DWORD dwDummy = 0; LPDWORD pdwResult = (pdwResultParam ? pdwResultParam : &dwDummy); *pdwResult = 0; // Nothing done so far HRESULT hrRes = S_OK; // So far, so good while((S_OK == hrRes) && (*pdwResult < dwCount)) { // Must have succeeded to get here, so OK to overwrite hrRes hrRes = m_dictionary->m_mbHelper.EnumKeys(NULL, m_dwIndex, szName); if(SUCCEEDED(hrRes)) { CComVariant varResult(szName); VariantInit(&varDest[*pdwResult]); hrRes = varResult.Detach(&varDest[*pdwResult]); ++(*pdwResult); // Increment successful count for caller ++m_dwIndex; // Point to the next one } } if(HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hrRes) hrRes = S_FALSE; if(HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hrRes) hrRes = S_FALSE; return (FAILED(hrRes) ? hrRes : ((*pdwResult < dwCount) ? S_FALSE : hrRes)); } STDMETHODIMP CSEOMetaDictionaryEnum::Skip(DWORD dwCount) { m_dwIndex += dwCount; return S_OK; } STDMETHODIMP CSEOMetaDictionaryEnum::Reset(void) { m_dwIndex = 0; return S_OK; } STDMETHODIMP CSEOMetaDictionaryEnum::Clone(IEnumVARIANT **ppunkResult) { // Based on Samples\ATL\circcoll\objects.cpp (see also ATL\beeper\beeper.* if (ppunkResult == NULL) return E_POINTER; *ppunkResult = NULL; CComObject *p; HRESULT hrRes = CComObject::CreateInstance(&p); if (!SUCCEEDED(hrRes)) return (hrRes); hrRes = p->Init(m_dictionary, m_dwIndex); if (SUCCEEDED(hrRes)) hrRes = p->QueryInterface(IID_IEnumVARIANT, (void**)ppunkResult); if (FAILED(hrRes)) delete p; return hrRes; } ///////////////////////////////////////////////////////////////////////////// // CSEOMetaDictionary // 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 close the handle if needed, etc. #define METABASE_READ METABASE_HELPER(m_mbHelper, Read) #define METABASE_WRITE METABASE_HELPER(m_mbHelper, Write) HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::get_Item( /* [in] */ VARIANT __RPC_FAR *pvarName, /* [retval][out] */ VARIANT __RPC_FAR *pvarResult) { if(!pvarName || !pvarResult) return E_INVALIDARG; USES_CONVERSION; // Needed for W2A(), etc. CComVariant vNew; HRESULT hrRes = E_INVALIDARG; if(SUCCEEDED(vNew.ChangeType(VT_BSTR, pvarName))) { hrRes = GetVariantA(W2A(vNew.bstrVal), pvarResult); // Convert SEO_E_NOTPRESENT to VT_EMPTY if(SEO_E_NOTPRESENT == hrRes) { VariantClear(pvarResult); hrRes = S_OK; } } return hrRes; } HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::put_Item( /* [in] */ VARIANT __RPC_FAR *pvarName, /* [in] */ VARIANT __RPC_FAR *pvarValue) { if(!pvarName || !pvarValue) return E_INVALIDARG; USES_CONVERSION; // Needed for W2A(), etc. CComVariant vNew; if(SUCCEEDED(vNew.ChangeType(VT_BSTR, pvarName))) { return SetVariantA(W2A(vNew.bstrVal), pvarValue); } else { return E_INVALIDARG; } } HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::get__NewEnum( /* [retval][out] */ IUnknown __RPC_FAR *__RPC_FAR *ppunkResult) { // Based on Samples\ATL\circcoll\objects.cpp (see also ATL\beeper\beeper.* if (ppunkResult == NULL) return E_POINTER; *ppunkResult = NULL; CComObject *p; HRESULT hrRes = CComObject::CreateInstance(&p); if (!SUCCEEDED(hrRes)) return (hrRes); hrRes = p->Init(this); if (SUCCEEDED(hrRes)) hrRes = p->QueryInterface(IID_IEnumVARIANT, (void**)ppunkResult); if (FAILED(hrRes)) delete p; return hrRes; } HRESULT CSEOMetaDictionary::GetVariantW(LPCWSTR pszName, VARIANT __RPC_FAR *pvarResult, BOOL bCreate) { if(!pvarResult) return E_POINTER; if(!pszName) return E_POINTER; CComVariant varResult; HRESULT hRes = E_FAIL; VariantInit(pvarResult); if(*pszName && (szSeparator[0] != pszName[wcslen(pszName) - 1])) { DWORD dwType = 0; DWORD dwCount = METADATA_MAX_NAME_LEN; // Initial buffer size PBYTE pbBuf = NULL; hRes = SEO_S_MOREDATA; while(SEO_S_MOREDATA == hRes) { pbBuf = (PBYTE) alloca(dwCount); hRes = m_mbHelper.GetData(pszName, dwType, dwCount, pbBuf); } if(SUCCEEDED(hRes)) { if(DWORD_METADATA == dwType) varResult = *((long *) pbBuf); else varResult = (LPCWSTR) pbBuf; } } if(varResult.vt == VT_EMPTY) { // nothing found so far, so read as subkey if (!bCreate) { WCHAR szName[METADATA_MAX_NAME_LEN]; hRes = m_mbHelper.EnumKeys(pszName,0,szName); if (hRes == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND)) { return (SEO_E_NOTPRESENT); } } CComPtr pRef; hRes = GetInterfaceW(pszName, IID_ISEODictionary, &pRef); varResult = pRef; } if(SUCCEEDED(hRes)) hRes = varResult.Detach(pvarResult); return hRes; } HRESULT CSEOMetaDictionary::GetVariantA(LPCSTR pszName, VARIANT __RPC_FAR *pvarResult, BOOL bCreate) { if(!pvarResult) return E_INVALIDARG; USES_CONVERSION; // Needed for W2A(), etc. return GetVariantW(A2W(pszName),pvarResult,bCreate); } HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::GetVariantW( /* [in] */ LPCWSTR pszName, /* [retval][out] */ VARIANT __RPC_FAR *pvarResult) { return (GetVariantW(pszName,pvarResult,TRUE)); } HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::GetVariantA( /* [in] */ LPCSTR pszName, /* [retval][out] */ VARIANT __RPC_FAR *pvarResult) { if(!pvarResult) return E_INVALIDARG; USES_CONVERSION; // Needed for W2A(), etc. return GetVariantW(A2W(pszName),pvarResult,TRUE); } HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::SetVariantW( /* [in] */ LPCWSTR pszName, /* [in] */ VARIANT __RPC_FAR *pvarValue) { if(!pvarValue) return E_POINTER; HRESULT hRes = S_OK; if(pvarValue->vt == VT_I4) { hRes = m_mbHelper.SetDWord(pszName, pvarValue->lVal); } else if((pvarValue->vt == VT_UNKNOWN) || (pvarValue->vt == VT_DISPATCH)) { CComQIPtr piDict = pvarValue->punkVal; if(piDict) hRes = CopyDictionary(pszName, piDict); } else if(pvarValue->vt == VT_EMPTY) { // Delete it hRes = m_mbHelper.SetData(pszName, 0, 0, NULL); } else if(pvarValue->vt == VT_BSTR) { // It's a string hRes = m_mbHelper.SetString(pszName, pvarValue->bstrVal); } else { // Try to convert it to a string CComVariant pvarTemp = *pvarValue; hRes = pvarTemp.ChangeType(VT_BSTR); if(SUCCEEDED(hRes)) { hRes = m_mbHelper.SetString(pszName, pvarTemp.bstrVal); } // Else, return the ChangeType error } return hRes; } HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::SetVariantA( /* [in] */ LPCSTR pszName, /* [in] */ VARIANT __RPC_FAR *pvarValue) { if(!pvarValue) return E_POINTER; USES_CONVERSION; // Needed for W2A(), etc. return SetVariantW(A2W(pszName), pvarValue); } HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::GetStringW( /* [in] */ LPCWSTR pszName, /* [out][in] */ DWORD __RPC_FAR *pchCount, /* [retval][size_is][out] */ LPWSTR pszResult) { if(!pszResult) return E_POINTER; DWORD dwType = 0; DWORD dwCountTmp = sizeof(*pszResult) * (*pchCount); HRESULT hRes = m_mbHelper.GetData(pszName, dwType, dwCountTmp, (PBYTE) pszResult); *pchCount = dwCountTmp / sizeof(*pszResult); if(SUCCEEDED(hRes) && (DWORD_METADATA == dwType)) hRes = SEO_E_NOTPRESENT; return hRes; } HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::GetStringA( /* [in] */ LPCSTR pszName, /* [out][in] */ DWORD __RPC_FAR *pchCount, /* [retval][size_is][out] */ LPSTR pszResult) { if(!pszResult) return E_POINTER; USES_CONVERSION; DWORD dwType = 0; DWORD dwByteCount = *pchCount * sizeof(*pszResult); PBYTE pbBuf = (PBYTE) alloca(dwByteCount); HRESULT hRes = m_mbHelper.GetData(A2W(pszName), dwType, dwByteCount, pbBuf); if(SUCCEEDED(hRes) && (DWORD_METADATA == dwType)) hRes = SEO_E_NOTPRESENT; // Now, convert back to ANSI chars if(SUCCEEDED(hRes) && (BINARY_METADATA == dwType)) { memcpy(pszResult, pbBuf, dwByteCount); *pchCount = dwByteCount / sizeof(*pszResult); } else { ATLW2AHELPER(pszResult, (LPCWSTR) pbBuf, sizeof(*pszResult) * min(*pchCount, dwByteCount)); *pchCount = dwByteCount; // Same number of characters } return hRes; } HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::SetStringW( /* [in] */ LPCWSTR pszName, /* [in] */ DWORD chCount, /* [size_is][in] */ LPCWSTR pszValue) { if(!pszValue) return E_POINTER; return m_mbHelper.SetData(pszName, STRING_METADATA, chCount*sizeof(*pszValue), (PBYTE) pszValue); } HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::SetStringA( /* [in] */ LPCSTR pszName, /* [in] */ DWORD chCount, /* [size_is][in] */ LPCSTR pszValue) { if(!pszValue) return E_POINTER; USES_CONVERSION; return m_mbHelper.SetData(A2W(pszName), STRING_METADATA, chCount, (PBYTE) A2W(pszValue)); } HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::GetDWordW( /* [in] */ LPCWSTR pszName, /* [retval][out] */ DWORD __RPC_FAR *pdwResult) { if(!pdwResult) return E_POINTER; DWORD dwType = 0; DWORD dwCount = sizeof(DWORD); HRESULT hRes = m_mbHelper.GetData(pszName, dwType, dwCount, (PBYTE) pdwResult); if(SUCCEEDED(hRes) && (DWORD_METADATA != dwType)) hRes = SEO_E_NOTPRESENT; return hRes; } HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::GetDWordA( /* [in] */ LPCSTR pszName, /* [retval][out] */ DWORD __RPC_FAR *pdwResult) { USES_CONVERSION; // Needed for W2A(), etc. return GetDWordW(A2W(pszName), pdwResult); } HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::SetDWordW( /* [in] */ LPCWSTR pszName, /* [in] */ DWORD dwValue) { return m_mbHelper.SetDWord(pszName, dwValue); } HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::SetDWordA( /* [in] */ LPCSTR pszName, /* [in] */ DWORD dwValue) { USES_CONVERSION; // Needed for W2A(), etc. return m_mbHelper.SetDWord(A2W(pszName), dwValue); } HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::GetInterfaceW( /* [in] */ LPCWSTR pszName, /* [in] */ REFIID iidDesired, /* [retval][iid_is][out] */ IUnknown __RPC_FAR *__RPC_FAR *ppunkResult) { if(!ppunkResult) return E_POINTER; CComObject *pKey; HRESULT hrRes = CComObject::CreateInstance(&pKey); if (FAILED(hrRes)) return (hrRes); CComPtr pAutomaticCleanup = pKey; hrRes = pKey->Init(m_mbHelper, pszName); if (SUCCEEDED(hrRes)) { hrRes = pKey->QueryInterface(iidDesired, (LPVOID *) ppunkResult); } return (hrRes); // tbd: return SEO_E_NOTPRESENT; // Didn't find it } HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::GetInterfaceA( /* [in] */ LPCSTR pszName, /* [in] */ REFIID iidDesired, /* [retval][iid_is][out] */ IUnknown __RPC_FAR *__RPC_FAR *ppunkResult) { USES_CONVERSION; // Needed for W2A(), etc. return GetInterfaceW(A2W(pszName), iidDesired, ppunkResult); } HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::SetInterfaceW( /* [in] */ LPCWSTR pszName, /* [in] */ IUnknown __RPC_FAR *punkValue) { CComQIPtr piDict = punkValue; return (piDict ? CopyDictionary(pszName, piDict) : E_INVALIDARG); } HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::SetInterfaceA( /* [in] */ LPCSTR pszName, /* [in] */ IUnknown __RPC_FAR *punkValue) { USES_CONVERSION; // Needed for W2A(), etc. return SetInterfaceW(A2W(pszName), punkValue); } HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::GetClassID(/* [out] */ CLSID __RPC_FAR *pClassID) { memcpy(pClassID, &CLSID_CSEOMetaDictionary, sizeof(CLSID)); _ASSERT(IsEqualCLSID(*pClassID, CLSID_CSEOMetaDictionary)); return S_OK; } HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::InitNew(void) { return S_OK; } HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::Load( /* [in] */ IPropertyBag __RPC_FAR *pPropBag, /* [in] */ IErrorLog __RPC_FAR * /*pErrorLog*/) { if(!pPropBag) return E_POINTER; CComVariant varPath; varPath.vt = VT_BSTR; // Request type from Read() varPath.bstrVal = NULL; HRESULT hRes = pPropBag->Read(szSaveKey, &varPath, NULL); if(SUCCEEDED(hRes)) m_mbHelper.SetPath(varPath.bstrVal); return hRes; } HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::Save( /* [in] */ IPropertyBag __RPC_FAR *pPropBag, /* [in] */ BOOL /*fClearDirty*/, /* [in] */ BOOL /*fSaveAllProperties*/) { if(!pPropBag) return E_POINTER; LPWSTR pszBuf = (LPWSTR) alloca(sizeof(*pszBuf)*(m_mbHelper.GetPathLength() + 1)); // Temporary buffer to hold path CComVariant varPath = m_mbHelper.GetPath(pszBuf); return pPropBag->Write(szSaveKey, &varPath); } HRESULT CSEOMetaDictionary::FinalConstruct() { HRESULT hrRes; hrRes = CoCreateFreeThreadedMarshaler(GetControllingUnknown(),&m_pUnkMarshaler.p); _ASSERTE(!SUCCEEDED(hrRes)||m_pUnkMarshaler); return (SUCCEEDED(hrRes)?S_OK:hrRes); } void CSEOMetaDictionary::FinalRelease() { m_pUnkMarshaler.Release(); } HRESULT CSEOMetaDictionary::OnChange(LPCWSTR *apszPath) { HRESULT hrRes; CComPtr pCP; CComPtr pEnum; CONNECTDATA cd; BOOL bDoNotify = FALSE; CSEOConnectionPointImpl *pCPImpl; LPWSTR pszThisPath = NULL; DWORD dwThisPathLen; if (!apszPath) { _ASSERTE(FALSE); return (E_POINTER); } if (!apszPath[0]) { _ASSERTE(FALSE); return (S_OK); } Lock(); pCPImpl = (CSEOConnectionPointImpl *) this; if (!pCPImpl->GetCount()) { Unlock(); return (S_OK); } Unlock(); hrRes = FindConnectionPoint(IID_IEventNotifyBindingChange,&pCP); if (!SUCCEEDED(hrRes)) { _ASSERTE(FALSE); return (S_OK); } hrRes = pCP->EnumConnections(&pEnum); if (!SUCCEEDED(hrRes)) { _ASSERTE(FALSE); return (S_OK); } while (1) { hrRes = pEnum->Next(1,&cd,NULL); if (!SUCCEEDED(hrRes)) { _ASSERTE(FALSE); return (S_OK); } if (hrRes == S_FALSE) { break; } if (!bDoNotify) { if (!pszThisPath) { pszThisPath = (LPWSTR) _alloca(sizeof(*pszThisPath)*(m_mbHelper.GetPathLength()+1)); if (!pszThisPath) { _ASSERTE(FALSE); return (S_OK); } m_mbHelper.GetPath(pszThisPath); dwThisPathLen = wcslen(pszThisPath); if (dwThisPathLen && (pszThisPath[dwThisPathLen-1] == szSeparator[0])) { dwThisPathLen--; } if (dwThisPathLen && (pszThisPath[0] == szSeparator[0])) { pszThisPath++; dwThisPathLen--; } } for (DWORD dwIdx=0;apszPath[dwIdx];dwIdx++) { DWORD dwPathLen; LPCWSTR pszPath; pszPath = apszPath[dwIdx]; dwPathLen = wcslen(pszPath); if (dwPathLen && (pszPath[dwPathLen-1] == szSeparator[0])) { dwPathLen--; } if (dwPathLen && (pszPath[0] == szSeparator[0])) { pszPath++; dwPathLen--; } if ((dwThisPathLen > dwPathLen) || (memicmp(pszThisPath,pszPath,dwThisPathLen*sizeof(pszPath[0])) != 0)) { continue; } if (!dwThisPathLen || (dwThisPathLen == dwPathLen) || (pszPath[dwThisPathLen] == szSeparator[0])) { bDoNotify = TRUE; break; } } } if (bDoNotify) { hrRes = ((IEventNotifyBindingChange *) cd.pUnk)->OnChange(); _ASSERTE(SUCCEEDED(hrRes)); } cd.pUnk->Release(); if (!bDoNotify) { break; } } return (S_OK); } void CSEOMetaDictionary::AdviseCalled(IUnknown *pUnk, DWORD *pdwCookie, REFIID riid, DWORD dwCount) { HRESULT hrRes; if (dwCount == 1) { if (!g_pChangeNotify) { return; } hrRes = g_pChangeNotify->AddNotify(this); _ASSERTE(SUCCEEDED(hrRes)); } } void CSEOMetaDictionary::UnadviseCalled(DWORD dwCookie, REFIID riid, DWORD dwCount) { HRESULT hrRes; if (dwCount == 0) { if (!g_pChangeNotify) { return; } hrRes = g_pChangeNotify->RemoveNotify(this); _ASSERTE(SUCCEEDED(hrRes)); } } HRESULT CSEOMetaDictionary::CopyDictionary(LPCWSTR pszName, ISEODictionary *pBag) { if(!pBag) return S_OK; // Nothing to copy // If not already open for writing, make it so CSEOMetabaseLock mbLocker(&m_mbHelper); if(::Write != m_mbHelper.Status()) { mbLocker.SetStatus(::Write); } CComObject *pKey; // New Subkey HRESULT hrRes = CComObject::CreateInstance(&pKey); if (FAILED(hrRes)) return (hrRes); CComPtr pAutomaticCleanup = pKey; hrRes = m_mbHelper.DeleteKey(pszName); // Empty Metabase path if (FAILED(hrRes)) return (hrRes); hrRes = m_mbHelper.AddKey(pszName); // Create Metabase path if (FAILED(hrRes)) return (hrRes); hrRes = pKey->InitShare(m_mbHelper, pszName); if (FAILED(hrRes)) return (hrRes); CComPtr piUnk; HRESULT hr = pBag->get__NewEnum(&piUnk); if(FAILED(hr) || !piUnk) return hr; CComQIPtr pieEnum = piUnk; piUnk.Release(); // Done with piUnk - use pieEnum now if(!pieEnum) return E_INVALIDARG; CComVariant varName; // Hold the current property name // Read in and copy all of the properties while(S_OK == pieEnum->Next(1, &varName, NULL)) { CComVariant varDest; // Hold the current result if(SUCCEEDED(pBag->get_Item(&varName, &varDest))) { varName.ChangeType(VT_BSTR); // Try to get a string pKey->SetVariantW(varName.bstrVal, &varDest); } } return S_OK; } HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::Read(LPCOLESTR pszPropName, VARIANT *pVar, IErrorLog *pErrorLog) { HRESULT hrRes; VARTYPE vtType; if (!pszPropName || !pVar) { return (E_POINTER); } vtType = pVar->vt; // VariantClear(pVar); hrRes = GetVariantW(pszPropName,pVar); if (SUCCEEDED(hrRes) && (vtType != VT_EMPTY)) { hrRes = VariantChangeType(pVar,pVar,0,vtType); } if (!SUCCEEDED(hrRes)) { VariantClear(pVar); } return (hrRes); } HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::Write(LPCOLESTR pszPropName, VARIANT *pVar) { return (SetVariantW(pszPropName,pVar)); } HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::Item(VARIANT *pvarPropDesired, VARIANT *pvarPropValue) { if (!pvarPropValue) { return (E_POINTER); } // VariantClear(pvarPropValue); // Might have been initialized by caller (?) CComVariant varResult; HRESULT hrRes = ResolveVariant(this, pvarPropDesired, varResult); if (S_OK != hrRes) { // Don't just check for SUCCEEDED in case it's S_FALSE return (hrRes); } hrRes = GetVariantW(varResult.bstrVal,pvarPropValue,FALSE); if (hrRes == SEO_E_NOTPRESENT) { return (S_FALSE); } #if 0 if (!SUCCEEDED(hrRes)) { return (hrRes); } { CComVariant varTmp(*pvarPropValue); HRESULT hrRes; // hide outer hrRes CComQIPtr pdictTmp; CComPtr punkEnum; CComQIPtr pEnum; hrRes = varTmp.ChangeType(VT_UNKNOWN); // Make it an Unknown (if possible) if (SUCCEEDED(hrRes)) { pdictTmp = varTmp.punkVal; if (!pdictTmp) { VariantClear(pvarPropValue); return (E_NOINTERFACE); } hrRes = pdictTmp->get__NewEnum(&punkEnum); // Get it's Enum object if (!SUCCEEDED(hrRes)) { VariantClear(pvarPropValue); return (hrRes); } pEnum = punkEnum; if (!pEnum) { VariantClear(pvarPropValue); return (E_NOINTERFACE); } varTmp.Clear(); hrRes = pEnum->Next(1,&varTmp,NULL); // Ask Enum for first object if (hrRes == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND)) { VariantClear(pvarPropValue); return (S_FALSE); } if (!SUCCEEDED(hrRes)) { VariantClear(pvarPropValue); return (hrRes); } } } #endif if (SUCCEEDED(hrRes)) { VariantChangeType(pvarPropValue,pvarPropValue,0,VT_DISPATCH); _ASSERTE(pvarPropValue->vt!=VT_UNKNOWN); } #if 0 { HRESULT hrRes; CComVariant varTmp(*pvarPropValue); hrRes = varTmp.ChangeType(VT_UNKNOWN); if (SUCCEEDED(hrRes)) { hrRes = varTmp.ChangeType(VT_DISPATCH); _ASSERTE(SUCCEEDED(hrRes)); if (SUCCEEDED(hrRes)) { VariantClear(pvarPropValue); pvarPropValue->vt = VT_DISPATCH; pvarPropValue->pdispVal = varTmp.pdispVal; pvarPropValue->pdispVal->AddRef(); } hrRes = varTmp.ChangeType(VT_UNKNOWN); _ASSERTE(SUCCEEDED(hrRes)); } } #endif return (hrRes); } HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::Name(long lPropIndex, BSTR *pbstrPropName) { if(!pbstrPropName) { return E_POINTER; } if (lPropIndex < 1) { return (S_FALSE); } *pbstrPropName = NULL; WCHAR szName[METADATA_MAX_NAME_LEN]; HRESULT hrRes = m_mbHelper.EnumKeys(NULL, lPropIndex - 1, szName); if(SUCCEEDED(hrRes)) { *pbstrPropName = SysAllocString(szName); if(!*pbstrPropName) hrRes = E_OUTOFMEMORY; } if(HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hrRes) hrRes = S_FALSE; return hrRes; } HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::Add(BSTR pszPropName, VARIANT *pvarPropValue) { return (SetVariantW(pszPropName,pvarPropValue)); } HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::Remove(VARIANT *pvarPropDesired) { CComVariant varCopy; HRESULT hrRes = ResolveVariant(this, pvarPropDesired, varCopy); if (S_OK != hrRes) { // Don't just check for SUCCEEDED in case it's S_FALSE return (hrRes); } hrRes = m_mbHelper.SetData(varCopy.bstrVal, 0, 0, NULL); if (hrRes == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND)) { return (S_FALSE); } return (hrRes); } HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::get_Count(long *plCount) { if(!plCount) return E_POINTER; *plCount = 0; // Nothing done so far WCHAR szName[METADATA_MAX_NAME_LEN]; HRESULT hrRes = S_OK; // So far, so good while(S_OK == hrRes) { // Must have succeeded to get here, so OK to overwrite hrRes hrRes = m_mbHelper.EnumKeys(NULL, *plCount, szName); if(SUCCEEDED(hrRes)) { ++(*plCount); // Increment successful count for caller } } if(HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hrRes) hrRes = S_OK; return hrRes; } /* Just use get__NewEnum from ISEODictionary HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::get__NewEnum(IUnknown **ppUnkEnum) { return (E_NOTIMPL); } */ HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::LockRead(int iTimeoutMS) { HRESULT hrRes; hrRes = m_mbHelper.SetStatus(::Read,iTimeoutMS); if (!SUCCEEDED(hrRes)) { if (hrRes == HRESULT_FROM_WIN32(ERROR_PATH_BUSY)) { return (EVENTS_E_TIMEOUT); } return (hrRes); } return (S_OK); } HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::UnlockRead() { HRESULT hrRes; hrRes = m_mbHelper.SetStatus(::Closed); if (!SUCCEEDED(hrRes)) { return (hrRes); } return (S_OK); } HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::LockWrite(int iTimeoutMS) { HRESULT hrRes; hrRes = m_mbHelper.SetStatus(::Write,iTimeoutMS); if (!SUCCEEDED(hrRes)) { if (hrRes == HRESULT_FROM_WIN32(ERROR_PATH_BUSY)) { return (EVENTS_E_TIMEOUT); } return (hrRes); } return (S_OK); } HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::UnlockWrite() { HRESULT hrRes; hrRes = m_mbHelper.SetStatus(::Closed); if (!SUCCEEDED(hrRes)) { return (hrRes); } return (S_OK); }