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

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. metabag.cpp
  5. Abstract:
  6. This module contains the implementation for an ISEODicitonary
  7. Object on the Metabase.
  8. Author:
  9. Andy Jacobs (andyj@microsoft.com)
  10. Revision History:
  11. andyj 03/11/97 created
  12. --*/
  13. // METABAG.cpp : Implementation of CSEOMetaDictionary
  14. #include "stdafx.h"
  15. #include "seodefs.h"
  16. #include "IADMW.H"
  17. #include "METABAG.h"
  18. #include <stdarg.h>
  19. #include <stdio.h>
  20. #ifdef DEBUG
  21. #define MY_OUTPUT_DEBUG_STRING(x) OutputDebugString("SEO.DLL: " x);
  22. #define MY_OUTPUT_DEBUG_STRING_HR(hr,x) if (FAILED(hr)) { MY_OUTPUT_DEBUG_STRING(x) }
  23. #else
  24. #define MY_OUTPUT_DEBUG_STRING(x)
  25. #define MY_OUTPUT_DEBUG_STRING_HR(hr,x)
  26. #endif
  27. #if 1
  28. #define MY_ASSERTE(x) _ASSERTE(x)
  29. #define MY_ASSERTE_CHK_HR(hr,chk) MY_ASSERTE(chk(hr))
  30. #else
  31. #ifdef DEBUG
  32. inline BOOL __assert_output(LPCSTR pszFile, DWORD dwLine, LPCSTR pszFmt, ...) {
  33. CHAR szOutput[512];
  34. LPSTR pszOutput;
  35. DWORD dwLen;
  36. _snprintf(szOutput,510,"ASSERT: %s(%u): \r\n",pszFile,dwLine);
  37. dwLen = lstrlen(szOutput);
  38. if (dwLen < 508) {
  39. va_list valArgs;
  40. va_start(valArgs,pszFmt);
  41. pszOutput = szOutput + dwLen - 2;
  42. _vsnprintf(pszOutput,508-dwLen,pszFmt,valArgs);
  43. lstrcat(szOutput,"\r\n");
  44. va_end(valArgs);
  45. }
  46. OutputDebugString(szOutput);
  47. DebugBreak();
  48. return (FALSE);
  49. }
  50. #define MY_ASSERTE(x) ((x)?1:__assert_output(__FILE__,__LINE__,#x))
  51. #define MY_ASSERTE_CHK_HR(hr,chk) (chk(hr)?1:__assert_output(__FILE__,__LINE__,"hr=0x%x",(hr)))
  52. #else
  53. #define MY_ASSERTE(X)
  54. #define MY_ASSERTE_CHK_HR(hr,chk)
  55. #endif
  56. #endif
  57. #define MY_ASSERTE_HR(hr) MY_ASSERTE_CHK_HR(hr,SUCCEEDED)
  58. #define MY_CHK_RPC_HR(hr) (SUCCEEDED(hr) || \
  59. (HRESULT_FACILITY(hr)==FACILITY_RPC) || \
  60. ((hr)==HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE)) || \
  61. ((hr)==HRESULT_FROM_WIN32(RPC_S_CALL_FAILED_DNE)))
  62. #define MY_ASSERTE_RPC_HR(hr) MY_ASSERTE_CHK_HR(hr,MY_CHK_RPC_HR)
  63. /////////////////////////////////////////////////////////////////////////////
  64. // CChangeNotify
  65. class ATL_NO_VTABLE CChangeNotify :
  66. public CComObjectRootEx<CComMultiThreadModelNoCS>,
  67. // public CComCoClass<CChangeNotify, &CLSID_CChangeNotify>,
  68. public IMSAdminBaseSinkW
  69. {
  70. public:
  71. HRESULT FinalConstruct();
  72. void FinalRelease();
  73. HRESULT Advise(CGlobalInterface<IMSAdminBaseW,&IID_IMSAdminBase_W> *pMetabaseHandle);
  74. HRESULT Unadvise();
  75. HRESULT AddNotify(CSEOMetaDictionary *pNotify);
  76. HRESULT RemoveNotify(CSEOMetaDictionary *pNotify);
  77. DECLARE_PROTECT_FINAL_CONSTRUCT();
  78. DECLARE_NOT_AGGREGATABLE(CChangeNotify);
  79. // DECLARE_REGISTRY_RESOURCEID_EX(IDR_StdAfx,
  80. // L"ChangeNotify Class",
  81. // L"Metabag.ChangeNotify.1",
  82. // L"Metabag.ChangeNotify");
  83. DECLARE_GET_CONTROLLING_UNKNOWN();
  84. BEGIN_COM_MAP(CChangeNotify)
  85. COM_INTERFACE_ENTRY_IID(IID_IMSAdminBaseSink_W, IMSAdminBaseSinkW)
  86. COM_INTERFACE_ENTRY_AGGREGATE(IID_IMarshal, m_pUnkMarshaler.p)
  87. END_COM_MAP()
  88. // IMSAdminBaseSinkW
  89. public:
  90. HRESULT STDMETHODCALLTYPE SinkNotify(DWORD dwMDNumElements, MD_CHANGE_OBJECT_W pcoChangeList[]);
  91. HRESULT STDMETHODCALLTYPE ShutdownNotify(void);
  92. private:
  93. CComPtr<IEventLock> m_pLock;
  94. DWORD m_dwNotifyCount;
  95. CSEOMetaDictionary **m_apNotify;
  96. DWORD m_dwCookie;
  97. CGlobalInterface<IMSAdminBaseW,&IID_IMSAdminBase_W> *m_pMetabaseHandle;
  98. BOOL m_bConnected;
  99. CComPtr<IUnknown> m_pUnkMarshaler;
  100. };
  101. /////////////////////////////////////////////////////////////////////////////
  102. // CChangeNotify
  103. HRESULT CChangeNotify::FinalConstruct() {
  104. TraceFunctEnter("CChangeNotify::FinalConstruct");
  105. HRESULT hrRes = S_OK;
  106. m_dwNotifyCount = 0;
  107. m_apNotify = NULL;
  108. m_pMetabaseHandle = NULL;
  109. m_bConnected = FALSE;
  110. hrRes = CoCreateInstance(CLSID_CEventLock,NULL,CLSCTX_ALL,IID_IEventLock,(LPVOID *) &m_pLock);
  111. MY_OUTPUT_DEBUG_STRING_HR(hrRes,"CChangeNotify::FinalConstruct - CoCreateInstance failed.\n")
  112. if (SUCCEEDED(hrRes)) {
  113. hrRes = CoCreateFreeThreadedMarshaler(GetControllingUnknown(),&m_pUnkMarshaler.p);
  114. MY_OUTPUT_DEBUG_STRING_HR(hrRes,"CChangeNotify::FinalConstruct - CoCreateFreeThreadedMarshaler failed.\n")
  115. _ASSERTE(!SUCCEEDED(hrRes)||m_pUnkMarshaler);
  116. }
  117. TraceFunctLeave();
  118. return (SUCCEEDED(hrRes)?S_OK:hrRes);
  119. }
  120. void CChangeNotify::FinalRelease() {
  121. TraceFunctEnter("CChangeNotify::FinalRelease");
  122. _ASSERTE(!m_apNotify);
  123. _ASSERTE(!m_pMetabaseHandle);
  124. _ASSERTE(!m_bConnected);
  125. m_pLock.Release();
  126. m_pUnkMarshaler.Release();
  127. TraceFunctLeave();
  128. }
  129. HRESULT CChangeNotify::Advise(CGlobalInterface<IMSAdminBase,&IID_IMSAdminBase_W> *pMetabaseHandle) {
  130. HRESULT hrRes;
  131. CComPtr<IConnectionPointContainer> pCPC;
  132. CComPtr<IConnectionPoint> pCP;
  133. CComQIPtr<IMSAdminBaseSinkW,&IID_IMSAdminBaseSink_W> pThis = this;
  134. _ASSERTE(pThis);
  135. hrRes = m_pLock->LockWrite(5000);
  136. if (!SUCCEEDED(hrRes)) {
  137. return (hrRes);
  138. }
  139. _ASSERTE(!m_apNotify);
  140. _ASSERTE(!m_pMetabaseHandle);
  141. if (!pMetabaseHandle) {
  142. m_pLock->UnlockWrite();
  143. return (E_POINTER);
  144. }
  145. m_pMetabaseHandle = pMetabaseHandle;
  146. hrRes = m_pMetabaseHandle->GetInterfaceQI(IID_IConnectionPointContainer,(LPVOID *) &pCPC);
  147. if (!SUCCEEDED(hrRes)) {
  148. m_pMetabaseHandle = NULL;
  149. m_pLock->UnlockWrite();
  150. MY_ASSERTE_RPC_HR(hrRes); // expected metabase to implement IConnectionPointContainer
  151. return (S_OK);
  152. }
  153. hrRes = pCPC->FindConnectionPoint(IID_IMSAdminBaseSink_W,&pCP);
  154. _ASSERTE(!SUCCEEDED(hrRes)||pCP);
  155. if (!SUCCEEDED(hrRes)) {
  156. m_pMetabaseHandle = NULL;
  157. m_pLock->UnlockWrite();
  158. MY_ASSERTE_RPC_HR(hrRes); // expected metabase to source IMSAdminBaseSink_W
  159. return (S_OK);
  160. }
  161. m_pLock->UnlockWrite();
  162. return (S_OK);
  163. }
  164. HRESULT CChangeNotify::Unadvise() {
  165. HRESULT hrRes;
  166. CComPtr<IConnectionPointContainer> pCPC;
  167. CComPtr<IConnectionPoint> pCP;
  168. if (!m_pMetabaseHandle) {
  169. return (S_OK);
  170. }
  171. hrRes = m_pLock->LockWrite(5000);
  172. if (!SUCCEEDED(hrRes)) {
  173. return (hrRes);
  174. }
  175. if (m_apNotify) {
  176. CoTaskMemFree(m_apNotify);
  177. m_apNotify = NULL;
  178. }
  179. hrRes = m_pMetabaseHandle->GetInterfaceQI(IID_IConnectionPointContainer,(LPVOID *) &pCPC);
  180. if (!SUCCEEDED(hrRes)) {
  181. m_pMetabaseHandle = NULL;
  182. m_pLock->UnlockWrite();
  183. MY_ASSERTE_RPC_HR(hrRes); // expected metabase to implement IConnectionPointContainer
  184. return (hrRes);
  185. }
  186. hrRes = pCPC->FindConnectionPoint(IID_IMSAdminBaseSink_W,&pCP);
  187. _ASSERTE(!SUCCEEDED(hrRes)||pCP);
  188. if (!SUCCEEDED(hrRes)) {
  189. m_pMetabaseHandle = NULL;
  190. m_pLock->UnlockWrite();
  191. MY_ASSERTE_RPC_HR(hrRes); // expected metabase to source IMSAdminBaseSink_W
  192. return (hrRes);
  193. }
  194. if (m_dwNotifyCount) {
  195. _ASSERTE(FALSE); // Object leak detected!
  196. hrRes = pCP->Unadvise(m_dwCookie);
  197. MY_ASSERTE_RPC_HR(hrRes);
  198. }
  199. m_pMetabaseHandle = NULL;
  200. m_pLock->UnlockWrite();
  201. return (S_OK);
  202. }
  203. HRESULT CChangeNotify::AddNotify(CSEOMetaDictionary *pNotify) {
  204. HRESULT hrRes;
  205. CSEOMetaDictionary **apNotify;
  206. if (!pNotify) {
  207. return (E_POINTER);
  208. }
  209. if (!m_pMetabaseHandle) {
  210. return (S_OK);
  211. }
  212. hrRes = m_pLock->LockWrite(5000);
  213. if (!SUCCEEDED(hrRes)) {
  214. return (hrRes);
  215. }
  216. apNotify = (CSEOMetaDictionary **) CoTaskMemRealloc(m_apNotify,sizeof(CSEOMetaDictionary *)*(m_dwNotifyCount+1));
  217. if (!apNotify) {
  218. m_pLock->UnlockWrite();
  219. return (E_OUTOFMEMORY);
  220. }
  221. m_apNotify = apNotify;
  222. m_apNotify[m_dwNotifyCount] = pNotify;
  223. m_dwNotifyCount++;
  224. if (!m_bConnected) {
  225. CComPtr<IConnectionPointContainer> pCPC;
  226. CComPtr<IConnectionPoint> pCP;
  227. CComQIPtr<IMSAdminBaseSinkW,&IID_IMSAdminBaseSink_W> pThis = this;
  228. _ASSERTE(m_dwNotifyCount==1);
  229. m_bConnected = TRUE;
  230. m_pLock->UnlockWrite();
  231. _ASSERTE(pThis);
  232. hrRes = m_pMetabaseHandle->GetInterfaceQI(IID_IConnectionPointContainer,(LPVOID *) &pCPC);
  233. if (SUCCEEDED(hrRes)) {
  234. hrRes = pCPC->FindConnectionPoint(IID_IMSAdminBaseSink_W,&pCP);
  235. MY_ASSERTE_RPC_HR(hrRes);
  236. if (SUCCEEDED(hrRes)) {
  237. hrRes = pCP->Advise(pThis,&m_dwCookie);
  238. _ASSERTE(SUCCEEDED(hrRes));
  239. }
  240. }
  241. } else {
  242. m_pLock->UnlockWrite();
  243. }
  244. return (S_OK);
  245. }
  246. HRESULT CChangeNotify::RemoveNotify(CSEOMetaDictionary *pNotify) {
  247. HRESULT hrRes;
  248. DWORD dwIdx;
  249. if (!pNotify) {
  250. return (E_POINTER);
  251. }
  252. if (!m_pMetabaseHandle) {
  253. return (S_OK);
  254. }
  255. hrRes = m_pLock->LockWrite(5000);
  256. if (!SUCCEEDED(hrRes)) {
  257. return (hrRes);
  258. }
  259. if (!m_apNotify) {
  260. m_pLock->UnlockWrite();
  261. return (S_FALSE);
  262. }
  263. for (dwIdx=0;dwIdx<m_dwNotifyCount;dwIdx++) {
  264. if (m_apNotify[dwIdx] == pNotify) {
  265. break;
  266. }
  267. }
  268. if (dwIdx == m_dwNotifyCount) {
  269. m_pLock->UnlockWrite();
  270. return (S_FALSE);
  271. }
  272. m_apNotify[dwIdx] = m_apNotify[m_dwNotifyCount-1];
  273. m_apNotify[m_dwNotifyCount-1] = NULL;
  274. m_dwNotifyCount--;
  275. if (!m_dwNotifyCount) {
  276. CComPtr<IConnectionPointContainer> pCPC;
  277. CComPtr<IConnectionPoint> pCP;
  278. DWORD dwCookie = m_dwCookie;
  279. _ASSERTE(m_bConnected);
  280. m_bConnected = FALSE;
  281. m_pLock->UnlockWrite();
  282. hrRes = m_pMetabaseHandle->GetInterfaceQI(IID_IConnectionPointContainer,(LPVOID *) &pCPC);
  283. MY_ASSERTE_RPC_HR(hrRes);
  284. if (SUCCEEDED(hrRes)) {
  285. hrRes = pCPC->FindConnectionPoint(IID_IMSAdminBaseSink_W,&pCP);
  286. MY_ASSERTE_RPC_HR(hrRes);
  287. if (SUCCEEDED(hrRes)) {
  288. hrRes = pCP->Unadvise(dwCookie);
  289. MY_ASSERTE_RPC_HR(hrRes);
  290. }
  291. }
  292. } else {
  293. m_pLock->UnlockWrite();
  294. }
  295. return (S_OK);
  296. }
  297. HRESULT STDMETHODCALLTYPE CChangeNotify::SinkNotify(DWORD dwMDNumElements, MD_CHANGE_OBJECT_W pcoChangeList[]) {
  298. HRESULT hrRes;
  299. CComPtr<IEventLock> pLock = m_pLock;
  300. CSEOMetaDictionary **apNotify;
  301. DWORD dwIdx;
  302. LPCWSTR *apszChange;
  303. _ASSERTE(dwMDNumElements&&pcoChangeList);
  304. if (!pcoChangeList) {
  305. return (E_POINTER);
  306. }
  307. if (!dwMDNumElements) {
  308. return (S_OK);
  309. }
  310. hrRes = pLock->LockRead(5000);
  311. if (!SUCCEEDED(hrRes)) {
  312. return (hrRes);
  313. }
  314. if (!m_apNotify || !m_dwNotifyCount) {
  315. pLock->UnlockRead();
  316. return (S_OK);
  317. }
  318. apNotify = (CSEOMetaDictionary **) _alloca(sizeof(CSEOMetaDictionary *)*(m_dwNotifyCount+1));
  319. if (!apNotify) {
  320. _ASSERTE(FALSE);
  321. pLock->UnlockRead();
  322. return (E_OUTOFMEMORY);
  323. }
  324. apszChange = (LPCWSTR *) _alloca(sizeof(LPWSTR)*(dwMDNumElements+1));
  325. if (!apszChange) {
  326. _ASSERTE(FALSE);
  327. pLock->UnlockRead();
  328. return (E_OUTOFMEMORY);
  329. }
  330. memcpy(apNotify,m_apNotify,sizeof(CSEOMetaDictionary *)*m_dwNotifyCount);
  331. apNotify[m_dwNotifyCount] = NULL;
  332. for (dwIdx=0;apNotify[dwIdx];dwIdx++) {
  333. apNotify[dwIdx]->GetControllingUnknown()->AddRef();
  334. }
  335. pLock->UnlockRead();
  336. pLock.Release();
  337. for (dwIdx=0;dwIdx<dwMDNumElements;dwIdx++) {
  338. apszChange[dwIdx] = pcoChangeList[dwIdx].pszMDPath;
  339. }
  340. apszChange[dwMDNumElements] = NULL;
  341. for (dwIdx=0;apNotify[dwIdx];dwIdx++) {
  342. hrRes = apNotify[dwIdx]->OnChange(apszChange);
  343. _ASSERTE(SUCCEEDED(hrRes));
  344. apNotify[dwIdx]->GetControllingUnknown()->Release();
  345. }
  346. return (S_OK);
  347. }
  348. HRESULT STDMETHODCALLTYPE CChangeNotify::ShutdownNotify(void) {
  349. // tbd
  350. return (S_OK);
  351. }
  352. /////////////////////////////////////////////////////////////////////////////
  353. LPCWSTR szSeparator = L"/";
  354. LPCOLESTR szSaveKey = OLESTR("MetabasePath");
  355. static CComObject<CChangeNotify> *g_pChangeNotify;
  356. HRESULT ResolveVariant(IEventPropertyBag *pBag, VARIANT *pvarPropDesired, CComVariant &varResult);
  357. // Static member variables
  358. CGlobalInterface<IMSAdminBaseW,&IID_IMSAdminBase_W> CSEOMetabase::m_MetabaseHandle;
  359. CGlobalInterface<IMSAdminBaseW,&IID_IMSAdminBase_W> CSEOMetabase::m_MetabaseChangeHandle;
  360. int CSEOMetabase::m_iCount = 0;
  361. HRESULT CSEOMetabase::InitializeMetabase() {
  362. EnterCriticalSection(&_Module.m_csWindowCreate);
  363. if (m_iCount++) {
  364. LeaveCriticalSection(&_Module.m_csWindowCreate);
  365. return S_OK; // Already initialized
  366. }
  367. m_MetabaseHandle.Init();
  368. m_MetabaseChangeHandle.Init();
  369. HRESULT hRes = m_MetabaseHandle.Load(CLSID_MSAdminBase_W);
  370. if (FAILED(hRes)) {
  371. MY_OUTPUT_DEBUG_STRING("CSEOMetabase::InitializeMetabase - m_MetabaseHandle.Load failed.\n")
  372. TerminateMetabase();
  373. LeaveCriticalSection(&_Module.m_csWindowCreate);
  374. return hRes;
  375. }
  376. hRes = m_MetabaseChangeHandle.Load(CLSID_MSAdminBase_W);
  377. if (FAILED(hRes)) {
  378. MY_OUTPUT_DEBUG_STRING("CSEOMetabase::InitializeMetabase - m_MetabaseChangeHandle.Load failed.\n")
  379. TerminateMetabase();
  380. LeaveCriticalSection(&_Module.m_csWindowCreate);
  381. return hRes;
  382. }
  383. hRes = CComObject<CChangeNotify>::CreateInstance(&g_pChangeNotify);
  384. if (!SUCCEEDED(hRes)) {
  385. MY_OUTPUT_DEBUG_STRING("CSEOMetabase::InitializeMetabase - CComObject<CChangeNotify>::CreateInstance failed.\n")
  386. TerminateMetabase();
  387. LeaveCriticalSection(&_Module.m_csWindowCreate);
  388. return (hRes);
  389. }
  390. g_pChangeNotify->GetControllingUnknown()->AddRef();
  391. hRes = g_pChangeNotify->Advise(&m_MetabaseChangeHandle);
  392. if (!SUCCEEDED(hRes)) {
  393. MY_OUTPUT_DEBUG_STRING("CSEOMetabase::InitializeMetabase - g_pChangeNotify->Advise failed.\n")
  394. TerminateMetabase();
  395. LeaveCriticalSection(&_Module.m_csWindowCreate);
  396. return (hRes);
  397. }
  398. LeaveCriticalSection(&_Module.m_csWindowCreate);
  399. return hRes;
  400. }
  401. HRESULT CSEOMetabase::TerminateMetabase()
  402. {
  403. EnterCriticalSection(&_Module.m_csWindowCreate);
  404. --m_iCount;
  405. if(m_iCount > 0) {
  406. LeaveCriticalSection(&_Module.m_csWindowCreate);
  407. return S_OK; // More copies still using it
  408. }
  409. if (g_pChangeNotify) {
  410. g_pChangeNotify->Unadvise();
  411. g_pChangeNotify->GetControllingUnknown()->Release();
  412. g_pChangeNotify = NULL;
  413. }
  414. if(m_MetabaseHandle) {
  415. m_MetabaseHandle.Term();
  416. }
  417. if(m_MetabaseChangeHandle) {
  418. m_MetabaseChangeHandle.Term();
  419. }
  420. LeaveCriticalSection(&_Module.m_csWindowCreate);
  421. return S_OK;
  422. }
  423. HRESULT CSEOMetabase::SetStatus(LockStatus ls, long lTimeout) {
  424. if (InitError == m_eStatus) {
  425. return (m_hrInitRes);
  426. }
  427. if(m_pmbDefer) {
  428. return m_pmbDefer->SetStatus(ls, lTimeout);
  429. }
  430. if(!m_MetabaseHandle) return E_FAIL;
  431. CComPtr<IMSAdminBaseW> piMetabase;
  432. HRESULT hRes = m_MetabaseHandle.GetInterface(&piMetabase);
  433. if (!SUCCEEDED(hRes)) {
  434. return (hRes);
  435. }
  436. // tbd: Do we need to count open requests, and wait for same number of close requests?
  437. if(m_eStatus == Error) return E_FAIL;
  438. if(m_eStatus == ls) return S_OK; // Already in desired state
  439. hRes = E_FAIL;
  440. if(m_eStatus == Closed) {
  441. if((ls == Read) || (ls == Write)) {
  442. DWORD dwAccess = ((ls == Write) ? METADATA_PERMISSION_WRITE|METADATA_PERMISSION_READ :
  443. METADATA_PERMISSION_READ);
  444. hRes = piMetabase->OpenKey(METADATA_MASTER_ROOT_HANDLE,
  445. m_pszPath, dwAccess, lTimeout, &m_mhHandle);
  446. // If it failed, and we're trying to write, try to create it
  447. if(FAILED(hRes) && (ls == Write)) {
  448. METADATA_HANDLE mhTemp;
  449. hRes = piMetabase->OpenKey(METADATA_MASTER_ROOT_HANDLE,
  450. NULL, dwAccess, lTimeout, &mhTemp);
  451. if(SUCCEEDED(hRes)) {
  452. piMetabase->AddKey(mhTemp, m_pszPath); // Create Path
  453. piMetabase->CloseKey(mhTemp); // Close the temp handle
  454. // And try one more time
  455. hRes = piMetabase->OpenKey(METADATA_MASTER_ROOT_HANDLE,
  456. m_pszPath, dwAccess, lTimeout, &m_mhHandle);
  457. }
  458. }
  459. if(SUCCEEDED(hRes)) {
  460. m_eStatus = ls;
  461. }
  462. } // Else unknown request
  463. } else if(ls == Closed) {
  464. // if(m_eStatus == Write) piMetabase->SaveData(); // I'm not sure if CloseKey() does this
  465. hRes = piMetabase->CloseKey(m_mhHandle);
  466. m_eStatus = Closed;
  467. m_mhHandle = METADATA_MASTER_ROOT_HANDLE;
  468. } else if ((ls == Read) && (m_eStatus == Write)) {
  469. hRes = S_FALSE;
  470. } // Else trying to change state while already opened
  471. return hRes;
  472. }
  473. // Opens the specified path and returns a new string to use as the path
  474. HRESULT CSEOMetabase::OpenPath(CSEOMetabaseLock &mbLocker, LPCWSTR pszPath,
  475. LPWSTR pszPathBuf, DWORD &dwId, LockStatus lsOpen) {
  476. HRESULT hRes = S_OK;
  477. if (InitError == m_hrInitRes) {
  478. return (m_hrInitRes);
  479. }
  480. if(m_pmbDefer) { // If we're defering
  481. hRes = mbLocker.SetStatus(lsOpen); // Open the master
  482. LPWSTR pszPathTmp = (LPWSTR) GetRelPath((LPWSTR) alloca(sizeof(*pszPath)*(GetPathLength() + 1)));
  483. ConcatinatePaths(pszPathBuf,pszPathTmp,pszPath);
  484. } else {
  485. hRes = mbLocker.SetStatus(lsOpen);
  486. if(pszPath) { // If there's something to copy
  487. wcscpy(pszPathBuf,pszPath);
  488. } else {
  489. pszPathBuf[0] = 0; // Treat null string like an empty string
  490. }
  491. }
  492. // Future: parse path for //# to indicate a specific entry for dwId
  493. dwId = 0;
  494. return hRes;
  495. }
  496. HRESULT CSEOMetabase::EnumKeys(LPCWSTR pszPath, DWORD dwNum, LPWSTR pszName) {
  497. if (InitError == m_eStatus) {
  498. return (m_hrInitRes);
  499. }
  500. if(Error == Status()) {
  501. return MD_ERROR_NOT_INITIALIZED; // or E_FAIL;
  502. }
  503. CComPtr<IMSAdminBaseW> piMetabase;
  504. HRESULT hRes = m_MetabaseHandle.GetInterface(&piMetabase);
  505. if (!SUCCEEDED(hRes)) {
  506. return (hRes);
  507. }
  508. CSEOMetabaseLock mbLocker(this);
  509. LPWSTR pszPathBuf = (LPWSTR) alloca(sizeof(*pszPathBuf)*(4 + GetPathLength() + SafeStrlen(pszPath)));
  510. DWORD dwDummyId = 0; // Not used in Enum
  511. hRes = OpenPath(mbLocker, pszPath, pszPathBuf, dwDummyId);
  512. if(FAILED(hRes)) return hRes;
  513. return piMetabase->EnumKeys(GetHandle(), pszPathBuf, pszName, dwNum);
  514. }
  515. HRESULT CSEOMetabase::GetData(LPCWSTR pszPath, DWORD &dwType, DWORD &dwLen, PBYTE pbData) {
  516. if (InitError == m_eStatus) {
  517. return (m_hrInitRes);
  518. }
  519. if(Error == Status()) {
  520. return MD_ERROR_NOT_INITIALIZED; // or E_FAIL;
  521. }
  522. CComPtr<IMSAdminBaseW> piMetabase;
  523. HRESULT hRes = m_MetabaseHandle.GetInterface(&piMetabase);
  524. if (!SUCCEEDED(hRes)) {
  525. return (hRes);
  526. }
  527. METADATA_RECORD mdrData;
  528. DWORD dwRequiredDataLen = 0;
  529. CSEOMetabaseLock mbLocker(this);
  530. LPWSTR pszPathBuf = (LPWSTR) alloca(sizeof(*pszPathBuf)*(4 + GetPathLength() + SafeStrlen(pszPath)));
  531. hRes = OpenPath(mbLocker, pszPath, pszPathBuf, mdrData.dwMDIdentifier);
  532. if(FAILED(hRes)) return hRes;
  533. // Initialize data
  534. mdrData.dwMDAttributes = METADATA_NO_ATTRIBUTES;
  535. mdrData.dwMDUserType = 0;
  536. mdrData.dwMDDataType = 0;
  537. mdrData.dwMDDataLen = dwLen;
  538. mdrData.pbMDData = (PBYTE) alloca(dwLen);
  539. mdrData.dwMDDataTag = 0;
  540. hRes = piMetabase->GetData(GetHandle(), pszPathBuf,
  541. &mdrData, &dwRequiredDataLen);
  542. // Set values for return
  543. dwType = mdrData.dwMDDataType;
  544. if(dwType == EXPANDSZ_METADATA) { // It needs environment string substitutions
  545. // Save the new size in mdrData.dwMDDataLen
  546. mdrData.dwMDDataLen = ExpandEnvironmentStringsW((LPCWSTR) mdrData.pbMDData, (LPWSTR) pbData, dwLen);
  547. dwType = STRING_METADATA; // Don't need to expand anymore
  548. if(!mdrData.dwMDDataLen && *pbData) hRes = E_FAIL;
  549. } else {
  550. memcpy(pbData, mdrData.pbMDData, min(dwLen, mdrData.dwMDDataLen));
  551. }
  552. // if(mdrData.dwMDDataTag) m_piMetabase->ReleaseReferenceData(mdrData.dwMDDataTag); - No longer needed
  553. dwLen = ((HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) == hRes) ? dwRequiredDataLen : mdrData.dwMDDataLen);
  554. switch (hRes) { // Translate return code
  555. case ERROR_PATH_NOT_FOUND:
  556. case MD_ERROR_DATA_NOT_FOUND:
  557. hRes = SEO_E_NOTPRESENT;
  558. break;
  559. case HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER):
  560. hRes = SEO_S_MOREDATA;
  561. break;
  562. case ERROR_SUCCESS:
  563. hRes = S_OK;
  564. break;
  565. }
  566. return hRes;
  567. }
  568. // Add path if it doesn't exist already
  569. HRESULT CSEOMetabase::AddKey(LPCWSTR pszPath) {
  570. if (InitError == m_eStatus) {
  571. return (m_hrInitRes);
  572. }
  573. CComPtr<IMSAdminBaseW> piMetabase;
  574. HRESULT hRes = m_MetabaseHandle.GetInterface(&piMetabase);
  575. if (!SUCCEEDED(hRes)) {
  576. return (hRes);
  577. }
  578. CSEOMetabaseLock mbLocker(this);
  579. LPWSTR pszPathBuf = (LPWSTR) alloca(sizeof(*pszPathBuf)*(4 + GetPathLength() + SafeStrlen(pszPath)));
  580. DWORD dwDummyId = 0; // Not needed for AddKey()
  581. hRes = OpenPath(mbLocker, pszPath, pszPathBuf, dwDummyId, Write);
  582. if(FAILED(hRes)) return hRes;
  583. if(Status() != Write) return E_FAIL; // Couldn't open for Writing
  584. hRes = piMetabase->AddKey(GetHandle(), pszPathBuf); // Make sure path exists
  585. if (hRes == HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS)) {
  586. hRes = S_OK;
  587. }
  588. return (hRes);
  589. }
  590. HRESULT CSEOMetabase::DeleteKey(LPCWSTR pszPath) {
  591. if (InitError == m_eStatus) {
  592. return (m_hrInitRes);
  593. }
  594. CComPtr<IMSAdminBaseW> piMetabase;
  595. HRESULT hRes = m_MetabaseHandle.GetInterface(&piMetabase);
  596. if (!SUCCEEDED(hRes)) {
  597. return (hRes);
  598. }
  599. CSEOMetabaseLock mbLocker(this);
  600. LPWSTR pszPathBuf = (LPWSTR) alloca(sizeof(*pszPathBuf)*(4 + GetPathLength() + SafeStrlen(pszPath)));
  601. DWORD dwDummyId = 0; // Not needed for DeleyeKey()
  602. hRes = OpenPath(mbLocker, pszPath, pszPathBuf, dwDummyId, Write);
  603. if(FAILED(hRes)) return hRes;
  604. if(Status() != Write) return E_FAIL; // Couldn't open for Writing
  605. hRes = piMetabase->DeleteKey(GetHandle(), pszPathBuf); // Make sure path does not exist
  606. if (hRes == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND)) {
  607. hRes = S_OK;
  608. }
  609. return (hRes);
  610. }
  611. HRESULT CSEOMetabase::SetData(LPCWSTR pszPath, DWORD dwType, DWORD dwLen, PBYTE pbData) {
  612. if (InitError == m_eStatus) {
  613. return (m_hrInitRes);
  614. }
  615. CComPtr<IMSAdminBaseW> piMetabase;
  616. HRESULT hRes = m_MetabaseHandle.GetInterface(&piMetabase);
  617. if (!SUCCEEDED(hRes)) {
  618. return (hRes);
  619. }
  620. METADATA_RECORD mdrData;
  621. DWORD dwRequiredDataLen = 0;
  622. CSEOMetabaseLock mbLocker(this);
  623. LPWSTR pszPathBuf = (LPWSTR) alloca(sizeof(*pszPathBuf)*(4 + GetPathLength() + SafeStrlen(pszPath)));
  624. hRes = OpenPath(mbLocker, pszPath, pszPathBuf, mdrData.dwMDIdentifier, Write);
  625. if(FAILED(hRes)) return hRes;
  626. if(Status() != Write) return E_FAIL; // Couldn't open for Writing
  627. // Initialize data
  628. mdrData.dwMDAttributes = 0;
  629. mdrData.dwMDUserType = 0;
  630. mdrData.dwMDDataType = dwType;
  631. mdrData.dwMDDataLen = dwLen;
  632. mdrData.pbMDData = pbData;
  633. mdrData.dwMDDataTag = 0;
  634. if(pbData) { // If it's a non-NULL pointer
  635. PBYTE pbTemp = (PBYTE) alloca(dwLen + 1); // Make sure string is null-terminated
  636. if((dwType == STRING_METADATA) && // If it's a string
  637. ((dwLen < 1) || pbData[dwLen - 1])) { // And it's not null-terminated
  638. memcpy(pbTemp, pbData, dwLen);
  639. pbTemp[dwLen] = 0; // Terminate new string
  640. ++dwLen; // Include null terminator in length
  641. mdrData.dwMDDataLen = dwLen; // New Length
  642. mdrData.pbMDData = pbTemp; // Point to new string
  643. }
  644. piMetabase->AddKey(GetHandle(), pszPathBuf); // Make sure path exists
  645. return piMetabase->SetData(GetHandle(), pszPathBuf, &mdrData);
  646. } else { // NULL pointer, so delete it
  647. // m_piMetabase->DeleteData(GetHandle(), pbPathBuf, 0, ALL_METADATA);
  648. return piMetabase->DeleteKey(GetHandle(), pszPathBuf);
  649. }
  650. }
  651. void CSEOMetabase::ConcatinatePaths(LPWSTR pszResult, LPCWSTR pszP1, LPCWSTR pszP2) {
  652. pszResult[0] = 0;
  653. if(pszP1 && *pszP1) {
  654. //if(szSeparator[0] != pszP1[0]) lstrcat(pszResult, szSeparator);
  655. wcscat(pszResult, pszP1);
  656. }
  657. if(pszP2) { // && *pszP2) {
  658. if(szSeparator[0] != pszResult[wcslen(pszResult) - 1]) wcscat(pszResult, szSeparator);
  659. if(!*pszP2) {
  660. wcscat(pszResult, szSeparator);
  661. } else {
  662. //lstrcat(pszResult, pszP2 + ((szSeparator[0] != pszP2[0]) ? 0 : lstrlen(szSeparator)));
  663. wcscat(pszResult, pszP2);
  664. }
  665. }
  666. //int iLast = lstrlen(pszResult) - 1;
  667. //if((iLast >= 0) && (szSeparator[0] == pszResult[iLast])) pszResult[iLast] = 0;
  668. }
  669. /////////////////////////////////////////////////////////////////////////////
  670. // CSEOMetaDictionaryEnum
  671. class CSEOMetaDictionaryEnum :
  672. public CComObjectRootEx<CComMultiThreadModelNoCS>,
  673. public IDispatchImpl<IEnumVARIANT, &IID_IEnumVARIANT, &LIBID_SEOLib>
  674. {
  675. public:
  676. HRESULT FinalConstruct();
  677. void FinalRelease();
  678. HRESULT STDMETHODCALLTYPE Next(DWORD, LPVARIANT, LPDWORD);
  679. HRESULT STDMETHODCALLTYPE Skip(DWORD);
  680. HRESULT STDMETHODCALLTYPE Reset(void);
  681. HRESULT STDMETHODCALLTYPE Clone(IEnumVARIANT **);
  682. // Not Exported
  683. HRESULT STDMETHODCALLTYPE Init(CSEOMetaDictionary *, DWORD dwIndex = 0);
  684. BEGIN_COM_MAP(CSEOMetaDictionaryEnum)
  685. COM_INTERFACE_ENTRY(IEnumVARIANT)
  686. END_COM_MAP()
  687. private: // Data members
  688. CSEOMetaDictionary *m_dictionary;
  689. DWORD m_dwIndex;
  690. };
  691. HRESULT CSEOMetaDictionaryEnum::FinalConstruct() {
  692. m_dictionary = NULL;
  693. m_dwIndex = 0;
  694. return S_OK;
  695. }
  696. void CSEOMetaDictionaryEnum::FinalRelease() {
  697. if(m_dictionary) m_dictionary->GetControllingUnknown()->Release();
  698. m_dictionary = NULL;
  699. }
  700. STDMETHODIMP CSEOMetaDictionaryEnum::Init(CSEOMetaDictionary *pDict, DWORD dwIndex) {
  701. if(m_dictionary) m_dictionary->GetControllingUnknown()->Release();
  702. m_dictionary = pDict;
  703. m_dwIndex = dwIndex;
  704. if(m_dictionary) {
  705. m_dictionary->GetControllingUnknown()->AddRef();
  706. }
  707. return S_OK;
  708. }
  709. STDMETHODIMP CSEOMetaDictionaryEnum::Next(DWORD dwCount, LPVARIANT varDest,
  710. LPDWORD pdwResultParam) {
  711. if(!m_dictionary) return E_FAIL; // Hasn't been properly initialized
  712. if(!varDest) return E_POINTER;
  713. WCHAR szName[METADATA_MAX_NAME_LEN];
  714. DWORD dwDummy = 0;
  715. LPDWORD pdwResult = (pdwResultParam ? pdwResultParam : &dwDummy);
  716. *pdwResult = 0; // Nothing done so far
  717. HRESULT hrRes = S_OK; // So far, so good
  718. while((S_OK == hrRes) && (*pdwResult < dwCount)) {
  719. // Must have succeeded to get here, so OK to overwrite hrRes
  720. hrRes = m_dictionary->m_mbHelper.EnumKeys(NULL, m_dwIndex, szName);
  721. if(SUCCEEDED(hrRes)) {
  722. CComVariant varResult(szName);
  723. VariantInit(&varDest[*pdwResult]);
  724. hrRes = varResult.Detach(&varDest[*pdwResult]);
  725. ++(*pdwResult); // Increment successful count for caller
  726. ++m_dwIndex; // Point to the next one
  727. }
  728. }
  729. if(HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hrRes) hrRes = S_FALSE;
  730. if(HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hrRes) hrRes = S_FALSE;
  731. return (FAILED(hrRes) ? hrRes : ((*pdwResult < dwCount) ? S_FALSE : hrRes));
  732. }
  733. STDMETHODIMP CSEOMetaDictionaryEnum::Skip(DWORD dwCount) {
  734. m_dwIndex += dwCount;
  735. return S_OK;
  736. }
  737. STDMETHODIMP CSEOMetaDictionaryEnum::Reset(void) {
  738. m_dwIndex = 0;
  739. return S_OK;
  740. }
  741. STDMETHODIMP CSEOMetaDictionaryEnum::Clone(IEnumVARIANT **ppunkResult) {
  742. // Based on Samples\ATL\circcoll\objects.cpp (see also ATL\beeper\beeper.*
  743. if (ppunkResult == NULL) return E_POINTER;
  744. *ppunkResult = NULL;
  745. CComObject<CSEOMetaDictionaryEnum> *p;
  746. HRESULT hrRes = CComObject<CSEOMetaDictionaryEnum>::CreateInstance(&p);
  747. if (!SUCCEEDED(hrRes)) return (hrRes);
  748. hrRes = p->Init(m_dictionary, m_dwIndex);
  749. if (SUCCEEDED(hrRes)) hrRes = p->QueryInterface(IID_IEnumVARIANT, (void**)ppunkResult);
  750. if (FAILED(hrRes)) delete p;
  751. return hrRes;
  752. }
  753. /////////////////////////////////////////////////////////////////////////////
  754. // CSEOMetaDictionary
  755. // The following macro may be inserted in a method to support
  756. // reading/writing from just that method if handle not already opened.
  757. // The object will take care of close the handle if needed, etc.
  758. #define METABASE_READ METABASE_HELPER(m_mbHelper, Read)
  759. #define METABASE_WRITE METABASE_HELPER(m_mbHelper, Write)
  760. HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::get_Item(
  761. /* [in] */ VARIANT __RPC_FAR *pvarName,
  762. /* [retval][out] */ VARIANT __RPC_FAR *pvarResult)
  763. {
  764. if(!pvarName || !pvarResult) return E_INVALIDARG;
  765. USES_CONVERSION; // Needed for W2A(), etc.
  766. CComVariant vNew;
  767. HRESULT hrRes = E_INVALIDARG;
  768. if(SUCCEEDED(vNew.ChangeType(VT_BSTR, pvarName))) {
  769. hrRes = GetVariantA(W2A(vNew.bstrVal), pvarResult);
  770. // Convert SEO_E_NOTPRESENT to VT_EMPTY
  771. if(SEO_E_NOTPRESENT == hrRes) {
  772. VariantClear(pvarResult);
  773. hrRes = S_OK;
  774. }
  775. }
  776. return hrRes;
  777. }
  778. HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::put_Item(
  779. /* [in] */ VARIANT __RPC_FAR *pvarName,
  780. /* [in] */ VARIANT __RPC_FAR *pvarValue)
  781. {
  782. if(!pvarName || !pvarValue) return E_INVALIDARG;
  783. USES_CONVERSION; // Needed for W2A(), etc.
  784. CComVariant vNew;
  785. if(SUCCEEDED(vNew.ChangeType(VT_BSTR, pvarName))) {
  786. return SetVariantA(W2A(vNew.bstrVal), pvarValue);
  787. } else {
  788. return E_INVALIDARG;
  789. }
  790. }
  791. HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::get__NewEnum(
  792. /* [retval][out] */ IUnknown __RPC_FAR *__RPC_FAR *ppunkResult)
  793. {
  794. // Based on Samples\ATL\circcoll\objects.cpp (see also ATL\beeper\beeper.*
  795. if (ppunkResult == NULL) return E_POINTER;
  796. *ppunkResult = NULL;
  797. CComObject<CSEOMetaDictionaryEnum> *p;
  798. HRESULT hrRes = CComObject<CSEOMetaDictionaryEnum>::CreateInstance(&p);
  799. if (!SUCCEEDED(hrRes)) return (hrRes);
  800. hrRes = p->Init(this);
  801. if (SUCCEEDED(hrRes)) hrRes = p->QueryInterface(IID_IEnumVARIANT, (void**)ppunkResult);
  802. if (FAILED(hrRes)) delete p;
  803. return hrRes;
  804. }
  805. HRESULT CSEOMetaDictionary::GetVariantW(LPCWSTR pszName, VARIANT __RPC_FAR *pvarResult, BOOL bCreate) {
  806. if(!pvarResult) return E_POINTER;
  807. if(!pszName) return E_POINTER;
  808. CComVariant varResult;
  809. HRESULT hRes = E_FAIL;
  810. VariantInit(pvarResult);
  811. if(*pszName && (szSeparator[0] != pszName[wcslen(pszName) - 1])) {
  812. DWORD dwType = 0;
  813. DWORD dwCount = METADATA_MAX_NAME_LEN; // Initial buffer size
  814. PBYTE pbBuf = NULL;
  815. hRes = SEO_S_MOREDATA;
  816. while(SEO_S_MOREDATA == hRes) {
  817. pbBuf = (PBYTE) alloca(dwCount);
  818. hRes = m_mbHelper.GetData(pszName, dwType, dwCount, pbBuf);
  819. }
  820. if(SUCCEEDED(hRes)) {
  821. if(DWORD_METADATA == dwType) varResult = *((long *) pbBuf);
  822. else varResult = (LPCWSTR) pbBuf;
  823. }
  824. }
  825. if(varResult.vt == VT_EMPTY) { // nothing found so far, so read as subkey
  826. if (!bCreate) {
  827. WCHAR szName[METADATA_MAX_NAME_LEN];
  828. hRes = m_mbHelper.EnumKeys(pszName,0,szName);
  829. if (hRes == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND)) {
  830. return (SEO_E_NOTPRESENT);
  831. }
  832. }
  833. CComPtr<IUnknown> pRef;
  834. hRes = GetInterfaceW(pszName, IID_ISEODictionary, &pRef);
  835. varResult = pRef;
  836. }
  837. if(SUCCEEDED(hRes)) hRes = varResult.Detach(pvarResult);
  838. return hRes;
  839. }
  840. HRESULT CSEOMetaDictionary::GetVariantA(LPCSTR pszName, VARIANT __RPC_FAR *pvarResult, BOOL bCreate) {
  841. if(!pvarResult) return E_INVALIDARG;
  842. USES_CONVERSION; // Needed for W2A(), etc.
  843. return GetVariantW(A2W(pszName),pvarResult,bCreate);
  844. }
  845. HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::GetVariantW(
  846. /* [in] */ LPCWSTR pszName,
  847. /* [retval][out] */ VARIANT __RPC_FAR *pvarResult)
  848. {
  849. return (GetVariantW(pszName,pvarResult,TRUE));
  850. }
  851. HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::GetVariantA(
  852. /* [in] */ LPCSTR pszName,
  853. /* [retval][out] */ VARIANT __RPC_FAR *pvarResult)
  854. {
  855. if(!pvarResult) return E_INVALIDARG;
  856. USES_CONVERSION; // Needed for W2A(), etc.
  857. return GetVariantW(A2W(pszName),pvarResult,TRUE);
  858. }
  859. HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::SetVariantW(
  860. /* [in] */ LPCWSTR pszName,
  861. /* [in] */ VARIANT __RPC_FAR *pvarValue)
  862. {
  863. if(!pvarValue) return E_POINTER;
  864. HRESULT hRes = S_OK;
  865. if(pvarValue->vt == VT_I4) {
  866. hRes = m_mbHelper.SetDWord(pszName, pvarValue->lVal);
  867. } else if((pvarValue->vt == VT_UNKNOWN) || (pvarValue->vt == VT_DISPATCH)) {
  868. CComQIPtr<ISEODictionary, &IID_ISEODictionary> piDict = pvarValue->punkVal;
  869. if(piDict) hRes = CopyDictionary(pszName, piDict);
  870. } else if(pvarValue->vt == VT_EMPTY) { // Delete it
  871. hRes = m_mbHelper.SetData(pszName, 0, 0, NULL);
  872. } else if(pvarValue->vt == VT_BSTR) { // It's a string
  873. hRes = m_mbHelper.SetString(pszName, pvarValue->bstrVal);
  874. } else { // Try to convert it to a string
  875. CComVariant pvarTemp = *pvarValue;
  876. hRes = pvarTemp.ChangeType(VT_BSTR);
  877. if(SUCCEEDED(hRes)) {
  878. hRes = m_mbHelper.SetString(pszName, pvarTemp.bstrVal);
  879. } // Else, return the ChangeType error
  880. }
  881. return hRes;
  882. }
  883. HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::SetVariantA(
  884. /* [in] */ LPCSTR pszName,
  885. /* [in] */ VARIANT __RPC_FAR *pvarValue)
  886. {
  887. if(!pvarValue) return E_POINTER;
  888. USES_CONVERSION; // Needed for W2A(), etc.
  889. return SetVariantW(A2W(pszName), pvarValue);
  890. }
  891. HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::GetStringW(
  892. /* [in] */ LPCWSTR pszName,
  893. /* [out][in] */ DWORD __RPC_FAR *pchCount,
  894. /* [retval][size_is][out] */ LPWSTR pszResult)
  895. {
  896. if(!pszResult) return E_POINTER;
  897. DWORD dwType = 0;
  898. DWORD dwCountTmp = sizeof(*pszResult) * (*pchCount);
  899. HRESULT hRes = m_mbHelper.GetData(pszName, dwType, dwCountTmp, (PBYTE) pszResult);
  900. *pchCount = dwCountTmp / sizeof(*pszResult);
  901. if(SUCCEEDED(hRes) && (DWORD_METADATA == dwType)) hRes = SEO_E_NOTPRESENT;
  902. return hRes;
  903. }
  904. HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::GetStringA(
  905. /* [in] */ LPCSTR pszName,
  906. /* [out][in] */ DWORD __RPC_FAR *pchCount,
  907. /* [retval][size_is][out] */ LPSTR pszResult)
  908. {
  909. if(!pszResult) return E_POINTER;
  910. USES_CONVERSION;
  911. DWORD dwType = 0;
  912. DWORD dwByteCount = *pchCount * sizeof(*pszResult);
  913. PBYTE pbBuf = (PBYTE) alloca(dwByteCount);
  914. HRESULT hRes = m_mbHelper.GetData(A2W(pszName), dwType, dwByteCount, pbBuf);
  915. if(SUCCEEDED(hRes) && (DWORD_METADATA == dwType)) hRes = SEO_E_NOTPRESENT;
  916. // Now, convert back to ANSI chars
  917. if(SUCCEEDED(hRes) && (BINARY_METADATA == dwType)) {
  918. memcpy(pszResult, pbBuf, dwByteCount);
  919. *pchCount = dwByteCount / sizeof(*pszResult);
  920. } else {
  921. ATLW2AHELPER(pszResult, (LPCWSTR) pbBuf, sizeof(*pszResult) * min(*pchCount, dwByteCount));
  922. *pchCount = dwByteCount; // Same number of characters
  923. }
  924. return hRes;
  925. }
  926. HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::SetStringW(
  927. /* [in] */ LPCWSTR pszName,
  928. /* [in] */ DWORD chCount,
  929. /* [size_is][in] */ LPCWSTR pszValue)
  930. {
  931. if(!pszValue) return E_POINTER;
  932. return m_mbHelper.SetData(pszName, STRING_METADATA,
  933. chCount*sizeof(*pszValue), (PBYTE) pszValue);
  934. }
  935. HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::SetStringA(
  936. /* [in] */ LPCSTR pszName,
  937. /* [in] */ DWORD chCount,
  938. /* [size_is][in] */ LPCSTR pszValue)
  939. {
  940. if(!pszValue) return E_POINTER;
  941. USES_CONVERSION;
  942. return m_mbHelper.SetData(A2W(pszName), STRING_METADATA,
  943. chCount, (PBYTE) A2W(pszValue));
  944. }
  945. HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::GetDWordW(
  946. /* [in] */ LPCWSTR pszName,
  947. /* [retval][out] */ DWORD __RPC_FAR *pdwResult)
  948. {
  949. if(!pdwResult) return E_POINTER;
  950. DWORD dwType = 0;
  951. DWORD dwCount = sizeof(DWORD);
  952. HRESULT hRes = m_mbHelper.GetData(pszName, dwType, dwCount, (PBYTE) pdwResult);
  953. if(SUCCEEDED(hRes) && (DWORD_METADATA != dwType)) hRes = SEO_E_NOTPRESENT;
  954. return hRes;
  955. }
  956. HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::GetDWordA(
  957. /* [in] */ LPCSTR pszName,
  958. /* [retval][out] */ DWORD __RPC_FAR *pdwResult)
  959. {
  960. USES_CONVERSION; // Needed for W2A(), etc.
  961. return GetDWordW(A2W(pszName), pdwResult);
  962. }
  963. HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::SetDWordW(
  964. /* [in] */ LPCWSTR pszName,
  965. /* [in] */ DWORD dwValue)
  966. {
  967. return m_mbHelper.SetDWord(pszName, dwValue);
  968. }
  969. HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::SetDWordA(
  970. /* [in] */ LPCSTR pszName,
  971. /* [in] */ DWORD dwValue)
  972. {
  973. USES_CONVERSION; // Needed for W2A(), etc.
  974. return m_mbHelper.SetDWord(A2W(pszName), dwValue);
  975. }
  976. HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::GetInterfaceW(
  977. /* [in] */ LPCWSTR pszName,
  978. /* [in] */ REFIID iidDesired,
  979. /* [retval][iid_is][out] */ IUnknown __RPC_FAR *__RPC_FAR *ppunkResult)
  980. {
  981. if(!ppunkResult) return E_POINTER;
  982. CComObject<CSEOMetaDictionary> *pKey;
  983. HRESULT hrRes = CComObject<CSEOMetaDictionary>::CreateInstance(&pKey);
  984. if (FAILED(hrRes)) return (hrRes);
  985. CComPtr<ISEODictionary> pAutomaticCleanup = pKey;
  986. hrRes = pKey->Init(m_mbHelper, pszName);
  987. if (SUCCEEDED(hrRes)) {
  988. hrRes = pKey->QueryInterface(iidDesired, (LPVOID *) ppunkResult);
  989. }
  990. return (hrRes);
  991. // tbd: return SEO_E_NOTPRESENT; // Didn't find it
  992. }
  993. HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::GetInterfaceA(
  994. /* [in] */ LPCSTR pszName,
  995. /* [in] */ REFIID iidDesired,
  996. /* [retval][iid_is][out] */ IUnknown __RPC_FAR *__RPC_FAR *ppunkResult)
  997. {
  998. USES_CONVERSION; // Needed for W2A(), etc.
  999. return GetInterfaceW(A2W(pszName), iidDesired, ppunkResult);
  1000. }
  1001. HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::SetInterfaceW(
  1002. /* [in] */ LPCWSTR pszName,
  1003. /* [in] */ IUnknown __RPC_FAR *punkValue)
  1004. {
  1005. CComQIPtr<ISEODictionary, &IID_ISEODictionary> piDict = punkValue;
  1006. return (piDict ? CopyDictionary(pszName, piDict) : E_INVALIDARG);
  1007. }
  1008. HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::SetInterfaceA(
  1009. /* [in] */ LPCSTR pszName,
  1010. /* [in] */ IUnknown __RPC_FAR *punkValue)
  1011. {
  1012. USES_CONVERSION; // Needed for W2A(), etc.
  1013. return SetInterfaceW(A2W(pszName), punkValue);
  1014. }
  1015. HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::GetClassID(/* [out] */ CLSID __RPC_FAR *pClassID) {
  1016. memcpy(pClassID, &CLSID_CSEOMetaDictionary, sizeof(CLSID));
  1017. _ASSERT(IsEqualCLSID(*pClassID, CLSID_CSEOMetaDictionary));
  1018. return S_OK;
  1019. }
  1020. HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::InitNew(void) {
  1021. return S_OK;
  1022. }
  1023. HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::Load(
  1024. /* [in] */ IPropertyBag __RPC_FAR *pPropBag,
  1025. /* [in] */ IErrorLog __RPC_FAR * /*pErrorLog*/) {
  1026. if(!pPropBag) return E_POINTER;
  1027. CComVariant varPath;
  1028. varPath.vt = VT_BSTR; // Request type from Read()
  1029. varPath.bstrVal = NULL;
  1030. HRESULT hRes = pPropBag->Read(szSaveKey, &varPath, NULL);
  1031. if(SUCCEEDED(hRes)) m_mbHelper.SetPath(varPath.bstrVal);
  1032. return hRes;
  1033. }
  1034. HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::Save(
  1035. /* [in] */ IPropertyBag __RPC_FAR *pPropBag,
  1036. /* [in] */ BOOL /*fClearDirty*/,
  1037. /* [in] */ BOOL /*fSaveAllProperties*/) {
  1038. if(!pPropBag) return E_POINTER;
  1039. LPWSTR pszBuf = (LPWSTR) alloca(sizeof(*pszBuf)*(m_mbHelper.GetPathLength() + 1)); // Temporary buffer to hold path
  1040. CComVariant varPath = m_mbHelper.GetPath(pszBuf);
  1041. return pPropBag->Write(szSaveKey, &varPath);
  1042. }
  1043. HRESULT CSEOMetaDictionary::FinalConstruct() {
  1044. HRESULT hrRes;
  1045. hrRes = CoCreateFreeThreadedMarshaler(GetControllingUnknown(),&m_pUnkMarshaler.p);
  1046. _ASSERTE(!SUCCEEDED(hrRes)||m_pUnkMarshaler);
  1047. return (SUCCEEDED(hrRes)?S_OK:hrRes);
  1048. }
  1049. void CSEOMetaDictionary::FinalRelease() {
  1050. m_pUnkMarshaler.Release();
  1051. }
  1052. HRESULT CSEOMetaDictionary::OnChange(LPCWSTR *apszPath) {
  1053. HRESULT hrRes;
  1054. CComPtr<IConnectionPoint> pCP;
  1055. CComPtr<IEnumConnections> pEnum;
  1056. CONNECTDATA cd;
  1057. BOOL bDoNotify = FALSE;
  1058. CSEOConnectionPointImpl<CSEOMetaDictionary,&IID_IEventNotifyBindingChange> *pCPImpl;
  1059. LPWSTR pszThisPath = NULL;
  1060. DWORD dwThisPathLen;
  1061. if (!apszPath) {
  1062. _ASSERTE(FALSE);
  1063. return (E_POINTER);
  1064. }
  1065. if (!apszPath[0]) {
  1066. _ASSERTE(FALSE);
  1067. return (S_OK);
  1068. }
  1069. Lock();
  1070. pCPImpl = (CSEOConnectionPointImpl<CSEOMetaDictionary,&IID_IEventNotifyBindingChange> *) this;
  1071. if (!pCPImpl->GetCount()) {
  1072. Unlock();
  1073. return (S_OK);
  1074. }
  1075. Unlock();
  1076. hrRes = FindConnectionPoint(IID_IEventNotifyBindingChange,&pCP);
  1077. if (!SUCCEEDED(hrRes)) {
  1078. _ASSERTE(FALSE);
  1079. return (S_OK);
  1080. }
  1081. hrRes = pCP->EnumConnections(&pEnum);
  1082. if (!SUCCEEDED(hrRes)) {
  1083. _ASSERTE(FALSE);
  1084. return (S_OK);
  1085. }
  1086. while (1) {
  1087. hrRes = pEnum->Next(1,&cd,NULL);
  1088. if (!SUCCEEDED(hrRes)) {
  1089. _ASSERTE(FALSE);
  1090. return (S_OK);
  1091. }
  1092. if (hrRes == S_FALSE) {
  1093. break;
  1094. }
  1095. if (!bDoNotify) {
  1096. if (!pszThisPath) {
  1097. pszThisPath = (LPWSTR) _alloca(sizeof(*pszThisPath)*(m_mbHelper.GetPathLength()+1));
  1098. if (!pszThisPath) {
  1099. _ASSERTE(FALSE);
  1100. return (S_OK);
  1101. }
  1102. m_mbHelper.GetPath(pszThisPath);
  1103. dwThisPathLen = wcslen(pszThisPath);
  1104. if (dwThisPathLen && (pszThisPath[dwThisPathLen-1] == szSeparator[0])) {
  1105. dwThisPathLen--;
  1106. }
  1107. if (dwThisPathLen && (pszThisPath[0] == szSeparator[0])) {
  1108. pszThisPath++;
  1109. dwThisPathLen--;
  1110. }
  1111. }
  1112. for (DWORD dwIdx=0;apszPath[dwIdx];dwIdx++) {
  1113. DWORD dwPathLen;
  1114. LPCWSTR pszPath;
  1115. pszPath = apszPath[dwIdx];
  1116. dwPathLen = wcslen(pszPath);
  1117. if (dwPathLen && (pszPath[dwPathLen-1] == szSeparator[0])) {
  1118. dwPathLen--;
  1119. }
  1120. if (dwPathLen && (pszPath[0] == szSeparator[0])) {
  1121. pszPath++;
  1122. dwPathLen--;
  1123. }
  1124. if ((dwThisPathLen > dwPathLen) ||
  1125. (memicmp(pszThisPath,pszPath,dwThisPathLen*sizeof(pszPath[0])) != 0)) {
  1126. continue;
  1127. }
  1128. if (!dwThisPathLen ||
  1129. (dwThisPathLen == dwPathLen) ||
  1130. (pszPath[dwThisPathLen] == szSeparator[0])) {
  1131. bDoNotify = TRUE;
  1132. break;
  1133. }
  1134. }
  1135. }
  1136. if (bDoNotify) {
  1137. hrRes = ((IEventNotifyBindingChange *) cd.pUnk)->OnChange();
  1138. _ASSERTE(SUCCEEDED(hrRes));
  1139. }
  1140. cd.pUnk->Release();
  1141. if (!bDoNotify) {
  1142. break;
  1143. }
  1144. }
  1145. return (S_OK);
  1146. }
  1147. void CSEOMetaDictionary::AdviseCalled(IUnknown *pUnk, DWORD *pdwCookie, REFIID riid, DWORD dwCount) {
  1148. HRESULT hrRes;
  1149. if (dwCount == 1) {
  1150. if (!g_pChangeNotify) {
  1151. return;
  1152. }
  1153. hrRes = g_pChangeNotify->AddNotify(this);
  1154. _ASSERTE(SUCCEEDED(hrRes));
  1155. }
  1156. }
  1157. void CSEOMetaDictionary::UnadviseCalled(DWORD dwCookie, REFIID riid, DWORD dwCount) {
  1158. HRESULT hrRes;
  1159. if (dwCount == 0) {
  1160. if (!g_pChangeNotify) {
  1161. return;
  1162. }
  1163. hrRes = g_pChangeNotify->RemoveNotify(this);
  1164. _ASSERTE(SUCCEEDED(hrRes));
  1165. }
  1166. }
  1167. HRESULT CSEOMetaDictionary::CopyDictionary(LPCWSTR pszName, ISEODictionary *pBag) {
  1168. if(!pBag) return S_OK; // Nothing to copy
  1169. // If not already open for writing, make it so
  1170. CSEOMetabaseLock mbLocker(&m_mbHelper);
  1171. if(::Write != m_mbHelper.Status()) {
  1172. mbLocker.SetStatus(::Write);
  1173. }
  1174. CComObject<CSEOMetaDictionary> *pKey; // New Subkey
  1175. HRESULT hrRes = CComObject<CSEOMetaDictionary>::CreateInstance(&pKey);
  1176. if (FAILED(hrRes)) return (hrRes);
  1177. CComPtr<ISEODictionary> pAutomaticCleanup = pKey;
  1178. hrRes = m_mbHelper.DeleteKey(pszName); // Empty Metabase path
  1179. if (FAILED(hrRes)) return (hrRes);
  1180. hrRes = m_mbHelper.AddKey(pszName); // Create Metabase path
  1181. if (FAILED(hrRes)) return (hrRes);
  1182. hrRes = pKey->InitShare(m_mbHelper, pszName);
  1183. if (FAILED(hrRes)) return (hrRes);
  1184. CComPtr<IUnknown> piUnk;
  1185. HRESULT hr = pBag->get__NewEnum(&piUnk);
  1186. if(FAILED(hr) || !piUnk) return hr;
  1187. CComQIPtr<IEnumVARIANT, &IID_IEnumVARIANT> pieEnum = piUnk;
  1188. piUnk.Release(); // Done with piUnk - use pieEnum now
  1189. if(!pieEnum) return E_INVALIDARG;
  1190. CComVariant varName; // Hold the current property name
  1191. // Read in and copy all of the properties
  1192. while(S_OK == pieEnum->Next(1, &varName, NULL)) {
  1193. CComVariant varDest; // Hold the current result
  1194. if(SUCCEEDED(pBag->get_Item(&varName, &varDest))) {
  1195. varName.ChangeType(VT_BSTR); // Try to get a string
  1196. pKey->SetVariantW(varName.bstrVal, &varDest);
  1197. }
  1198. }
  1199. return S_OK;
  1200. }
  1201. HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::Read(LPCOLESTR pszPropName, VARIANT *pVar, IErrorLog *pErrorLog) {
  1202. HRESULT hrRes;
  1203. VARTYPE vtType;
  1204. if (!pszPropName || !pVar) {
  1205. return (E_POINTER);
  1206. }
  1207. vtType = pVar->vt;
  1208. // VariantClear(pVar);
  1209. hrRes = GetVariantW(pszPropName,pVar);
  1210. if (SUCCEEDED(hrRes) && (vtType != VT_EMPTY)) {
  1211. hrRes = VariantChangeType(pVar,pVar,0,vtType);
  1212. }
  1213. if (!SUCCEEDED(hrRes)) {
  1214. VariantClear(pVar);
  1215. }
  1216. return (hrRes);
  1217. }
  1218. HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::Write(LPCOLESTR pszPropName, VARIANT *pVar) {
  1219. return (SetVariantW(pszPropName,pVar));
  1220. }
  1221. HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::Item(VARIANT *pvarPropDesired, VARIANT *pvarPropValue) {
  1222. if (!pvarPropValue) {
  1223. return (E_POINTER);
  1224. }
  1225. // VariantClear(pvarPropValue); // Might have been initialized by caller (?)
  1226. CComVariant varResult;
  1227. HRESULT hrRes = ResolveVariant(this, pvarPropDesired, varResult);
  1228. if (S_OK != hrRes) { // Don't just check for SUCCEEDED in case it's S_FALSE
  1229. return (hrRes);
  1230. }
  1231. hrRes = GetVariantW(varResult.bstrVal,pvarPropValue,FALSE);
  1232. if (hrRes == SEO_E_NOTPRESENT) {
  1233. return (S_FALSE);
  1234. }
  1235. #if 0
  1236. if (!SUCCEEDED(hrRes)) {
  1237. return (hrRes);
  1238. }
  1239. {
  1240. CComVariant varTmp(*pvarPropValue);
  1241. HRESULT hrRes; // hide outer hrRes
  1242. CComQIPtr<ISEODictionary,&IID_ISEODictionary> pdictTmp;
  1243. CComPtr<IUnknown> punkEnum;
  1244. CComQIPtr<IEnumVARIANT,&IID_IEnumVARIANT> pEnum;
  1245. hrRes = varTmp.ChangeType(VT_UNKNOWN); // Make it an Unknown (if possible)
  1246. if (SUCCEEDED(hrRes)) {
  1247. pdictTmp = varTmp.punkVal;
  1248. if (!pdictTmp) {
  1249. VariantClear(pvarPropValue);
  1250. return (E_NOINTERFACE);
  1251. }
  1252. hrRes = pdictTmp->get__NewEnum(&punkEnum); // Get it's Enum object
  1253. if (!SUCCEEDED(hrRes)) {
  1254. VariantClear(pvarPropValue);
  1255. return (hrRes);
  1256. }
  1257. pEnum = punkEnum;
  1258. if (!pEnum) {
  1259. VariantClear(pvarPropValue);
  1260. return (E_NOINTERFACE);
  1261. }
  1262. varTmp.Clear();
  1263. hrRes = pEnum->Next(1,&varTmp,NULL); // Ask Enum for first object
  1264. if (hrRes == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND)) {
  1265. VariantClear(pvarPropValue);
  1266. return (S_FALSE);
  1267. }
  1268. if (!SUCCEEDED(hrRes)) {
  1269. VariantClear(pvarPropValue);
  1270. return (hrRes);
  1271. }
  1272. }
  1273. }
  1274. #endif
  1275. if (SUCCEEDED(hrRes)) {
  1276. VariantChangeType(pvarPropValue,pvarPropValue,0,VT_DISPATCH);
  1277. _ASSERTE(pvarPropValue->vt!=VT_UNKNOWN);
  1278. }
  1279. #if 0
  1280. {
  1281. HRESULT hrRes;
  1282. CComVariant varTmp(*pvarPropValue);
  1283. hrRes = varTmp.ChangeType(VT_UNKNOWN);
  1284. if (SUCCEEDED(hrRes)) {
  1285. hrRes = varTmp.ChangeType(VT_DISPATCH);
  1286. _ASSERTE(SUCCEEDED(hrRes));
  1287. if (SUCCEEDED(hrRes)) {
  1288. VariantClear(pvarPropValue);
  1289. pvarPropValue->vt = VT_DISPATCH;
  1290. pvarPropValue->pdispVal = varTmp.pdispVal;
  1291. pvarPropValue->pdispVal->AddRef();
  1292. }
  1293. hrRes = varTmp.ChangeType(VT_UNKNOWN);
  1294. _ASSERTE(SUCCEEDED(hrRes));
  1295. }
  1296. }
  1297. #endif
  1298. return (hrRes);
  1299. }
  1300. HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::Name(long lPropIndex, BSTR *pbstrPropName) {
  1301. if(!pbstrPropName) {
  1302. return E_POINTER;
  1303. }
  1304. if (lPropIndex < 1) {
  1305. return (S_FALSE);
  1306. }
  1307. *pbstrPropName = NULL;
  1308. WCHAR szName[METADATA_MAX_NAME_LEN];
  1309. HRESULT hrRes = m_mbHelper.EnumKeys(NULL, lPropIndex - 1, szName);
  1310. if(SUCCEEDED(hrRes)) {
  1311. *pbstrPropName = SysAllocString(szName);
  1312. if(!*pbstrPropName) hrRes = E_OUTOFMEMORY;
  1313. }
  1314. if(HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hrRes) hrRes = S_FALSE;
  1315. return hrRes;
  1316. }
  1317. HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::Add(BSTR pszPropName, VARIANT *pvarPropValue) {
  1318. return (SetVariantW(pszPropName,pvarPropValue));
  1319. }
  1320. HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::Remove(VARIANT *pvarPropDesired) {
  1321. CComVariant varCopy;
  1322. HRESULT hrRes = ResolveVariant(this, pvarPropDesired, varCopy);
  1323. if (S_OK != hrRes) { // Don't just check for SUCCEEDED in case it's S_FALSE
  1324. return (hrRes);
  1325. }
  1326. hrRes = m_mbHelper.SetData(varCopy.bstrVal, 0, 0, NULL);
  1327. if (hrRes == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND)) {
  1328. return (S_FALSE);
  1329. }
  1330. return (hrRes);
  1331. }
  1332. HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::get_Count(long *plCount) {
  1333. if(!plCount) return E_POINTER;
  1334. *plCount = 0; // Nothing done so far
  1335. WCHAR szName[METADATA_MAX_NAME_LEN];
  1336. HRESULT hrRes = S_OK; // So far, so good
  1337. while(S_OK == hrRes) {
  1338. // Must have succeeded to get here, so OK to overwrite hrRes
  1339. hrRes = m_mbHelper.EnumKeys(NULL, *plCount, szName);
  1340. if(SUCCEEDED(hrRes)) {
  1341. ++(*plCount); // Increment successful count for caller
  1342. }
  1343. }
  1344. if(HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hrRes) hrRes = S_OK;
  1345. return hrRes;
  1346. }
  1347. /* Just use get__NewEnum from ISEODictionary
  1348. HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::get__NewEnum(IUnknown **ppUnkEnum) {
  1349. return (E_NOTIMPL);
  1350. } */
  1351. HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::LockRead(int iTimeoutMS) {
  1352. HRESULT hrRes;
  1353. hrRes = m_mbHelper.SetStatus(::Read,iTimeoutMS);
  1354. if (!SUCCEEDED(hrRes)) {
  1355. if (hrRes == HRESULT_FROM_WIN32(ERROR_PATH_BUSY)) {
  1356. return (EVENTS_E_TIMEOUT);
  1357. }
  1358. return (hrRes);
  1359. }
  1360. return (S_OK);
  1361. }
  1362. HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::UnlockRead() {
  1363. HRESULT hrRes;
  1364. hrRes = m_mbHelper.SetStatus(::Closed);
  1365. if (!SUCCEEDED(hrRes)) {
  1366. return (hrRes);
  1367. }
  1368. return (S_OK);
  1369. }
  1370. HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::LockWrite(int iTimeoutMS) {
  1371. HRESULT hrRes;
  1372. hrRes = m_mbHelper.SetStatus(::Write,iTimeoutMS);
  1373. if (!SUCCEEDED(hrRes)) {
  1374. if (hrRes == HRESULT_FROM_WIN32(ERROR_PATH_BUSY)) {
  1375. return (EVENTS_E_TIMEOUT);
  1376. }
  1377. return (hrRes);
  1378. }
  1379. return (S_OK);
  1380. }
  1381. HRESULT STDMETHODCALLTYPE CSEOMetaDictionary::UnlockWrite() {
  1382. HRESULT hrRes;
  1383. hrRes = m_mbHelper.SetStatus(::Closed);
  1384. if (!SUCCEEDED(hrRes)) {
  1385. return (hrRes);
  1386. }
  1387. return (S_OK);
  1388. }