Source code of Windows XP (NT5)
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.

1729 lines
39 KiB

  1. /*===================================================================
  2. Microsoft Denali
  3. Microsoft Confidential.
  4. Copyright 1997 Microsoft Corporation. All Rights Reserved.
  5. Component: MetaUtil object
  6. File: KeyCol.cpp
  7. Owner: t-BrianM
  8. This file contains implementation of the key collections.
  9. ===================================================================*/
  10. #include "stdafx.h"
  11. #include "MetaUtil.h"
  12. #include "MUtilObj.h"
  13. #include "keycol.h"
  14. /*------------------------------------------------------------------
  15. * C F l a t K e y C o l l e c t i o n
  16. */
  17. /*===================================================================
  18. CFlatKeyCollection::CFlatKeyCollection
  19. Constructor
  20. Parameters:
  21. None
  22. Returns:
  23. Nothing
  24. ===================================================================*/
  25. CFlatKeyCollection::CFlatKeyCollection() : m_tszBaseKey(NULL)
  26. {
  27. }
  28. /*===================================================================
  29. CFlatKeyCollection::Init
  30. Constructor
  31. Parameters:
  32. pIMeta ATL Smart pointer to the metabase admin base object
  33. tszBaseKey Name of key to enumerate from
  34. Returns:
  35. E_OUTOFMEMORY if allocation fails
  36. S_OK on success
  37. ===================================================================*/
  38. HRESULT CFlatKeyCollection::Init(const CComPtr<IMSAdminBase> &pIMeta, LPCTSTR tszBaseKey)
  39. {
  40. ASSERT(pIMeta.p != NULL);
  41. ASSERT_NULL_OR_STRING(tszBaseKey);
  42. m_pIMeta = pIMeta;
  43. // Copy tszBaseKey to m_tszBaseKey
  44. if (tszBaseKey == NULL) {
  45. // BaseKey is root
  46. m_tszBaseKey = NULL;
  47. }
  48. else {
  49. // Allocate and copy the passed string to the member string
  50. m_tszBaseKey = new TCHAR[_tcslen(tszBaseKey) + 1];
  51. if (m_tszBaseKey == NULL) {
  52. return ::ReportError(E_OUTOFMEMORY);
  53. }
  54. _tcscpy(m_tszBaseKey, tszBaseKey);
  55. CannonizeKey(m_tszBaseKey);
  56. }
  57. return S_OK;
  58. }
  59. /*===================================================================
  60. CFlatKeyCollection::~CFlatKeyCollection
  61. Destructor
  62. Parameters:
  63. None
  64. Returns:
  65. Nothing
  66. ===================================================================*/
  67. CFlatKeyCollection::~CFlatKeyCollection()
  68. {
  69. if (m_tszBaseKey != NULL)
  70. delete m_tszBaseKey;
  71. }
  72. /*===================================================================
  73. CFlatKeyCollection::InterfaceSupportsErrorInfo
  74. Standard ATL implementation
  75. ===================================================================*/
  76. STDMETHODIMP CFlatKeyCollection::InterfaceSupportsErrorInfo(REFIID riid)
  77. {
  78. static const IID* arr[] =
  79. {
  80. &IID_IKeyCollection,
  81. };
  82. for (int i=0;i<sizeof(arr)/sizeof(arr[0]);i++)
  83. {
  84. if (InlineIsEqualGUID(*arr[i],riid))
  85. return S_OK;
  86. }
  87. return S_FALSE;
  88. }
  89. /*===================================================================
  90. CFlatKeyCollection::get_Count
  91. Get method for Count property. Counts the number of subkeys
  92. Parameters:
  93. plReturn [out, retval] Value to return to client.
  94. Returns:
  95. E_INVALIDARG if plReturn == NULL
  96. S_OK on success
  97. Notes:
  98. Actually counts all of the subkeys. Do not call in a loop!
  99. ===================================================================*/
  100. STDMETHODIMP CFlatKeyCollection::get_Count(long * plReturn)
  101. {
  102. TRACE0("MetaUtil: CFlatKeyCollection::get_Count\n");
  103. ASSERT_NULL_OR_POINTER(plReturn, long);
  104. if (plReturn == NULL) {
  105. return ::ReportError(E_INVALIDARG);
  106. }
  107. USES_CONVERSION;
  108. HRESULT hr;
  109. *plReturn = 0;
  110. // Count the subkeys
  111. wchar_t wszSubKey[ADMINDATA_MAX_NAME_LEN];
  112. int iIndex;
  113. iIndex = 0;
  114. for (;;) { // FOREVER, will return from loop
  115. hr = m_pIMeta->EnumKeys(METADATA_MASTER_ROOT_HANDLE,
  116. T2W(m_tszBaseKey),
  117. wszSubKey,
  118. iIndex);
  119. if (FAILED(hr)) {
  120. if (HRESULT_CODE(hr) == ERROR_NO_MORE_ITEMS) {
  121. // Ran out of items, return the number we counted
  122. *plReturn = iIndex;
  123. return S_OK;
  124. }
  125. else {
  126. return ::ReportError(hr);
  127. }
  128. }
  129. iIndex++;
  130. }
  131. }
  132. /*===================================================================
  133. CFlatKeyCollection::get_Item
  134. Get method for Item property. Returns a key given its index.
  135. Parameters:
  136. lIndex [in] 1 based index of the key to get
  137. pbstrRetKey [out, retval] Retrived key
  138. Returns:
  139. E_INVALIDARG if pbstrRetKey == NULL or lIndex <= 0
  140. S_OK on success
  141. ===================================================================*/
  142. STDMETHODIMP CFlatKeyCollection::get_Item(long lIndex, BSTR *pbstrRetKey)
  143. {
  144. TRACE0("MetaUtil: CFlatKeyCollection::get_Item\n");
  145. ASSERT_NULL_OR_POINTER(pbstrRetKey, BSTR);
  146. if ((pbstrRetKey == NULL) || (lIndex <= 0)) {
  147. return ::ReportError(E_INVALIDARG);
  148. }
  149. *pbstrRetKey = NULL;
  150. USES_CONVERSION;
  151. HRESULT hr;
  152. wchar_t wszSubKey[ADMINDATA_MAX_NAME_LEN];
  153. hr = m_pIMeta->EnumKeys(METADATA_MASTER_ROOT_HANDLE,
  154. T2W(m_tszBaseKey),
  155. wszSubKey,
  156. lIndex - 1);
  157. if (FAILED(hr)) {
  158. return ::ReportError(hr);
  159. }
  160. *pbstrRetKey = W2BSTR(wszSubKey);
  161. return S_OK;
  162. }
  163. /*===================================================================
  164. CFlatKeyCollection::get__NewEnum
  165. Get method for _NewEnum property. Returns an enumeration object for
  166. the subkeys.
  167. Parameters:
  168. ppIReturn [out, retval] Interface for the enumberation object
  169. Returns:
  170. E_OUTOFMEMORY if allocation fails.
  171. E_INVALIDARG if ppIReturn == NULL
  172. S_OK on success
  173. ===================================================================*/
  174. STDMETHODIMP CFlatKeyCollection::get__NewEnum(LPUNKNOWN * ppIReturn)
  175. {
  176. TRACE0("MetaUtil: CFlatKeyCollection::get__NewEnum\n");
  177. ASSERT_NULL_OR_POINTER(ppIReturn, LPUNKNOWN);
  178. if (ppIReturn == NULL) {
  179. return ::ReportError(E_INVALIDARG);
  180. }
  181. HRESULT hr;
  182. // Create the flat key enumeration
  183. CComObject<CFlatKeyEnum> *pObj = NULL;
  184. ATLTRY(pObj = new CComObject<CFlatKeyEnum>);
  185. if (pObj == NULL) {
  186. return ::ReportError(E_OUTOFMEMORY);
  187. }
  188. hr = pObj->Init(m_pIMeta, m_tszBaseKey, 0);
  189. if (FAILED(hr)) {
  190. return ::ReportError(hr);
  191. }
  192. // Set the interface to IUnknown
  193. hr = pObj->QueryInterface(IID_IUnknown, (void **) ppIReturn);
  194. if (FAILED(hr)) {
  195. return ::ReportError(hr);
  196. }
  197. ASSERT(*ppIReturn != NULL);
  198. return S_OK;
  199. }
  200. /*===================================================================
  201. CFlatKeyCollection::Add
  202. Adds a key to the metabase relative to the collection's base key
  203. Parameters:
  204. bstrRelKey [in] Relative key to add
  205. Returns:
  206. E_INVALIDARG if bstrRelKey == NULL
  207. S_OK on success
  208. ===================================================================*/
  209. STDMETHODIMP CFlatKeyCollection::Add(BSTR bstrRelKey)
  210. {
  211. TRACE0("MetaUtil: CFlatKeyCollection::Add\n");
  212. ASSERT_NULL_OR_POINTER(bstrRelKey, OLECHAR);
  213. if (bstrRelKey == NULL) {
  214. return ::ReportError(E_INVALIDARG);
  215. }
  216. // Build the full key
  217. USES_CONVERSION;
  218. TCHAR tszFullKey[ADMINDATA_MAX_NAME_LEN];
  219. if (m_tszBaseKey == NULL) {
  220. _tcscpy(tszFullKey, OLE2T(bstrRelKey));
  221. }
  222. else {
  223. _tcscpy(tszFullKey, m_tszBaseKey);
  224. _tcscat(tszFullKey, _T("/"));
  225. _tcscat(tszFullKey, OLE2T(bstrRelKey));
  226. }
  227. CannonizeKey(tszFullKey);
  228. return ::CreateKey(m_pIMeta, tszFullKey);
  229. }
  230. /*===================================================================
  231. CFlatKeyCollection::Remove
  232. Removes a key from the metabase relative to the collection's base key
  233. Parameters:
  234. bstrRelKey [in] Relative key to remove
  235. Returns:
  236. E_INVALIDARG if bstrRelKey == NULL
  237. S_OK on success
  238. ===================================================================*/
  239. STDMETHODIMP CFlatKeyCollection::Remove(BSTR bstrRelKey)
  240. {
  241. TRACE0("MetaUtil: CFlatKeyCollection::Remove\n");
  242. ASSERT_NULL_OR_POINTER(bstrRelKey, OLECHAR);
  243. if (bstrRelKey == NULL) {
  244. return ::ReportError(E_INVALIDARG);
  245. }
  246. // Build the full key
  247. USES_CONVERSION;
  248. TCHAR tszFullKey[ADMINDATA_MAX_NAME_LEN];
  249. if (m_tszBaseKey == NULL) {
  250. _tcscpy(tszFullKey, OLE2T(bstrRelKey));
  251. }
  252. else {
  253. _tcscpy(tszFullKey, m_tszBaseKey);
  254. _tcscat(tszFullKey, _T("/"));
  255. _tcscat(tszFullKey, OLE2T(bstrRelKey));
  256. }
  257. CannonizeKey(tszFullKey);
  258. return ::DeleteKey(m_pIMeta, tszFullKey);
  259. }
  260. /*------------------------------------------------------------------
  261. * C F l a t K e y E n u m
  262. */
  263. /*===================================================================
  264. CFlatKeyEnum::CFlatKeyEnum
  265. Constructor
  266. Parameters:
  267. None
  268. Returns:
  269. Nothing
  270. ===================================================================*/
  271. CFlatKeyEnum::CFlatKeyEnum() : m_tszBaseKey(NULL),
  272. m_iIndex(0)
  273. {
  274. }
  275. /*===================================================================
  276. CFlatKeyEnum::Init
  277. Constructor
  278. Parameters:
  279. pIMeta ATL Smart pointer to the metabase
  280. tszBaseKey Name of key to enumerate from
  281. iIndex Index of next element in enumeration
  282. Returns:
  283. E_OUTOFMEMORY if allocation fails
  284. S_OK on success
  285. ===================================================================*/
  286. HRESULT CFlatKeyEnum::Init(const CComPtr<IMSAdminBase> &pIMeta, LPCTSTR tszBaseKey, int iIndex)
  287. {
  288. ASSERT(pIMeta.p != NULL);
  289. ASSERT_NULL_OR_STRING(tszBaseKey);
  290. ASSERT(iIndex >= 0);
  291. m_pIMeta = pIMeta;
  292. // Copy tszBaseKey to m_tszBaseKey
  293. if (tszBaseKey == NULL) {
  294. // BaseKey is root
  295. m_tszBaseKey = NULL;
  296. }
  297. else {
  298. // Allocate and copy the passed string to the member string
  299. m_tszBaseKey = new TCHAR[_tcslen(tszBaseKey) + 1];
  300. if (m_tszBaseKey == NULL) {
  301. return ::ReportError(E_OUTOFMEMORY);
  302. }
  303. _tcscpy(m_tszBaseKey, tszBaseKey);
  304. CannonizeKey(m_tszBaseKey);
  305. }
  306. m_iIndex = iIndex;
  307. return S_OK;
  308. }
  309. /*===================================================================
  310. CFlatKeyEnum::~CFlatKeyEnum
  311. Destructor
  312. Parameters:
  313. None
  314. Returns:
  315. Nothing
  316. ===================================================================*/
  317. CFlatKeyEnum::~CFlatKeyEnum()
  318. {
  319. if (m_tszBaseKey != NULL) {
  320. delete m_tszBaseKey;
  321. }
  322. }
  323. /*===================================================================
  324. CFlatKeyEnum::Next
  325. Gets the next n items from the enumberation.
  326. Parameters:
  327. ulNumToGet [in] Number of elements to get
  328. rgvarDest [out] Array to put them in
  329. pulNumGot [out] If not NULL, number of elements rgvarDest got
  330. Returns:
  331. E_INVALIDARG if rgvarDest == NULL
  332. S_OK on success
  333. ===================================================================*/
  334. STDMETHODIMP CFlatKeyEnum::Next(unsigned long ulNumToGet,
  335. VARIANT FAR* rgvarDest,
  336. unsigned long FAR* pulNumGot)
  337. {
  338. TRACE0("MetaUtil: CFlatKeyEnum::Next\n");
  339. ASSERT_NULL_OR_POINTER(pulNumGot, unsigned long);
  340. // Make sure the array is big enough and we can write to it
  341. ASSERT((rgvarDest == NULL) || IsValidAddress(rgvarDest, ulNumToGet * sizeof(VARIANT), TRUE));
  342. if (rgvarDest == NULL) {
  343. return ::ReportError(E_INVALIDARG);
  344. }
  345. USES_CONVERSION;
  346. HRESULT hr;
  347. wchar_t wszSubKey[ADMINDATA_MAX_NAME_LEN];
  348. unsigned int uiDestIndex;
  349. // Clear the output array
  350. for(uiDestIndex = 0; uiDestIndex < ulNumToGet; uiDestIndex++) {
  351. VariantInit(&(rgvarDest[uiDestIndex]));
  352. }
  353. // For each subkey to get
  354. uiDestIndex = 0;
  355. while (uiDestIndex < ulNumToGet) {
  356. // Get a subkey
  357. hr = m_pIMeta->EnumKeys(METADATA_MASTER_ROOT_HANDLE,
  358. T2W(m_tszBaseKey),
  359. wszSubKey,
  360. m_iIndex);
  361. if (FAILED(hr)) {
  362. if (HRESULT_CODE(hr) == ERROR_NO_MORE_ITEMS) {
  363. if (pulNumGot != NULL) {
  364. *pulNumGot = uiDestIndex;
  365. }
  366. return S_FALSE;
  367. }
  368. else {
  369. return ::ReportError(hr);
  370. }
  371. }
  372. // Output the subkey
  373. rgvarDest[uiDestIndex].vt = VT_BSTR;
  374. rgvarDest[uiDestIndex].bstrVal = W2BSTR(wszSubKey);
  375. // Setup next iteration
  376. m_iIndex++;
  377. uiDestIndex++;
  378. }
  379. if (pulNumGot != NULL) {
  380. *pulNumGot = uiDestIndex;
  381. }
  382. return S_OK;
  383. }
  384. /*===================================================================
  385. CFlatKeyEnum::Skip
  386. Skips the next n items in an enumeration
  387. Parameters:
  388. ulNumToSkip [in] Number of elements to skip
  389. Returns:
  390. S_OK always
  391. ===================================================================*/
  392. STDMETHODIMP CFlatKeyEnum::Skip(unsigned long ulNumToSkip)
  393. {
  394. TRACE0("MetaUtil: CFlatKeyEnum::Skip\n");
  395. m_iIndex += ulNumToSkip;
  396. return S_OK;
  397. }
  398. /*===================================================================
  399. CFlatKeyEnum::Reset
  400. Rests the enumeration to the first item
  401. Parameters:
  402. None
  403. Returns:
  404. S_OK always
  405. ===================================================================*/
  406. STDMETHODIMP CFlatKeyEnum::Reset()
  407. {
  408. TRACE0("MetaUtil: CFlatKeyEnum::Reset\n");
  409. m_iIndex = 0;
  410. return S_OK;
  411. }
  412. /*===================================================================
  413. CFlatKeyEnum::Clone
  414. Gets an interface pointer to a copy of the enumeration at its
  415. current state.
  416. Parameters:
  417. ppIReturn [out] Pointer to interface for copy
  418. Returns:
  419. E_OUTOFMEMORY if allocation fails.
  420. E_INVALIDARG if ppIReturn == NULL
  421. S_OK on success
  422. ===================================================================*/
  423. STDMETHODIMP CFlatKeyEnum::Clone(IEnumVARIANT FAR* FAR* ppIReturn)
  424. {
  425. TRACE0("MetaUtil: CFlatKeyEnum::Clone\n");
  426. ASSERT_NULL_OR_POINTER(ppIReturn, LPUNKNOWN);
  427. if (ppIReturn == NULL) {
  428. return ::ReportError(E_INVALIDARG);
  429. }
  430. HRESULT hr;
  431. // Create a copy of the enumeration
  432. CComObject<CFlatKeyEnum> *pObj = NULL;
  433. ATLTRY(pObj = new CComObject<CFlatKeyEnum>);
  434. if (pObj == NULL) {
  435. return ::ReportError(E_OUTOFMEMORY);
  436. }
  437. hr = pObj->Init(m_pIMeta, m_tszBaseKey, m_iIndex);
  438. if (FAILED(hr)) {
  439. return ::ReportError(hr);
  440. }
  441. // Set the interface to IEnumVARIANT
  442. hr = pObj->QueryInterface(IID_IEnumVARIANT, (void **) ppIReturn);
  443. if (FAILED(hr)) {
  444. return ::ReportError(hr);
  445. }
  446. ASSERT(*ppIReturn != NULL);
  447. return S_OK;
  448. }
  449. /*------------------------------------------------------------------
  450. * C K e y S t a c k N o d e
  451. */
  452. /*===================================================================
  453. CKeyStackNode::Init
  454. Constructor
  455. Parameters:
  456. tszRelKey Relative key for the enumeration level, NULL for root
  457. iIndex 0-based index for the next element
  458. Returns:
  459. E_OUTOFMEMORY if allocation fails.
  460. E_INVALIDARG if iIndex < 0
  461. S_OK on success
  462. ===================================================================*/
  463. HRESULT CKeyStackNode::Init(LPCTSTR tszRelKey, int iIndex)
  464. {
  465. ASSERT_NULL_OR_STRING(tszRelKey);
  466. ASSERT(iIndex >= 0);
  467. // Copy the relative key string
  468. if (tszRelKey == NULL) {
  469. // RelKey is empty
  470. m_tszRelKey = NULL;
  471. }
  472. else {
  473. // Allocate and copy the passed string to the member string
  474. m_tszRelKey = new TCHAR[_tcslen(tszRelKey) + 1];
  475. if (m_tszRelKey == NULL) {
  476. return E_OUTOFMEMORY;
  477. }
  478. _tcscpy(m_tszRelKey, tszRelKey);
  479. }
  480. m_iIndex = iIndex;
  481. return S_OK;
  482. }
  483. /*===================================================================
  484. CKeyStackNode::~CKeyStackNode
  485. Destructor
  486. Parameters:
  487. None
  488. Returns:
  489. Nothing
  490. ===================================================================*/
  491. CKeyStackNode::~CKeyStackNode()
  492. {
  493. if (m_tszRelKey != NULL) {
  494. delete m_tszRelKey;
  495. }
  496. }
  497. /*===================================================================
  498. CKeyStackNode::Clone
  499. Copies the node, except for the next pointer, which is NULL.
  500. Parameters:
  501. None
  502. Returns:
  503. NULL on failure
  504. Pointer to copy of node on success
  505. ===================================================================*/
  506. CKeyStackNode *CKeyStackNode::Clone()
  507. {
  508. HRESULT hr;
  509. CKeyStackNode *pCRet;
  510. pCRet = new CKeyStackNode();
  511. if (pCRet == NULL) {
  512. return NULL;
  513. }
  514. hr = pCRet->Init(m_tszRelKey, m_iIndex);
  515. if (FAILED(hr)) {
  516. delete pCRet;
  517. return NULL;
  518. }
  519. return pCRet;
  520. }
  521. /*------------------------------------------------------------------
  522. * C K e y S t a c k
  523. */
  524. /*===================================================================
  525. CKeyStack::~CKeyStack
  526. Destructor
  527. Parameters:
  528. None
  529. Returns:
  530. Nothing
  531. ===================================================================*/
  532. CKeyStack::~CKeyStack()
  533. {
  534. // Delete the remaining nodes
  535. CKeyStackNode *pCDelete;
  536. while(m_pCTop != NULL) {
  537. ASSERT_POINTER(m_pCTop, CKeyStackNode);
  538. pCDelete = m_pCTop;
  539. m_pCTop = m_pCTop->m_pCNext;
  540. delete pCDelete;
  541. }
  542. }
  543. /*===================================================================
  544. CKeyStack::Push
  545. Pushes a CKeyStackNode onto the stack
  546. Parameters:
  547. pNew Pointer to CKeyStackNode to push on the stack
  548. Returns:
  549. Nothing, never fails
  550. Notes:
  551. CKeyStack "owns" the memory pointed to by pNew after call.
  552. CKeyStack or a later caller will delete it when done with it.
  553. ===================================================================*/
  554. void CKeyStack::Push(CKeyStackNode *pCNew)
  555. {
  556. ASSERT_POINTER(pCNew, CKeyStackNode);
  557. pCNew->m_pCNext = m_pCTop;
  558. m_pCTop = pCNew;
  559. }
  560. /*===================================================================
  561. CKeyStack::Pop
  562. Pops a CKeyStackNode from the stack
  563. Parameters:
  564. None
  565. Returns:
  566. Pointer to the top element or NULL if the stack is empty
  567. Notes:
  568. Caller "owns" the memory pointed to by pNew after call.
  569. Caller is expected to delete it when it is done with it.
  570. ===================================================================*/
  571. CKeyStackNode *CKeyStack::Pop()
  572. {
  573. CKeyStackNode *pCRet;
  574. pCRet = m_pCTop;
  575. if (m_pCTop != NULL) {
  576. m_pCTop = m_pCTop->m_pCNext;
  577. ASSERT_NULL_OR_POINTER(m_pCTop, CKeyStackNode);
  578. }
  579. return pCRet;
  580. }
  581. /*===================================================================
  582. CKeyStack::Clone
  583. Copies the stack, including all of the nodes.
  584. Parameters:
  585. Sheep
  586. Returns:
  587. NULL on failure
  588. Pointer to copy of stack on success
  589. ===================================================================*/
  590. CKeyStack *CKeyStack::Clone()
  591. {
  592. CKeyStack *pCRet;
  593. // Build the container
  594. pCRet = new CKeyStack();
  595. if (pCRet == NULL) {
  596. return NULL;
  597. }
  598. // Copy the nodes
  599. CKeyStackNode *pCSource;
  600. CKeyStackNode **ppCDest;
  601. pCSource = m_pCTop;
  602. ppCDest = &(pCRet->m_pCTop);
  603. while(pCSource != NULL) {
  604. ASSERT_POINTER(pCSource, CKeyStackNode);
  605. *ppCDest = pCSource->Clone();
  606. if ((*ppCDest) == NULL) {
  607. delete pCRet;
  608. return NULL;
  609. }
  610. ppCDest = &((*ppCDest)->m_pCNext);
  611. pCSource = pCSource->m_pCNext;
  612. }
  613. *ppCDest = NULL;
  614. return pCRet;
  615. }
  616. /*------------------------------------------------------------------
  617. * C D e e p K e y C o l l e c t i o n
  618. */
  619. /*===================================================================
  620. CDeepKeyCollection::CDeepKeyCollection
  621. Constructor
  622. Parameters:
  623. None
  624. Returns:
  625. Nothing
  626. ===================================================================*/
  627. CDeepKeyCollection::CDeepKeyCollection() : m_tszBaseKey(NULL)
  628. {
  629. }
  630. /*===================================================================
  631. CDeepKeyCollection::Init
  632. Constructor
  633. Parameters:
  634. pIMeta ATL Smart pointer to the metabase
  635. tszBaseKey Name of key to enumerate from
  636. Returns:
  637. E_OUTOFMEMORY if allocation fails
  638. S_OK on success
  639. ===================================================================*/
  640. HRESULT CDeepKeyCollection::Init(const CComPtr<IMSAdminBase> &pIMeta, LPCTSTR tszBaseKey)
  641. {
  642. ASSERT(pIMeta.p != NULL);
  643. ASSERT_NULL_OR_STRING(tszBaseKey);
  644. m_pIMeta = pIMeta;
  645. // Copy tszBaseKey to m_tszBaseKey
  646. if (tszBaseKey == NULL) {
  647. // BaseKey is root
  648. m_tszBaseKey = NULL;
  649. }
  650. else {
  651. // Allocate and copy the passed string to the member string
  652. m_tszBaseKey = new TCHAR[_tcslen(tszBaseKey) + 1];
  653. if (m_tszBaseKey == NULL) {
  654. return ::ReportError(E_OUTOFMEMORY);
  655. }
  656. _tcscpy(m_tszBaseKey, tszBaseKey);
  657. CannonizeKey(m_tszBaseKey);
  658. }
  659. return S_OK;
  660. }
  661. /*===================================================================
  662. CDeepKeyCollection::~CDeepKeyCollection
  663. Destructor
  664. Parameters:
  665. None
  666. Returns:
  667. Nothing
  668. ===================================================================*/
  669. CDeepKeyCollection::~CDeepKeyCollection()
  670. {
  671. if (m_tszBaseKey != NULL)
  672. delete m_tszBaseKey;
  673. }
  674. /*===================================================================
  675. CDeepKeyCollection::InterfaceSupportsErrorInfo
  676. Standard ATL implementation
  677. ===================================================================*/
  678. STDMETHODIMP CDeepKeyCollection::InterfaceSupportsErrorInfo(REFIID riid)
  679. {
  680. static const IID* arr[] =
  681. {
  682. &IID_IKeyCollection,
  683. };
  684. for (int i=0;i<sizeof(arr)/sizeof(arr[0]);i++)
  685. {
  686. if (InlineIsEqualGUID(*arr[i],riid))
  687. return S_OK;
  688. }
  689. return S_FALSE;
  690. }
  691. /*===================================================================
  692. CDeepKeyCollection::get_Count
  693. Get method for Count property. Counts the number of subkeys
  694. Parameters:
  695. plReturn [out, retval] Value to return to client.
  696. Returns:
  697. E_INVALIDARG if pVal == NULL
  698. S_OK on success
  699. Notes:
  700. Actually counts all of the subkeys recursivly. Very slow, do
  701. not put in a loop!
  702. ===================================================================*/
  703. STDMETHODIMP CDeepKeyCollection::get_Count(long * pVal)
  704. {
  705. TRACE0("MetaUtil: CDeepKeyCollection::get_Count\n");
  706. ASSERT_NULL_OR_POINTER(pVal, long);
  707. if (pVal == NULL) {
  708. return ::ReportError(E_INVALIDARG);
  709. }
  710. HRESULT hr;
  711. hr = CountKeys(m_tszBaseKey, pVal);
  712. return hr;
  713. }
  714. /*===================================================================
  715. CDeepKeyCollection::get_Item
  716. Get method for Item property. Returns a key given its index.
  717. Parameters:
  718. lIndex [in] 1 based index of the key to get
  719. pbstrRetKey [out, retval] Interface for the enumberation object
  720. Returns:
  721. E_INVALIDARG if lIndex <= 0 or pbstrRetKey == NULL
  722. ERROR_NO_MORE_ITEMS if index is > count
  723. S_OK on success
  724. Notes:
  725. This method is slow. Deep enumerations are much faster. Might
  726. be able to do some hacking with a stack object and cached location
  727. to speed up sequential calls.
  728. ===================================================================*/
  729. STDMETHODIMP CDeepKeyCollection::get_Item(long lIndex, BSTR *pbstrRetKey)
  730. {
  731. TRACE0("MetaUtil: CDeepKeyCollection::get_Item\n");
  732. ASSERT_NULL_OR_POINTER(pbstrRetKey, BSTR);
  733. if ((lIndex <= 0) || (pbstrRetKey == NULL)) {
  734. return ::ReportError(E_INVALIDARG);
  735. }
  736. HRESULT hr;
  737. TCHAR tszRetKey[ADMINDATA_MAX_NAME_LEN];
  738. long lCurIndex;
  739. lCurIndex = 1;
  740. tszRetKey[0] = _T('\0');
  741. hr = IndexItem(NULL, lIndex, &lCurIndex, tszRetKey);
  742. if (hr == S_FALSE) {
  743. // Ran out of items before we found it
  744. return ::ReportError(ERROR_NO_MORE_ITEMS);
  745. }
  746. else if (hr == S_OK) {
  747. // Found it
  748. *pbstrRetKey = T2BSTR(tszRetKey);
  749. }
  750. else {
  751. return ::ReportError(hr);
  752. }
  753. return hr;
  754. }
  755. /*===================================================================
  756. CDeepKeyCollection::get__NewEnum
  757. Get method for _NewEnum property. Returns an enumeration object for
  758. the subkeys.
  759. Parameters:
  760. ppIReturn [out, retval] Interface for the enumberation object
  761. Returns:
  762. E_INVALIDARG if ppIReturn == NULL
  763. S_OK on success
  764. ===================================================================*/
  765. STDMETHODIMP CDeepKeyCollection::get__NewEnum(LPUNKNOWN * ppIReturn)
  766. {
  767. TRACE0("MetaUtil: CDeepKeyCollection::get__NewEnum\n");
  768. ASSERT_NULL_OR_POINTER(ppIReturn, LPUNKNOWN);
  769. if (ppIReturn == NULL) {
  770. return ::ReportError(E_INVALIDARG);
  771. }
  772. HRESULT hr;
  773. // Create the deep key enumeration
  774. CComObject<CDeepKeyEnum> *pObj = NULL;
  775. ATLTRY(pObj = new CComObject<CDeepKeyEnum>);
  776. if (pObj == NULL) {
  777. return ::ReportError(E_OUTOFMEMORY);
  778. }
  779. hr = pObj->Init(m_pIMeta, m_tszBaseKey, NULL);
  780. if (FAILED(hr)) {
  781. return ::ReportError(hr);
  782. }
  783. // Set the interface to IUnknown
  784. hr = pObj->QueryInterface(IID_IUnknown, (void **) ppIReturn);
  785. if (FAILED(hr)) {
  786. return ::ReportError(hr);
  787. }
  788. ASSERT(*ppIReturn != NULL);
  789. return S_OK;
  790. }
  791. /*===================================================================
  792. CDeepKeyCollection::Add
  793. Adds a key to the metabase relative to the collection's base key
  794. Parameters:
  795. bstrRelKey [in] Relative key to add
  796. Returns:
  797. E_INVALIDARG if bstrRelKey == NULL
  798. S_OK on success
  799. ===================================================================*/
  800. STDMETHODIMP CDeepKeyCollection::Add(BSTR bstrRelKey)
  801. {
  802. TRACE0("MetaUtil: CDeepKeyCollection::Add\n");
  803. ASSERT_NULL_OR_POINTER(bstrRelKey, OLECHAR);
  804. if (bstrRelKey == NULL) {
  805. return ::ReportError(E_INVALIDARG);
  806. }
  807. // Build the full key
  808. USES_CONVERSION;
  809. TCHAR tszFullKey[ADMINDATA_MAX_NAME_LEN];
  810. if (m_tszBaseKey == NULL) {
  811. _tcscpy(tszFullKey, OLE2T(bstrRelKey));
  812. }
  813. else {
  814. _tcscpy(tszFullKey, m_tszBaseKey);
  815. _tcscat(tszFullKey, _T("/"));
  816. _tcscat(tszFullKey, OLE2T(bstrRelKey));
  817. }
  818. CannonizeKey(tszFullKey);
  819. return ::CreateKey(m_pIMeta, tszFullKey);
  820. }
  821. /*===================================================================
  822. CDeepKeyCollection::Remove
  823. Removes a key from the metabase relative to the collection's base key
  824. Parameters:
  825. bstrRelKey [in] Relative key to remove
  826. Returns:
  827. E_INVALIDARG if bstrRelKey == NULL
  828. S_OK on success
  829. ===================================================================*/
  830. STDMETHODIMP CDeepKeyCollection::Remove(BSTR bstrRelKey)
  831. {
  832. TRACE0("MetaUtil: CDeepKeyCollection::Remove\n");
  833. ASSERT_NULL_OR_POINTER(bstrRelKey, OLECHAR);
  834. if (bstrRelKey == NULL) {
  835. return ::ReportError(E_INVALIDARG);
  836. }
  837. // Build the full key
  838. USES_CONVERSION;
  839. TCHAR tszFullKey[ADMINDATA_MAX_NAME_LEN];
  840. if (m_tszBaseKey == NULL) {
  841. _tcscpy(tszFullKey, OLE2T(bstrRelKey));
  842. }
  843. else {
  844. _tcscpy(tszFullKey, m_tszBaseKey);
  845. _tcscat(tszFullKey, _T("/"));
  846. _tcscat(tszFullKey, OLE2T(bstrRelKey));
  847. }
  848. CannonizeKey(tszFullKey);
  849. return ::DeleteKey(m_pIMeta, tszFullKey);
  850. }
  851. /*===================================================================
  852. CDeepKeyCollection::CountKeys
  853. Private, recursive method for counting keys
  854. Parameters:
  855. tszBaseKey [in] Key to begin counting with (but not to count)
  856. NULL can represent the root key.
  857. plNumKeys [out] Number of keys counter, not including the base
  858. Returns:
  859. S_OK on success
  860. ===================================================================*/
  861. HRESULT CDeepKeyCollection::CountKeys(LPTSTR tszBaseKey, long *plNumKeys)
  862. {
  863. ASSERT_NULL_OR_STRING(tszBaseKey);
  864. ASSERT_POINTER(plNumKeys, long);
  865. *plNumKeys = 0;
  866. USES_CONVERSION;
  867. HRESULT hr;
  868. wchar_t wszSubKey[ADMINDATA_MAX_NAME_LEN];
  869. wchar_t wszFullSubKey[ADMINDATA_MAX_NAME_LEN];
  870. int iIndex;
  871. iIndex = 0;
  872. for (;;) { // FOREVER, will return from loop
  873. hr = m_pIMeta->EnumKeys(METADATA_MASTER_ROOT_HANDLE,
  874. T2W(tszBaseKey),
  875. wszSubKey,
  876. iIndex);
  877. if (FAILED(hr)) {
  878. if ((HRESULT_CODE(hr) == ERROR_NO_MORE_ITEMS) ||
  879. (HRESULT_CODE(hr) == ERROR_PATH_NOT_FOUND)) {
  880. // Ran out of items, break
  881. return S_OK;
  882. }
  883. else {
  884. return ::ReportError(hr);
  885. }
  886. }
  887. else { // SUCCEEDED(hr)
  888. // Build the full subkey
  889. if ((tszBaseKey == NULL) ||
  890. (tszBaseKey[0] == _T('\0')) ) {
  891. wcscpy(wszFullSubKey, wszSubKey);
  892. }
  893. else {
  894. wcscpy(wszFullSubKey, T2W(tszBaseKey));
  895. wcscat(wszFullSubKey, L"/");
  896. wcscat(wszFullSubKey, wszSubKey);
  897. }
  898. // Count this key
  899. (*plNumKeys)++;
  900. // Count the subkeys
  901. long lNumSubKeys;
  902. hr = CountKeys(W2T(wszFullSubKey), &lNumSubKeys);
  903. if (FAILED(hr)) {
  904. return hr;
  905. }
  906. (*plNumKeys) += lNumSubKeys;
  907. }
  908. iIndex++;
  909. }
  910. }
  911. /*===================================================================
  912. CDeepKeyCollection::IndexItem
  913. Private, recursive method for indexing keys
  914. Parameters:
  915. tszRelKey Relative key to index from
  916. lDestIndex Destination index
  917. plCurIndex Current (working) index
  918. tszRet Result from search
  919. Returns:
  920. S_OK if the destination index was reached
  921. S_FALSE if the destination index was not reached
  922. ===================================================================*/
  923. HRESULT CDeepKeyCollection::IndexItem(LPTSTR tszRelKey, long lDestIndex, long *plCurIndex, LPTSTR tszRet)
  924. {
  925. ASSERT_NULL_OR_STRING(tszRelKey);
  926. ASSERT_POINTER(plCurIndex, long);
  927. ASSERT_STRING(tszRet);
  928. USES_CONVERSION;
  929. HRESULT hr;
  930. wchar_t wszSubKey[ADMINDATA_MAX_NAME_LEN];
  931. wchar_t wszRelSubKey[ADMINDATA_MAX_NAME_LEN];
  932. int iIndex;
  933. // Open the base key
  934. METADATA_HANDLE hMDBaseKey;
  935. hr = m_pIMeta->OpenKey(METADATA_MASTER_ROOT_HANDLE,
  936. T2W(m_tszBaseKey),
  937. METADATA_PERMISSION_READ,
  938. MUTIL_OPEN_KEY_TIMEOUT,
  939. &hMDBaseKey);
  940. if (FAILED(hr)) {
  941. return ::ReportError(hr);
  942. }
  943. iIndex = 0;
  944. for (;;) { // FOREVER, will return from loop
  945. hr = m_pIMeta->EnumKeys(hMDBaseKey,
  946. T2W(tszRelKey),
  947. wszSubKey,
  948. iIndex);
  949. if (FAILED(hr)) {
  950. m_pIMeta->CloseKey(hMDBaseKey);
  951. if ((HRESULT_CODE(hr) == ERROR_NO_MORE_ITEMS) ||
  952. (HRESULT_CODE(hr) == ERROR_PATH_NOT_FOUND)) {
  953. // Ran out of items, break
  954. return S_FALSE;
  955. }
  956. else {
  957. return ::ReportError(hr);
  958. }
  959. }
  960. else {
  961. // Build the full subkey
  962. if ((tszRelKey == NULL) ||
  963. (tszRelKey[0] == _T('\0')) ) {
  964. wcscpy(wszRelSubKey, wszSubKey);
  965. }
  966. else {
  967. wcscpy(wszRelSubKey, T2W(tszRelKey));
  968. wcscat(wszRelSubKey, L"/");
  969. wcscat(wszRelSubKey, wszSubKey);
  970. }
  971. // Is this the destination?
  972. if ((*plCurIndex) == lDestIndex) {
  973. //Found it, copy it to the return buffer
  974. _tcscpy(tszRet, W2T(wszRelSubKey));
  975. m_pIMeta->CloseKey(hMDBaseKey);
  976. return S_OK;
  977. }
  978. // Count this key
  979. (*plCurIndex)++;
  980. // Check the subkeys
  981. hr = IndexItem(W2T(wszRelSubKey), lDestIndex, plCurIndex, tszRet);
  982. if (hr == S_OK) {
  983. //Found it
  984. m_pIMeta->CloseKey(hMDBaseKey);
  985. return S_OK;
  986. }
  987. else if (FAILED(hr)) {
  988. m_pIMeta->CloseKey(hMDBaseKey);
  989. return hr;
  990. }
  991. }
  992. iIndex++;
  993. }
  994. // Close the base key
  995. m_pIMeta->CloseKey(hMDBaseKey);
  996. return S_OK;
  997. }
  998. /*------------------------------------------------------------------
  999. * C D e e p K e y E n u m
  1000. */
  1001. /*===================================================================
  1002. CDeepKeyEnum::CDeepKeyEnum
  1003. Constructor
  1004. Parameters:
  1005. None
  1006. Returns:
  1007. Nothing
  1008. ===================================================================*/
  1009. CDeepKeyEnum::CDeepKeyEnum() : m_tszBaseKey(NULL),
  1010. m_pCKeyStack(NULL)
  1011. {
  1012. }
  1013. /*===================================================================
  1014. CDeepKeyEnum::Init
  1015. Constructor
  1016. Parameters:
  1017. pIMeta ATL Smart pointer to the metabase
  1018. tszBaseKey Name of key to enumerate from
  1019. pKeyStack pointer to a stack containing the state to copy or
  1020. NULL to start from the begining
  1021. Returns:
  1022. E_OUTOFMEMORY if allocation fails
  1023. S_OK on success
  1024. ===================================================================*/
  1025. HRESULT CDeepKeyEnum::Init(const CComPtr<IMSAdminBase> &pIMeta,
  1026. LPCTSTR tszBaseKey,
  1027. CKeyStack *pCKeyStack)
  1028. {
  1029. ASSERT(pIMeta.p != NULL);
  1030. ASSERT_NULL_OR_STRING(tszBaseKey);
  1031. ASSERT_NULL_OR_POINTER(pCKeyStack, CKeyStack);
  1032. HRESULT hr;
  1033. m_pIMeta = pIMeta;
  1034. // Copy the base string
  1035. if (tszBaseKey == NULL) {
  1036. // BaseKey is root
  1037. m_tszBaseKey = NULL;
  1038. }
  1039. else {
  1040. // Allocate and copy the passed string to the member string
  1041. m_tszBaseKey = new TCHAR[_tcslen(tszBaseKey) + 1];
  1042. if (m_tszBaseKey == NULL) {
  1043. return ::ReportError(E_OUTOFMEMORY);
  1044. }
  1045. _tcscpy(m_tszBaseKey, tszBaseKey);
  1046. CannonizeKey(m_tszBaseKey);
  1047. }
  1048. // Setup the stack
  1049. if (pCKeyStack == NULL) {
  1050. // Build a new stack
  1051. CKeyStackNode *pCNew;
  1052. m_pCKeyStack = new CKeyStack();
  1053. if (m_pCKeyStack == NULL) {
  1054. return ::ReportError(E_OUTOFMEMORY);
  1055. }
  1056. // Create the first node
  1057. pCNew = new CKeyStackNode();
  1058. if (pCNew == NULL) {
  1059. delete m_pCKeyStack;
  1060. m_pCKeyStack = NULL;
  1061. return ::ReportError(E_OUTOFMEMORY);
  1062. }
  1063. hr = pCNew->Init(NULL, 0);
  1064. if (FAILED(hr)) {
  1065. delete m_pCKeyStack;
  1066. m_pCKeyStack = NULL;
  1067. return ::ReportError(E_OUTOFMEMORY);
  1068. }
  1069. // Put the first node onto the stack
  1070. m_pCKeyStack->Push(pCNew);
  1071. }
  1072. else {
  1073. // Clone the stack we were passed
  1074. m_pCKeyStack = pCKeyStack->Clone();
  1075. if (m_pCKeyStack == NULL) {
  1076. return ::ReportError(E_OUTOFMEMORY);
  1077. }
  1078. }
  1079. return S_OK;
  1080. }
  1081. /*===================================================================
  1082. CDeepKeyEnum::~CDeepKeyEnum
  1083. Destructor
  1084. Parameters:
  1085. None
  1086. Returns:
  1087. Nothing
  1088. ===================================================================*/
  1089. CDeepKeyEnum::~CDeepKeyEnum()
  1090. {
  1091. if (m_tszBaseKey != NULL) {
  1092. delete m_tszBaseKey;
  1093. }
  1094. if (m_pCKeyStack != NULL) {
  1095. delete m_pCKeyStack;
  1096. }
  1097. }
  1098. /*===================================================================
  1099. CDeepKeyEnum::Next
  1100. Gets the next n items from the enumberation.
  1101. Parameters:
  1102. ulNumToGet [in] Number of elements to get
  1103. rgvarDest [out] Array to put them in
  1104. pulNumGot [out] If not NULL, number of elements rgvarDest got
  1105. Returns:
  1106. S_OK if outputs ulNumToGet items
  1107. S_FALSE if outputs less than ulNumToGet items
  1108. E_OUTOFMEMORY if allocation failed
  1109. ===================================================================*/
  1110. STDMETHODIMP CDeepKeyEnum::Next(unsigned long ulNumToGet,
  1111. VARIANT FAR* rgvarDest,
  1112. unsigned long FAR* pulNumGot)
  1113. {
  1114. TRACE0("MetaUtil: CDeepKeyEnum::Next\n");
  1115. ASSERT_NULL_OR_POINTER(pulNumGot, unsigned long);
  1116. // Make sure the array is big enough and we can write to it
  1117. ASSERT((rgvarDest == NULL) || IsValidAddress(rgvarDest, ulNumToGet * sizeof(VARIANT), TRUE));
  1118. if (pulNumGot != NULL) {
  1119. pulNumGot = 0;
  1120. }
  1121. USES_CONVERSION;
  1122. HRESULT hr;
  1123. unsigned int i;
  1124. CKeyStackNode *pCKeyNode;
  1125. CKeyStackNode *pCSubKeyNode;
  1126. wchar_t wszSubKey[ADMINDATA_MAX_NAME_LEN];
  1127. wchar_t wszRelSubKey[ADMINDATA_MAX_NAME_LEN];
  1128. // Open the base key
  1129. METADATA_HANDLE hMDBaseKey;
  1130. hr = m_pIMeta->OpenKey(METADATA_MASTER_ROOT_HANDLE,
  1131. T2W(m_tszBaseKey),
  1132. METADATA_PERMISSION_READ,
  1133. MUTIL_OPEN_KEY_TIMEOUT,
  1134. &hMDBaseKey);
  1135. if (FAILED(hr)) {
  1136. return ::ReportError(hr);
  1137. }
  1138. // For each element to retrive
  1139. for (i=0; i < ulNumToGet; i++) {
  1140. // Get a subkey
  1141. do {
  1142. // Pop a key off the stack
  1143. pCKeyNode = m_pCKeyStack->Pop();
  1144. // if the stack is empty, we're done return S_FALSE
  1145. if (pCKeyNode == NULL) {
  1146. m_pIMeta->CloseKey(hMDBaseKey);
  1147. if (pulNumGot != NULL) {
  1148. *pulNumGot = i;
  1149. }
  1150. return S_FALSE;
  1151. }
  1152. // Attempt to Enum the next key
  1153. hr = m_pIMeta->EnumKeys(hMDBaseKey,
  1154. T2W(pCKeyNode->GetBaseKey()),
  1155. wszSubKey,
  1156. pCKeyNode->GetIndex());
  1157. // If failed delete the stack entry
  1158. if (FAILED(hr)) {
  1159. delete pCKeyNode;
  1160. if ((HRESULT_CODE(hr) != ERROR_NO_MORE_ITEMS) &&
  1161. (HRESULT_CODE(hr) != ERROR_PATH_NOT_FOUND)) {
  1162. // Got an unexpected Error
  1163. m_pIMeta->CloseKey(hMDBaseKey);
  1164. return ::ReportError(hr);
  1165. }
  1166. }
  1167. } while (FAILED(hr));
  1168. // Build the relative subkey
  1169. if ((pCKeyNode->GetBaseKey() == NULL) ||
  1170. ((pCKeyNode->GetBaseKey())[0] == _T('\0')) ) {
  1171. wcscpy(wszRelSubKey, wszSubKey);
  1172. }
  1173. else {
  1174. wcscpy(wszRelSubKey, T2W(pCKeyNode->GetBaseKey()));
  1175. wcscat(wszRelSubKey, L"/");
  1176. wcscat(wszRelSubKey, wszSubKey);
  1177. }
  1178. // Output the relative subkey
  1179. VariantInit(&(rgvarDest[i]));
  1180. rgvarDest[i].vt = VT_BSTR;
  1181. rgvarDest[i].bstrVal = W2BSTR(wszRelSubKey);
  1182. // Increment the key index
  1183. pCKeyNode->SetIndex(pCKeyNode->GetIndex() + 1);
  1184. // Push the key back onto the stack
  1185. m_pCKeyStack->Push(pCKeyNode);
  1186. // Create a stack node for the subkey
  1187. pCSubKeyNode = new CKeyStackNode();
  1188. if (pCSubKeyNode == NULL) {
  1189. m_pIMeta->CloseKey(hMDBaseKey);
  1190. return ::ReportError(E_OUTOFMEMORY);
  1191. }
  1192. hr = pCSubKeyNode->Init(W2T(wszRelSubKey), 0);
  1193. if (FAILED(hr)) {
  1194. m_pIMeta->CloseKey(hMDBaseKey);
  1195. return ::ReportError(hr);
  1196. }
  1197. // Push the subkey onto the stack
  1198. m_pCKeyStack->Push(pCSubKeyNode);
  1199. }
  1200. // Close the base key
  1201. m_pIMeta->CloseKey(hMDBaseKey);
  1202. if (pulNumGot != NULL) {
  1203. *pulNumGot = i;
  1204. }
  1205. return S_OK;
  1206. }
  1207. /*===================================================================
  1208. CDeepKeyEnum::Skip
  1209. Skips the next n items in an enumeration
  1210. Parameters:
  1211. ulNumToSkip [in] Number of elements to skip
  1212. Returns:
  1213. S_OK if outputs ulNumToGet items
  1214. E_OUTOFMEMORY if allocation failed
  1215. ===================================================================*/
  1216. STDMETHODIMP CDeepKeyEnum::Skip(unsigned long ulNumToSkip)
  1217. {
  1218. TRACE0("MetaUtil: CDeepKeyEnum::Skip\n");
  1219. USES_CONVERSION;
  1220. HRESULT hr;
  1221. unsigned long i;
  1222. CKeyStackNode *pCKeyNode;
  1223. CKeyStackNode *pCSubKeyNode;
  1224. wchar_t wszSubKey[ADMINDATA_MAX_NAME_LEN];
  1225. wchar_t wszRelSubKey[ADMINDATA_MAX_NAME_LEN];
  1226. // Open the base key
  1227. METADATA_HANDLE hMDBaseKey;
  1228. hr = m_pIMeta->OpenKey(METADATA_MASTER_ROOT_HANDLE,
  1229. T2W(m_tszBaseKey),
  1230. METADATA_PERMISSION_READ,
  1231. MUTIL_OPEN_KEY_TIMEOUT,
  1232. &hMDBaseKey);
  1233. if (FAILED(hr)) {
  1234. return ::ReportError(hr);
  1235. }
  1236. // For each element to stip
  1237. for (i=0; i < ulNumToSkip; i++) {
  1238. // Get a subkey
  1239. do {
  1240. // Pop a key off the stack
  1241. pCKeyNode = m_pCKeyStack->Pop();
  1242. // if the stack is empty, we're done return S_OK
  1243. if (pCKeyNode == NULL) {
  1244. m_pIMeta->CloseKey(hMDBaseKey);
  1245. return S_OK;
  1246. }
  1247. // Attempt to Enum the next key
  1248. hr = m_pIMeta->EnumKeys(METADATA_MASTER_ROOT_HANDLE,
  1249. T2W(pCKeyNode->GetBaseKey()),
  1250. wszSubKey,
  1251. pCKeyNode->GetIndex());
  1252. // If failed delete the stack entry
  1253. if (FAILED(hr)) {
  1254. delete pCKeyNode;
  1255. if ((HRESULT_CODE(hr) != ERROR_NO_MORE_ITEMS) &&
  1256. (HRESULT_CODE(hr) != ERROR_PATH_NOT_FOUND)) {
  1257. // Got an unexpected Error
  1258. m_pIMeta->CloseKey(hMDBaseKey);
  1259. return ::ReportError(hr);
  1260. }
  1261. }
  1262. } while (FAILED(hr));
  1263. // Build the relative subkey
  1264. if ((pCKeyNode->GetBaseKey() == NULL) ||
  1265. ((pCKeyNode->GetBaseKey())[0] == _T('\0')) ) {
  1266. wcscpy(wszRelSubKey, wszSubKey);
  1267. }
  1268. else {
  1269. wcscpy(wszRelSubKey, T2W(pCKeyNode->GetBaseKey()));
  1270. wcscat(wszRelSubKey, L"/");
  1271. wcscat(wszRelSubKey, wszSubKey);
  1272. }
  1273. // Increment the key index
  1274. pCKeyNode->SetIndex(pCKeyNode->GetIndex() + 1);
  1275. // Push the key back on the stack
  1276. m_pCKeyStack->Push(pCKeyNode);
  1277. // Create a stack node for the subkey
  1278. pCSubKeyNode = new CKeyStackNode();
  1279. if (pCSubKeyNode == NULL) {
  1280. m_pIMeta->CloseKey(hMDBaseKey);
  1281. return ::ReportError(E_OUTOFMEMORY);
  1282. }
  1283. hr = pCSubKeyNode->Init(W2T(wszRelSubKey), 0);
  1284. if (FAILED(hr)) {
  1285. m_pIMeta->CloseKey(hMDBaseKey);
  1286. return ::ReportError(hr);
  1287. }
  1288. // Push the subkey onto the stack
  1289. m_pCKeyStack->Push(pCSubKeyNode);
  1290. }
  1291. // Close the base key
  1292. m_pIMeta->CloseKey(hMDBaseKey);
  1293. return S_OK;
  1294. }
  1295. /*===================================================================
  1296. CDeepKeyEnum::Reset
  1297. Rests the enumeration to the first item
  1298. Parameters:
  1299. None
  1300. Returns:
  1301. E_OUTOFMEMORY if not enough memory to build a new stack
  1302. S_OK on success
  1303. ===================================================================*/
  1304. STDMETHODIMP CDeepKeyEnum::Reset()
  1305. {
  1306. TRACE0("MetaUtil: CDeepKeyEnum::Reset\n");
  1307. HRESULT hr;
  1308. // Build a new stack (if this fails we still have the old stack)
  1309. CKeyStack *pCNewStack;
  1310. CKeyStackNode *pCNewNode;
  1311. pCNewStack = new CKeyStack();
  1312. if (pCNewStack == NULL) {
  1313. return ::ReportError(E_OUTOFMEMORY);
  1314. }
  1315. // Create the first node
  1316. pCNewNode = new CKeyStackNode();
  1317. if (pCNewNode == NULL) {
  1318. delete pCNewStack;
  1319. return ::ReportError(E_OUTOFMEMORY);
  1320. }
  1321. hr = pCNewNode->Init(NULL, 0);
  1322. if (FAILED(hr)) {
  1323. delete pCNewStack;
  1324. return ::ReportError(E_OUTOFMEMORY);
  1325. }
  1326. // Put the first node onto the new stack
  1327. pCNewStack->Push(pCNewNode);
  1328. // Replace the old stack
  1329. delete m_pCKeyStack;
  1330. m_pCKeyStack = pCNewStack;
  1331. return S_OK;
  1332. }
  1333. /*===================================================================
  1334. CDeepKeyEnum::Clone
  1335. Gets an interface pointer to a copy of the enumeration at its
  1336. current state.
  1337. Parameters:
  1338. ppIReturn [out] Pointer to interface for copy
  1339. Returns:
  1340. E_INVALIDARG if ppIReturn == NULL
  1341. E_OUTOFMEMORY if not enough memory to create clone
  1342. S_OK on success
  1343. ===================================================================*/
  1344. STDMETHODIMP CDeepKeyEnum::Clone(IEnumVARIANT FAR* FAR* ppIReturn)
  1345. {
  1346. TRACE0("MetaUtil: CDeepKeyEnum::Clone\n");
  1347. ASSERT_NULL_OR_POINTER(ppIReturn, LPUNKNOWN);
  1348. if (ppIReturn == NULL) {
  1349. return ::ReportError(E_INVALIDARG);
  1350. }
  1351. HRESULT hr;
  1352. // Create a copy of the enumeration
  1353. CComObject<CDeepKeyEnum> *pObj = NULL;
  1354. ATLTRY(pObj = new CComObject<CDeepKeyEnum>);
  1355. if (pObj == NULL) {
  1356. return ::ReportError(E_OUTOFMEMORY);
  1357. }
  1358. hr = pObj->Init(m_pIMeta, m_tszBaseKey, m_pCKeyStack);
  1359. if (FAILED(hr)) {
  1360. return ::ReportError(hr);
  1361. }
  1362. // Set the interface to IEnumVARIANT
  1363. hr = pObj->QueryInterface(IID_IEnumVARIANT, (void **) ppIReturn);
  1364. if (FAILED(hr)) {
  1365. return ::ReportError(hr);
  1366. }
  1367. ASSERT(*ppIReturn != NULL);
  1368. return S_OK;
  1369. }