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
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);
|
|
}
|