Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1653 lines
48 KiB

/*++
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 ([email protected])
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 <stdarg.h>
#include <stdio.h>
#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<CComMultiThreadModelNoCS>,
// public CComCoClass<CChangeNotify, &CLSID_CChangeNotify>,
public IMSAdminBaseSinkW
{
public:
HRESULT FinalConstruct();
void FinalRelease();
HRESULT Advise(CGlobalInterface<IMSAdminBaseW,&IID_IMSAdminBase_W> *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<IEventLock> m_pLock;
DWORD m_dwNotifyCount;
CSEOMetaDictionary **m_apNotify;
DWORD m_dwCookie;
CGlobalInterface<IMSAdminBaseW,&IID_IMSAdminBase_W> *m_pMetabaseHandle;
BOOL m_bConnected;
CComPtr<IUnknown> 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<IMSAdminBase,&IID_IMSAdminBase_W> *pMetabaseHandle) {
HRESULT hrRes;
CComPtr<IConnectionPointContainer> pCPC;
CComPtr<IConnectionPoint> pCP;
CComQIPtr<IMSAdminBaseSinkW,&IID_IMSAdminBaseSink_W> 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<IConnectionPointContainer> pCPC;
CComPtr<IConnectionPoint> 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<IConnectionPointContainer> pCPC;
CComPtr<IConnectionPoint> pCP;
CComQIPtr<IMSAdminBaseSinkW,&IID_IMSAdminBaseSink_W> 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;dwIdx<m_dwNotifyCount;dwIdx++) {
if (m_apNotify[dwIdx] == pNotify) {
break;
}
}
if (dwIdx == m_dwNotifyCount) {
m_pLock->UnlockWrite();
return (S_FALSE);
}
m_apNotify[dwIdx] = m_apNotify[m_dwNotifyCount-1];
m_apNotify[m_dwNotifyCount-1] = NULL;
m_dwNotifyCount--;
if (!m_dwNotifyCount) {
CComPtr<IConnectionPointContainer> pCPC;
CComPtr<IConnectionPoint> 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<IEventLock> 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;dwIdx<dwMDNumElements;dwIdx++) {
apszChange[dwIdx] = pcoChangeList[dwIdx].pszMDPath;
}
apszChange[dwMDNumElements] = NULL;
for (dwIdx=0;apNotify[dwIdx];dwIdx++) {
hrRes = apNotify[dwIdx]->OnChange(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<CChangeNotify> *g_pChangeNotify;
HRESULT ResolveVariant(IEventPropertyBag *pBag, VARIANT *pvarPropDesired, CComVariant &varResult);
// Static member variables
CGlobalInterface<IMSAdminBaseW,&IID_IMSAdminBase_W> CSEOMetabase::m_MetabaseHandle;
CGlobalInterface<IMSAdminBaseW,&IID_IMSAdminBase_W> 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<CChangeNotify>::CreateInstance(&g_pChangeNotify);
if (!SUCCEEDED(hRes)) {
MY_OUTPUT_DEBUG_STRING("CSEOMetabase::InitializeMetabase - CComObject<CChangeNotify>::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<IMSAdminBaseW> 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<IMSAdminBaseW> 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<IMSAdminBaseW> 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<IMSAdminBaseW> 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<IMSAdminBaseW> 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<IMSAdminBaseW> 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<CComMultiThreadModelNoCS>,
public IDispatchImpl<IEnumVARIANT, &IID_IEnumVARIANT, &LIBID_SEOLib>
{
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<CSEOMetaDictionaryEnum> *p;
HRESULT hrRes = CComObject<CSEOMetaDictionaryEnum>::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<CSEOMetaDictionaryEnum> *p;
HRESULT hrRes = CComObject<CSEOMetaDictionaryEnum>::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<IUnknown> 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<ISEODictionary, &IID_ISEODictionary> 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<CSEOMetaDictionary> *pKey;
HRESULT hrRes = CComObject<CSEOMetaDictionary>::CreateInstance(&pKey);
if (FAILED(hrRes)) return (hrRes);
CComPtr<ISEODictionary> 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<ISEODictionary, &IID_ISEODictionary> 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<IConnectionPoint> pCP;
CComPtr<IEnumConnections> pEnum;
CONNECTDATA cd;
BOOL bDoNotify = FALSE;
CSEOConnectionPointImpl<CSEOMetaDictionary,&IID_IEventNotifyBindingChange> *pCPImpl;
LPWSTR pszThisPath = NULL;
DWORD dwThisPathLen;
if (!apszPath) {
_ASSERTE(FALSE);
return (E_POINTER);
}
if (!apszPath[0]) {
_ASSERTE(FALSE);
return (S_OK);
}
Lock();
pCPImpl = (CSEOConnectionPointImpl<CSEOMetaDictionary,&IID_IEventNotifyBindingChange> *) 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<CSEOMetaDictionary> *pKey; // New Subkey
HRESULT hrRes = CComObject<CSEOMetaDictionary>::CreateInstance(&pKey);
if (FAILED(hrRes)) return (hrRes);
CComPtr<ISEODictionary> 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<IUnknown> piUnk;
HRESULT hr = pBag->get__NewEnum(&piUnk);
if(FAILED(hr) || !piUnk) return hr;
CComQIPtr<IEnumVARIANT, &IID_IEnumVARIANT> 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<ISEODictionary,&IID_ISEODictionary> pdictTmp;
CComPtr<IUnknown> punkEnum;
CComQIPtr<IEnumVARIANT,&IID_IEnumVARIANT> 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);
}