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.

2075 lines
45 KiB

  1. // compkey.cpp: implementation of the CCompoundKey class
  2. // Copyright (c)1997-2001 Microsoft Corporation
  3. //
  4. //////////////////////////////////////////////////////////////////////
  5. // original author: shawnwu
  6. // creation date: 4/18/2001
  7. #include "precomp.h"
  8. #include "compkey.h"
  9. #include "persistmgr.h"
  10. /*
  11. Routine Description:
  12. Name:
  13. CompKeyLessThan::operator()
  14. Functionality:
  15. override () operator
  16. Virtual:
  17. No.
  18. Arguments:
  19. pX - left.
  20. pY - right.
  21. Return Value:
  22. read code. It's easier that way.
  23. Notes:
  24. We are not really doing much other than call CCompoundKey's operator <.
  25. */
  26. bool CompKeyLessThan::operator() (
  27. IN const CCompoundKey* pX,
  28. IN const CCompoundKey* pY
  29. ) const
  30. {
  31. if (pX == NULL && pY != NULL)
  32. return true;
  33. else if (pX != NULL && pY == NULL)
  34. return false;
  35. else
  36. return *pX < *pY;
  37. }
  38. /*
  39. Routine Description:
  40. Name:
  41. CCompoundKey::CCompoundKey
  42. Functionality:
  43. constructor.
  44. Virtual:
  45. No.
  46. Arguments:
  47. dwSize - This will be size of the compound key's capacity to hold values.
  48. you can't change it.
  49. Return Value:
  50. none
  51. Notes:
  52. If dwSize == 0, it's considered a null key. Null keys are useful for identifying
  53. static method calls, and singletons (because they don't have keys)
  54. */
  55. CCompoundKey::CCompoundKey (
  56. IN DWORD dwSize
  57. )
  58. :
  59. m_dwSize(dwSize),
  60. m_pValues(NULL)
  61. {
  62. if (m_dwSize > 0)
  63. {
  64. m_pValues = new VARIANT*[m_dwSize];
  65. if (m_pValues == NULL)
  66. {
  67. m_dwSize = 0;
  68. }
  69. else
  70. {
  71. //
  72. // make sure that we initialize those VARIANT* to NULL
  73. // because we are going to own them and delete them!
  74. //
  75. ::memset(m_pValues, 0, m_dwSize * sizeof(VARIANT*));
  76. }
  77. }
  78. }
  79. /*
  80. Routine Description:
  81. Name:
  82. CCompoundKey::~CCompoundKey
  83. Functionality:
  84. destructor.
  85. Virtual:
  86. No.
  87. Arguments:
  88. none
  89. Return Value:
  90. none
  91. Notes:
  92. Just need to know how to delete a VARIANT*
  93. */
  94. CCompoundKey::~CCompoundKey()
  95. {
  96. for (DWORD i = 0; i < m_dwSize; i++)
  97. {
  98. if (m_pValues[i])
  99. {
  100. ::VariantClear(m_pValues[i]);
  101. delete m_pValues[i];
  102. }
  103. }
  104. delete [] m_pValues;
  105. }
  106. /*
  107. Routine Description:
  108. Name:
  109. CCompoundKey::AddKeyPropertyValue
  110. Functionality:
  111. Add a key property value to this compound key.
  112. Virtual:
  113. No.
  114. Arguments:
  115. none
  116. Return Value:
  117. WBEM_NO_ERROR if succeeded.
  118. WBEM_E_INVALID_PARAMETER if ppVar == NULL;
  119. WBEM_E_VALUE_OUT_OF_RANGE is the given index is not in range.
  120. Notes:
  121. CCompoundKey doesn't keep track of property names. Instead, it simply records
  122. its values. The order this function is called determines what value belongs to
  123. what property. Caller must keep track of that order. Different compound keys
  124. become comparable only if they have the same order.
  125. Also, the in coming parameter *ppVar is owned by the this object after this call
  126. */
  127. HRESULT
  128. CCompoundKey::AddKeyPropertyValue (
  129. IN DWORD dwIndex,
  130. IN OUT VARIANT ** ppVar
  131. )
  132. {
  133. if (ppVar == NULL)
  134. {
  135. return WBEM_E_INVALID_PARAMETER;
  136. }
  137. else if (dwIndex >= m_dwSize)
  138. {
  139. return WBEM_E_VALUE_OUT_OF_RANGE;
  140. }
  141. //
  142. // if there is already a value, then we need to delete the old one
  143. //
  144. if (m_pValues[dwIndex])
  145. {
  146. ::VariantClear(m_pValues[dwIndex]);
  147. delete m_pValues[dwIndex];
  148. }
  149. //
  150. // attach to the new one
  151. //
  152. m_pValues[dwIndex] = *ppVar;
  153. //
  154. // hey, we own it now
  155. //
  156. *ppVar = NULL;
  157. return WBEM_NO_ERROR;
  158. }
  159. /*
  160. Routine Description:
  161. Name:
  162. CCompoundKey::GetPropertyValue
  163. Functionality:
  164. Retrieve a key property value by key property index (caller must know that).
  165. Virtual:
  166. No.
  167. Arguments:
  168. none
  169. Return Value:
  170. Read code.
  171. Notes:
  172. See AddKeyPropertyValue's notes
  173. */
  174. HRESULT
  175. CCompoundKey::GetPropertyValue (
  176. IN DWORD dwIndex,
  177. OUT VARIANT * pVar
  178. )const
  179. {
  180. if (pVar == NULL)
  181. {
  182. return WBEM_E_INVALID_PARAMETER;
  183. }
  184. else if (dwIndex >= m_dwSize)
  185. {
  186. return WBEM_E_VALUE_OUT_OF_RANGE;
  187. }
  188. //
  189. // make sure that our out-bound parameter is in a empty state
  190. //
  191. ::VariantInit(pVar);
  192. if (m_pValues[dwIndex])
  193. {
  194. return ::VariantCopy(pVar, m_pValues[dwIndex]);
  195. }
  196. else
  197. {
  198. return WBEM_E_NOT_AVAILABLE;
  199. }
  200. }
  201. /*
  202. Routine Description:
  203. Name:
  204. CCompoundKey::operator <
  205. Functionality:
  206. Compare this object with the in-bound parameter and see which compound key
  207. key is greater. Ultimately, the relation is determined by the variant values
  208. of each corresponding key property.
  209. Virtual:
  210. No.
  211. Arguments:
  212. none
  213. Return Value:
  214. Read code.
  215. Notes:
  216. (1) See AddKeyPropertyValue's notes.
  217. (2) See CompareVariant's notes
  218. */
  219. bool
  220. CCompoundKey::operator < (
  221. IN const CCompoundKey& right
  222. )const
  223. {
  224. //
  225. // defensive against potential erroneous comparison.
  226. // This shouldn't happen in our correct use. But sometimes we write
  227. // less-than-correct code.
  228. //
  229. if (m_dwSize != right.m_dwSize)
  230. {
  231. return (m_dwSize < right.m_dwSize);
  232. }
  233. int iComp = 0;
  234. //
  235. // The first less than or greater than result wins
  236. //
  237. for (int i = 0; i < m_dwSize; i++)
  238. {
  239. //
  240. // if both variants are valid
  241. //
  242. if (m_pValues[i] != NULL && right.m_pValues[i] != NULL)
  243. {
  244. //
  245. // CompareVariant returns the exact same int value
  246. // as string comparison results
  247. //
  248. iComp = CompareVariant(m_pValues[i], right.m_pValues[i]);
  249. if (iComp > 0)
  250. {
  251. return false;
  252. }
  253. else if (iComp < 0)
  254. {
  255. return true;
  256. }
  257. //
  258. // else is equal! need to continue comparing the rest of the values
  259. //
  260. }
  261. else if (m_pValues[i] == NULL)
  262. {
  263. return true;
  264. }
  265. else
  266. {
  267. //
  268. // right.m_pValues[i] == NULL
  269. //
  270. return false;
  271. }
  272. }
  273. //
  274. // if reach here, this must be an equal case
  275. //
  276. return false;
  277. }
  278. /*
  279. Routine Description:
  280. Name:
  281. CCompoundKey::CompareVariant
  282. Functionality:
  283. Compare two variants
  284. Virtual:
  285. No.
  286. Arguments:
  287. pVar1 - must not be NULL
  288. pVar2 - must not be NULL
  289. Return Value:
  290. less than 0 if pVar1 < pVar2
  291. Greater than 0 if pVar1 < pVar2
  292. 0 if they are considered equal
  293. Notes:
  294. (1) for efficiency reasons, we don't check the parameters.
  295. (2) The reason we are doing this is due the fact that WMI will give us inconsistent
  296. path when boolean are used. Sometimes it gives boolVal=TRUE, sometimes it gives
  297. boolVal=1. This creates problems for us.
  298. (3) This function currently only works for our supported vt types.
  299. (4) type mismatch will only be dealt with if one of them is boolean.
  300. */
  301. int
  302. CCompoundKey::CompareVariant (
  303. IN VARIANT* pVar1,
  304. IN VARIANT* pVar2
  305. )const
  306. {
  307. //
  308. // default to equal because that is the only consistent value
  309. // in case of failure
  310. //
  311. int iResult = 0;
  312. VARIANT varCoerced1;
  313. ::VariantInit(&varCoerced1);
  314. VARIANT varCoerced2;
  315. ::VariantInit(&varCoerced2);
  316. //
  317. // if both are strings, then use case-insensitive comparison
  318. //
  319. if (pVar1->vt == pVar2->vt && pVar1->vt == VT_BSTR)
  320. {
  321. iResult = _wcsicmp(pVar1->bstrVal, pVar2->bstrVal);
  322. }
  323. //
  324. // if one is boolean, then coerced both to boolean
  325. //
  326. else if (pVar1->vt == VT_BOOL || pVar2->vt == VT_BOOL)
  327. {
  328. //
  329. // in case the coersion fails, we will call the failed one less then the succeeded one.
  330. // Don't use the WBEM_NO_ERROR even though they are defined to be S_OK. WMI may change it
  331. // later. So, use the MSDN documented hresult values
  332. //
  333. HRESULT hr1 = ::VariantChangeType(&varCoerced1, pVar1, VARIANT_LOCALBOOL, VT_BOOL);
  334. HRESULT hr2 = ::VariantChangeType(&varCoerced2, pVar2, VARIANT_LOCALBOOL, VT_BOOL);
  335. if (hr1 == S_OK && hr2 == S_OK)
  336. {
  337. if (varCoerced1.boolVal == varCoerced2.lVal)
  338. {
  339. //
  340. // equal
  341. //
  342. iResult = 0;
  343. }
  344. else if (varCoerced1.boolVal == VARIANT_TRUE)
  345. {
  346. //
  347. // greater
  348. //
  349. iResult = 1;
  350. }
  351. else
  352. {
  353. //
  354. // less
  355. //
  356. iResult = -1;
  357. }
  358. }
  359. else if (hr1 == S_OK)
  360. {
  361. //
  362. // second coersion fails, we say the second is greater
  363. //
  364. iResult = 1;
  365. }
  366. else if (hr2 == S_OK)
  367. {
  368. //
  369. // first coersion fails, we say the first is greater
  370. //
  371. iResult = -1;
  372. }
  373. else
  374. {
  375. //
  376. // both fails. We are out of luck.
  377. //
  378. iResult = 0;
  379. }
  380. }
  381. //
  382. // everything else, coerced both to VI_I4
  383. //
  384. else
  385. {
  386. HRESULT hr1 = ::VariantChangeType(&varCoerced1, pVar1, VARIANT_LOCALBOOL, VT_I4);
  387. HRESULT hr2 = ::VariantChangeType(&varCoerced2, pVar2, VARIANT_LOCALBOOL, VT_I4);
  388. if (hr1 == S_OK && hr2 == S_OK)
  389. {
  390. iResult = varCoerced1.lVal - varCoerced2.lVal;
  391. }
  392. else if (hr1 == S_OK)
  393. {
  394. //
  395. // second coersion fails, we say the second is greater
  396. //
  397. iResult = 1;
  398. }
  399. else if (hr2 == S_OK)
  400. {
  401. //
  402. // first coersion fails, we say the first is greater
  403. //
  404. iResult = -1;
  405. }
  406. else
  407. {
  408. //
  409. // both fails. We are out of luck.
  410. //
  411. iResult = 0;
  412. }
  413. }
  414. ::VariantClear(&varCoerced1);
  415. ::VariantClear(&varCoerced2);
  416. return iResult;
  417. }
  418. //
  419. // implementation of CExtClassInstCookieList
  420. //
  421. /*
  422. Routine Description:
  423. Name:
  424. CExtClassInstCookieList::CExtClassInstCookie
  425. Functionality:
  426. constructor.
  427. Virtual:
  428. No.
  429. Arguments:
  430. none
  431. Return Value:
  432. none
  433. Notes:
  434. (1) INVALID_COOKIE is the invalid cookie value.
  435. (2) No thread safety. Caller must be aware.
  436. */
  437. CExtClassInstCookieList::CExtClassInstCookieList ()
  438. :
  439. m_dwMaxCookie(INVALID_COOKIE),
  440. m_pVecNames(NULL),
  441. m_dwCookieArrayCount(0)
  442. {
  443. }
  444. /*
  445. Routine Description:
  446. Name:
  447. CExtClassInstCookieList::~CExtClassInstCookieList
  448. Functionality:
  449. destructor.
  450. Virtual:
  451. No.
  452. Arguments:
  453. none
  454. Return Value:
  455. none
  456. Notes:
  457. (1) No thread safety. Caller must be aware.
  458. */
  459. CExtClassInstCookieList::~CExtClassInstCookieList ()
  460. {
  461. Cleanup();
  462. }
  463. /*
  464. Routine Description:
  465. Name:
  466. CExtClassInstCookieList::Create
  467. Functionality:
  468. Given a store and a section name (each class has a section corresponding to it, as
  469. a matter of fact, the section name is, in current implementation, the class name),
  470. this function populates its contents.
  471. Virtual:
  472. No.
  473. Arguments:
  474. pSceStore - pointer to the CSceStore object prepared to read
  475. pszSectionName - section name where this cookie list is to be created.
  476. pvecNames - the vector that holds the key property names in order. We rely
  477. on this vector as our order guidence to push values into our own vector.
  478. Remember? those two things must match in their order.
  479. A NULL in-bounding value means it intends to create a NULL key cookie
  480. Return Value:
  481. Success: WBEM_NO_ERROR
  482. Failure: Various HRESULT code. In particular, if the cookie array is incorrectly formated
  483. ( it must be a integer number delimited by : (including the trailing : at the end), then
  484. we return WBEM_E_INVALID_SYNTAX.
  485. Any failure indicates that the cookie list is not created.
  486. Notes:
  487. (1) No thread safety. Caller must be aware.
  488. */
  489. HRESULT
  490. CExtClassInstCookieList::Create (
  491. IN CSceStore * pSceStore,
  492. IN LPCWSTR pszSectionName,
  493. IN std::vector<BSTR> * pvecNames
  494. )
  495. {
  496. //
  497. // we must have a valid store and a valid section name
  498. //
  499. if (pSceStore == NULL || pszSectionName == NULL)
  500. {
  501. return WBEM_E_INVALID_PARAMETER;
  502. }
  503. m_pVecNames = pvecNames;
  504. //
  505. // 1 is reserved for pszListPrefix
  506. //
  507. WCHAR szCookieList[MAX_INT_LENGTH + 1];
  508. WCHAR szCompKey[MAX_INT_LENGTH + 1];
  509. HRESULT hr = WBEM_NO_ERROR;
  510. //
  511. // Assume that we have no cookie array
  512. //
  513. m_dwCookieArrayCount = 0;
  514. //
  515. // cookie list is persisted in the following fashion: "A1=n:m:k:", "A2=n:m:k:", "A3=n:m:k:"
  516. // where 'A' == pszListPrefix.
  517. //
  518. //
  519. // enumerate all such possiblilities until we see a non-existent Ai (i is a integer).
  520. //
  521. DWORD dwCount = 1;
  522. while (SUCCEEDED(hr))
  523. {
  524. //
  525. // First, we need to create the cookie list name
  526. //
  527. wsprintf(szCookieList, L"%s%d", pszListPrefix, dwCount++);
  528. DWORD dwRead = 0;
  529. //
  530. // pszBuffer will hold the contents read from the store.
  531. // Need to free the memory allocated for pszBuffer
  532. //
  533. LPWSTR pszBuffer = NULL;
  534. hr = pSceStore->GetPropertyFromStore(pszSectionName, szCookieList, &pszBuffer, &dwRead);
  535. if (SUCCEEDED(hr) && pszBuffer)
  536. {
  537. //
  538. // so far, we have this many cookie arrays
  539. //
  540. m_dwCookieArrayCount += 1;
  541. LPCWSTR pszCur = pszBuffer;
  542. DWORD dwCookie = 0;
  543. //
  544. // as long as it is a digit
  545. //
  546. while (iswdigit(*pszCur))
  547. {
  548. //
  549. // conver the first portion as a number
  550. //
  551. dwCookie = _wtol(pszCur);
  552. //
  553. // First, prepare the composite key's name (K1, K2, depending on the dwCookie.)
  554. //
  555. wsprintf(szCompKey, L"%s%d", pszKeyPrefix, dwCookie);
  556. //
  557. // read the composite key of this cookie
  558. // need to free the memory allocated for pszCompKeyBuffer
  559. //
  560. LPWSTR pszCompKeyBuffer = NULL;
  561. DWORD dwCompKeyLen = 0;
  562. hr = pSceStore->GetPropertyFromStore(pszSectionName, szCompKey, &pszCompKeyBuffer, &dwCompKeyLen);
  563. if (SUCCEEDED(hr))
  564. {
  565. //
  566. // AddCompKey can be called for two purposes (simply adding, or adding and requesting a new cookie)
  567. // Here, we are just adding. But we need a place holder.
  568. //
  569. DWORD dwNewCookie = INVALID_COOKIE;
  570. //
  571. // we are truly adding the (compound key, cookie) pair
  572. //
  573. hr = AddCompKey(pszCompKeyBuffer, dwCookie, &dwNewCookie);
  574. //
  575. // increate the max used cookie member if appropriate
  576. //
  577. if (dwCookie > m_dwMaxCookie)
  578. {
  579. m_dwMaxCookie = dwCookie;
  580. }
  581. }
  582. delete [] pszCompKeyBuffer;
  583. //
  584. //skip the current portion of the integer
  585. //
  586. while (iswdigit(*pszCur))
  587. {
  588. ++pszCur;
  589. }
  590. if (*pszCur == wchCookieSep)
  591. {
  592. //
  593. // skip the ':'
  594. //
  595. ++pszCur;
  596. }
  597. else if (*pszCur == L'\0')
  598. {
  599. //
  600. // see the end
  601. //
  602. break;
  603. }
  604. else
  605. {
  606. //
  607. // see an invalid character
  608. //
  609. hr = WBEM_E_INVALID_SYNTAX;
  610. break;
  611. }
  612. }
  613. }
  614. else if (hr == WBEM_E_NOT_FOUND)
  615. {
  616. // if Ai doesn't exist, we no longer look for A(i+1). For example, if A3 doesn't exist, then we
  617. // no longer look for A4, A5, etc. So, if property manager fails to get Ai, we consider this as
  618. // no more data.
  619. delete [] pszBuffer;
  620. pszBuffer = NULL;
  621. hr = WBEM_NO_ERROR;
  622. break;
  623. }
  624. delete [] pszBuffer;
  625. }
  626. //
  627. // in case of failure, set proper default
  628. //
  629. if (FAILED(hr))
  630. {
  631. //
  632. // maybe partial construction, so clean it up
  633. //
  634. Cleanup();
  635. }
  636. return hr;
  637. }
  638. /*
  639. Routine Description:
  640. Name:
  641. CExtClassInstCookieList::Save
  642. Functionality:
  643. save the cookie list into a store.
  644. Virtual:
  645. No.
  646. Arguments:
  647. pSceStore - pointer to the CSceStore object prepared for save
  648. pszSectionName - section name where this cookie list is to be created.
  649. Return Value:
  650. Success: various potential success code. Use SUCCEEDED to test.
  651. Failure: Various HRESULT code.
  652. Any failure indicates that the cookie list is not saved properly.
  653. Notes:
  654. (1) No thread safety. Caller must be aware.
  655. */
  656. HRESULT
  657. CExtClassInstCookieList::Save (
  658. IN CSceStore* pSceStore,
  659. IN LPCWSTR pszSectionName
  660. )
  661. {
  662. //
  663. // pszBuffer will hold upto MAX_COOKIE_COUNT_PER_LINE count of cookie info = <cookie number> plus separater
  664. //
  665. LPWSTR pszBuffer = new WCHAR [(MAX_INT_LENGTH + 1) * MAX_COOKIE_COUNT_PER_LINE + 1];
  666. if (pszBuffer == NULL)
  667. {
  668. return WBEM_E_OUT_OF_MEMORY;
  669. }
  670. //
  671. // allocate a generous buffer to hold the key name and cookie array name
  672. //
  673. LPWSTR pszKey = new WCHAR[MAX_INT_LENGTH + wcslen(pszKeyPrefix) + wcslen(pszListPrefix) + 1];
  674. if (pszKey == NULL)
  675. {
  676. delete [] pszBuffer;
  677. return WBEM_E_OUT_OF_MEMORY;
  678. }
  679. DWORD dwCookieArrayCount = 1;
  680. int iLenKey = wcslen(pszKeyPrefix);
  681. int iLen = wcslen(pszListPrefix);
  682. if (iLen < iLenKey)
  683. {
  684. iLen = iLenKey;
  685. }
  686. HRESULT hr = WBEM_NO_ERROR;
  687. DWORD dwCookieCount = m_vecCookies.size();
  688. //
  689. // going through all cookies. Since we want to preserve the order
  690. // this time, we need to use the m_vecCookies to enumerate.
  691. //
  692. DWORD dwIndex = 0;
  693. while (dwIndex < dwCookieCount)
  694. {
  695. //
  696. // this loop is to:
  697. // (1) write the string version of each compound key
  698. // (2) pack enough cookies into the cookie list (but won't write it)
  699. //
  700. LPWSTR pCur = pszBuffer;
  701. for (int i = 0; (i < MAX_COOKIE_COUNT_PER_LINE) && (dwIndex < dwCookieCount); ++i, dwIndex++)
  702. {
  703. //
  704. // packing the cookies into the cookie list. We need to advance our
  705. // pCur to the next position (of pszBuffer) to write
  706. //
  707. wsprintf(pCur, L"%d%c", m_vecCookies[dwIndex]->dwCookie, wchCookieSep);
  708. pCur += wcslen(pCur);
  709. //
  710. // now, write Knnn=<compound key>
  711. //
  712. wsprintf(pszKey, L"%s%d", pszKeyPrefix, m_vecCookies[dwIndex]->dwCookie);
  713. CComBSTR bstrCompKey;
  714. //
  715. // create the string version of the composite key (the <compound key>)
  716. //
  717. hr = CreateCompoundKeyString(&bstrCompKey, m_vecCookies[dwIndex]->pKey);
  718. if (SUCCEEDED(hr))
  719. {
  720. hr = pSceStore->SavePropertyToStore(pszSectionName, pszKey, (LPCWSTR)bstrCompKey);
  721. }
  722. if (FAILED(hr))
  723. {
  724. break;
  725. }
  726. }
  727. //
  728. // if everything is alright, now is time to write the cookie list prepared by
  729. // the previous loop
  730. //
  731. if (SUCCEEDED(hr))
  732. {
  733. //
  734. // prepare the cookie list name
  735. //
  736. wsprintf(pszKey, L"%s%d", pszListPrefix, dwCookieArrayCount);
  737. hr = pSceStore->SavePropertyToStore(pszSectionName, pszKey, pszBuffer);
  738. if (FAILED(hr))
  739. {
  740. break;
  741. }
  742. }
  743. else
  744. {
  745. break;
  746. }
  747. ++dwCookieArrayCount;
  748. }
  749. //
  750. // if everything goes well (all cookie arrays have been saved), then, we need to remove
  751. // any potential extra cookie arrays Axxx, where the count starts from dwCookieArrayCount to m_dwCookieArrayCount
  752. //
  753. if (SUCCEEDED(hr))
  754. {
  755. //
  756. // we will delete all left over cookie arrays.
  757. // In case of error during deleting, we will continue the deletion, but will report the error
  758. //
  759. while (dwCookieArrayCount <= m_dwCookieArrayCount)
  760. {
  761. //
  762. // prepare the cookie list name
  763. //
  764. wsprintf(pszKey, L"%s%d", pszListPrefix, dwCookieArrayCount++);
  765. HRESULT hrDelete = pSceStore->DeletePropertyFromStore(pszSectionName, pszKey);
  766. //
  767. // we won't stop the deletion in case of error.
  768. // But we will report it.
  769. //
  770. if (FAILED(hrDelete))
  771. {
  772. hr = hrDelete;
  773. }
  774. }
  775. }
  776. delete [] pszBuffer;
  777. delete [] pszKey;
  778. return hr;
  779. }
  780. /*
  781. Routine Description:
  782. Name:
  783. CExtClassInstCookieList::DeleteKeyFromStore
  784. Functionality:
  785. Delete all key properties (Key=<Compound Key String>)
  786. Virtual:
  787. No.
  788. Arguments:
  789. pSceStore - pointer to the CSceStore object prepared for save
  790. pszSectionName - section name where this cookie list is to be created.
  791. dwCookie - the cookie to of the key to be deleted
  792. Return Value:
  793. Success: WBEM_NO_ERROR.
  794. Failure: Various HRESULT code.
  795. Any failure indicates that the cookie list is not delete properly.
  796. Notes:
  797. (1) No thread safety. Caller must be aware.
  798. */
  799. HRESULT
  800. CExtClassInstCookieList::DeleteKeyFromStore (
  801. IN CSceStore* pSceStore,
  802. IN LPCWSTR pszSectionName,
  803. IN DWORD dwCookie
  804. )
  805. {
  806. int iLen = wcslen(pszKeyPrefix);
  807. //
  808. // 1 for pszKeyPrefix
  809. //
  810. WCHAR szKey[MAX_INT_LENGTH + 1];
  811. wsprintf(szKey, L"%s%d", pszKeyPrefix, dwCookie);
  812. return pSceStore->DeletePropertyFromStore(pszSectionName, szKey);
  813. }
  814. /*
  815. Routine Description:
  816. Name:
  817. CExtClassInstCookieList::GetCompKeyCookie
  818. Functionality:
  819. Given a string version of the compound key (what is really stored in our template),
  820. find the cookie. If found, also give an interator of the map to that element.
  821. Virtual:
  822. No.
  823. Arguments:
  824. pszCompKey - string version of the compound key
  825. pIt - The iterator to the map that points to the CCompoundKey
  826. whose key properties match what is encoded in the pszCompKey
  827. Return Value:
  828. the cookie if found.
  829. INVALID_COOKIE if not found.
  830. Notes:
  831. (1) No thread safety. Caller must be aware.
  832. */
  833. DWORD
  834. CExtClassInstCookieList::GetCompKeyCookie (
  835. IN LPCWSTR pszCompKey,
  836. OUT ExtClassCookieIterator * pIt
  837. )
  838. {
  839. CCompoundKey* pKey = NULL;
  840. //
  841. // we need a CCompoundKey to lookup. Convert the string version
  842. // to a CCompoundKey instance. Need to delete it.
  843. //
  844. HRESULT hr = CreateCompoundKeyFromString(pszCompKey, &pKey);
  845. if (FAILED(hr))
  846. {
  847. *pIt = m_mapCookies.end();
  848. return INVALID_COOKIE;
  849. }
  850. *pIt = m_mapCookies.find(pKey);
  851. DWORD cookie = INVALID_COOKIE;
  852. if (*pIt != m_mapCookies.end())
  853. {
  854. cookie = (*((ExtClassCookieIterator)(*pIt))).second;
  855. }
  856. delete pKey;
  857. return cookie;
  858. }
  859. /*
  860. Routine Description:
  861. Name:
  862. CExtClassInstCookieList::AddCompKey
  863. Functionality:
  864. Add a string version of the compound key (what is really stored in our template) to
  865. this object. Since our store really only give string version of the compound key,
  866. this method is what is used during creation upon reading the compound key string.
  867. Virtual:
  868. No.
  869. Arguments:
  870. pszCompKey - string version of the compound key. pszCompKey == pszNullKey means
  871. to add a static function call instance or a singleton
  872. dwDefCookie - Default value for the cookie it is called to add.
  873. If dwDefCookie == INVALID_COOKIE, we will create a new cookie while adding
  874. *pdwNewCookie - pass back the new cookie for the just added compound key
  875. Return Value:
  876. Will return the cookie for the compound key
  877. Notes:
  878. (1) No thread safety. Caller must be aware.
  879. (2) Calling this function multiple times for the same cookie is safe because we will
  880. prevent it from being added more than once.
  881. */
  882. HRESULT
  883. CExtClassInstCookieList::AddCompKey (
  884. IN LPCWSTR pszCompKey,
  885. IN DWORD dwDefCookie,
  886. OUT DWORD * pdwNewCookie
  887. )
  888. {
  889. if (pdwNewCookie == NULL || pszCompKey == NULL || *pszCompKey == L'\0')
  890. {
  891. return WBEM_E_INVALID_PARAMETER;
  892. }
  893. HRESULT hr = WBEM_NO_ERROR;
  894. CCompoundKey* pKey = NULL;
  895. //
  896. // We really need a CCompoundKey object
  897. //
  898. hr = CreateCompoundKeyFromString(pszCompKey, &pKey);
  899. if (FAILED(hr))
  900. {
  901. *pdwNewCookie = INVALID_COOKIE;
  902. return hr;
  903. }
  904. //
  905. // make sure that we don't add duplicate keys
  906. //
  907. ExtClassCookieIterator it = m_mapCookies.find(pKey);
  908. if (it != m_mapCookies.end())
  909. {
  910. //
  911. // already there, just pass back the cookie
  912. //
  913. *pdwNewCookie = (*it).second;
  914. }
  915. else
  916. {
  917. //
  918. // not present in our map yet
  919. //
  920. *pdwNewCookie = dwDefCookie;
  921. if (dwDefCookie == INVALID_COOKIE)
  922. {
  923. if (m_dwMaxCookie + 1 == INVALID_COOKIE)
  924. {
  925. //
  926. // If the next cookie is INVALID_COOKIE, we need to search
  927. // for a free slot. This gets more expansive. But given that
  928. // it needs to reach 0xFFFFFFFF to have this happen, ordinary
  929. // situation won't get to this point.
  930. //
  931. hr = GetNextFreeCookie(pdwNewCookie);
  932. }
  933. else
  934. {
  935. *pdwNewCookie = ++m_dwMaxCookie;
  936. }
  937. }
  938. //
  939. // we need to maintain the other vector, which records the order at which
  940. // cookies are added (so that it can be preserved and used as access order)
  941. //
  942. if (SUCCEEDED(hr))
  943. {
  944. //
  945. // now, push the pair to the vector, it will take care of the memory
  946. //
  947. CookieKeyPair* pNewCookieKey = new CookieKeyPair;
  948. if (pNewCookieKey == NULL)
  949. {
  950. hr = WBEM_E_OUT_OF_MEMORY;
  951. }
  952. else
  953. {
  954. pNewCookieKey->dwCookie = *pdwNewCookie;
  955. pNewCookieKey->pKey = pKey;
  956. m_vecCookies.push_back(pNewCookieKey);
  957. //
  958. // the map takes the ownership of the memory of pKey
  959. //
  960. m_mapCookies.insert(MapExtClassCookie::value_type(pKey, *pdwNewCookie));
  961. pKey = NULL;
  962. }
  963. }
  964. }
  965. //
  966. // if we have added it to the map, pKey == NULL. So harmless
  967. //
  968. delete pKey;
  969. return hr;
  970. }
  971. /*
  972. Routine Description:
  973. Name:
  974. CExtClassInstCookieList::RemoveCompKey
  975. Functionality:
  976. Will remove the compound key (given by the string) from the store. This is just a helper
  977. not intended for outside use.
  978. Virtual:
  979. No.
  980. Arguments:
  981. pSceStore - the store
  982. pszSectionName - section name
  983. pszCompKey - the string version of the compound key to be removed from store
  984. Return Value:
  985. Will return the cookie for the compound key. INVALID_COOKIE indicate some failure to
  986. remove the compound key from the store.
  987. Notes:
  988. (1) No thread safety. Caller must be aware.
  989. */
  990. DWORD CExtClassInstCookieList::RemoveCompKey (
  991. IN CSceStore * pSceStore,
  992. IN LPCWSTR pszSectionName,
  993. IN LPCWSTR pszCompKey
  994. )
  995. {
  996. if (pszCompKey == NULL || *pszCompKey == L'\0')
  997. {
  998. return INVALID_COOKIE;
  999. }
  1000. //
  1001. // We really need a CCompoundKey object
  1002. //
  1003. CCompoundKey* pKey = NULL;
  1004. HRESULT hr = CreateCompoundKeyFromString(pszCompKey, &pKey);
  1005. if (FAILED(hr))
  1006. {
  1007. return INVALID_COOKIE;
  1008. }
  1009. ExtClassCookieIterator it = m_mapCookies.find(pKey);
  1010. DWORD dwCookie = INVALID_COOKIE;
  1011. if (it != m_mapCookies.end())
  1012. {
  1013. dwCookie = (*it).second;
  1014. }
  1015. if (pSceStore && dwCookie != INVALID_COOKIE)
  1016. {
  1017. //
  1018. // found! So, we need to erase it from our map and our vector.
  1019. // make sure that we release the compound key managed by the element
  1020. // of the map and then erase it!
  1021. //
  1022. //
  1023. // if anything goes wrong with deleting from store, then we don't do it
  1024. //
  1025. if (SUCCEEDED(DeleteKeyFromStore(pSceStore, pszSectionName, dwCookie)))
  1026. {
  1027. delete (*it).first;
  1028. m_mapCookies.erase(it);
  1029. //
  1030. // remove it from the vector, too. This is expensive. Again, don't release
  1031. // the pointer of pKey inside the vector's struct element since it's taken care
  1032. // of by the map's release.
  1033. //
  1034. CookieKeyIterator itCookieKey = m_vecCookies.begin();
  1035. while (itCookieKey != m_vecCookies.end() && (*itCookieKey)->dwCookie != dwCookie)
  1036. {
  1037. ++itCookieKey;
  1038. }
  1039. if (itCookieKey != m_vecCookies.end())
  1040. {
  1041. delete (*itCookieKey);
  1042. m_vecCookies.erase(itCookieKey);
  1043. }
  1044. }
  1045. }
  1046. return dwCookie;
  1047. }
  1048. /*
  1049. Routine Description:
  1050. Name:
  1051. CExtClassInstCookieList::Next
  1052. Functionality:
  1053. Enumeration
  1054. Virtual:
  1055. No.
  1056. Arguments:
  1057. pbstrCompoundKey - the string version of the compound key the enumeration finds. May be NULL.
  1058. pdwCookie - the cookie where the enumeration find. May be NULL.
  1059. pdwResumeHandle - hint for next enumeration (0 when start enumeration)
  1060. Return Value:
  1061. Success: WBEM_E_NO_ERROR
  1062. Failure: WBEM_S_NO_MORE_DATA if the enueration has reached the end
  1063. WBEM_E_INVALID_PARAMETER if pdwResumeHandle == NULL
  1064. Other errors may also occur.
  1065. Notes:
  1066. (1) No thread safety. Caller must be aware.
  1067. (2) Pass in 0 to start the first enuemration step
  1068. (3) If caller is only interested in the cookie, then pass pbstrCompoundKey == NULL
  1069. (4) Similarly, if the caller is only interested in the string version of the compounp key,
  1070. then pass pdwCookie.
  1071. */
  1072. HRESULT
  1073. CExtClassInstCookieList::Next (
  1074. OUT BSTR * pbstrCompoundKey,
  1075. OUT DWORD * pdwCookie,
  1076. IN OUT DWORD * pdwResumeHandle
  1077. )
  1078. {
  1079. if (pdwResumeHandle == NULL)
  1080. {
  1081. return WBEM_E_INVALID_PARAMETER;
  1082. }
  1083. HRESULT hr = WBEM_NO_ERROR;
  1084. //
  1085. // set some good default values
  1086. //
  1087. if (pbstrCompoundKey)
  1088. {
  1089. *pbstrCompoundKey = NULL;
  1090. }
  1091. if (pdwCookie)
  1092. {
  1093. *pdwCookie = INVALID_COOKIE;
  1094. }
  1095. if (*pdwResumeHandle >= m_vecCookies.size())
  1096. {
  1097. hr = WBEM_S_NO_MORE_DATA;
  1098. }
  1099. else
  1100. {
  1101. if (pbstrCompoundKey)
  1102. {
  1103. hr = CreateCompoundKeyString(pbstrCompoundKey, m_vecCookies[*pdwResumeHandle]->pKey);
  1104. }
  1105. if (pdwCookie)
  1106. {
  1107. *pdwCookie = m_vecCookies[*pdwResumeHandle]->dwCookie;
  1108. }
  1109. (*pdwResumeHandle)++;
  1110. }
  1111. return hr;
  1112. }
  1113. /*
  1114. Routine Description:
  1115. Name:
  1116. CExtClassInstCookieList::GetNextFreeCookie
  1117. Functionality:
  1118. A private helper to deal with cookie value overflow problem. Will search for
  1119. a unused slot for the next cookie.
  1120. Virtual:
  1121. No.
  1122. Arguments:
  1123. pdwCookie - will pass back the next available cookie
  1124. Return Value:
  1125. Success: WBEM_E_NO_ERROR
  1126. Failure: WBEM_E_OUT_OF_MEMORY or WBEM_E_INVALID_PARAMETER
  1127. Notes:
  1128. (1) No thread safety. Caller must be aware.
  1129. (2) ***Warning*** Don't use it directly!
  1130. */
  1131. HRESULT
  1132. CExtClassInstCookieList::GetNextFreeCookie (
  1133. OUT DWORD * pdwCookie
  1134. )
  1135. {
  1136. if (pdwCookie == NULL)
  1137. {
  1138. return WBEM_E_INVALID_PARAMETER;
  1139. }
  1140. ExtClassCookieIterator it = m_mapCookies.begin();
  1141. ExtClassCookieIterator itEnd = m_mapCookies.end();
  1142. int iCount = m_mapCookies.size();
  1143. //
  1144. // remember pigeon hole principle? iCount + 1 holes will definitely have one
  1145. // that is not occupied! So, we will find one in the first iCount + 1 indexes (1 -> iCount + 1)
  1146. //
  1147. //
  1148. // since we don't want 0, we will waste the first index
  1149. // for easy readability, I opt to wait this bit memory
  1150. //
  1151. BYTE *pdwUsedCookies = new BYTE[iCount + 2];
  1152. if (pdwUsedCookies == NULL)
  1153. {
  1154. return WBEM_E_OUT_OF_MEMORY;
  1155. }
  1156. //
  1157. // set all slots unused!
  1158. //
  1159. ::memset(pdwUsedCookies, 0, iCount + 2);
  1160. while(it != itEnd)
  1161. {
  1162. if ((*it).second <= iCount + 1)
  1163. {
  1164. pdwUsedCookies[(*it).second] = 1;
  1165. }
  1166. it++;
  1167. }
  1168. //
  1169. // look for holes from 1 --> iCount + 1
  1170. //
  1171. for (int i = 1; i <= iCount + 1; ++i)
  1172. {
  1173. if (pdwUsedCookies[i] == 0)
  1174. break;
  1175. }
  1176. delete [] pdwUsedCookies;
  1177. *pdwCookie = i;
  1178. return WBEM_NO_ERROR;
  1179. }
  1180. /*
  1181. Routine Description:
  1182. Name:
  1183. CExtClassInstCookieList::CreateCompoundKeyFromString
  1184. Functionality:
  1185. A private helper to deal with cookie value overflow problem. Will search for
  1186. a unused slot for the next cookie.
  1187. Virtual:
  1188. No.
  1189. Arguments:
  1190. pszCompKeyStr - string version of the compound key
  1191. ppCompKey - out-bound compound key if the string can be successfully interpreted as
  1192. compound key
  1193. Return Value:
  1194. Success: Any success code (use SUCCEEDED(hr) to test) indicates success.
  1195. Failure: any failure code indicates failure.
  1196. Notes:
  1197. (1) No thread safety. Caller must be aware.
  1198. (2) As normal, caller is responsible to release *ppCompKey.
  1199. */
  1200. HRESULT
  1201. CExtClassInstCookieList::CreateCompoundKeyFromString (
  1202. IN LPCWSTR pszCompKeyStr,
  1203. OUT CCompoundKey ** ppCompKey
  1204. )
  1205. {
  1206. if (ppCompKey == NULL || pszCompKeyStr == NULL || *pszCompKeyStr == L'\0')
  1207. {
  1208. return WBEM_E_INVALID_PARAMETER;
  1209. }
  1210. *ppCompKey = NULL;
  1211. HRESULT hr = WBEM_NO_ERROR;
  1212. //
  1213. // deal with NULL_KEY
  1214. //
  1215. bool bIsNullKey = _wcsicmp(pszCompKeyStr, pszNullKey) == 0;
  1216. if (bIsNullKey)
  1217. {
  1218. //
  1219. // CCompoundKey(0) creates a null key
  1220. //
  1221. *ppCompKey = new CCompoundKey(0);
  1222. if (*ppCompKey == NULL)
  1223. {
  1224. hr = WBEM_E_OUT_OF_MEMORY;
  1225. }
  1226. return hr;
  1227. }
  1228. if (m_pVecNames == NULL || m_pVecNames->size() == 0)
  1229. {
  1230. //
  1231. // in this case, you really have to pass in pszCompKeyStr as NULL_KEY.
  1232. //
  1233. return WBEM_E_INVALID_SYNTAX;
  1234. }
  1235. DWORD dwKeyPropCount = m_pVecNames->size();
  1236. *ppCompKey = new CCompoundKey(dwKeyPropCount);
  1237. if (*ppCompKey == NULL)
  1238. {
  1239. return WBEM_E_OUT_OF_MEMORY;
  1240. }
  1241. //
  1242. // ready to parse the string version of the compound key
  1243. //
  1244. //
  1245. // hold the key property name
  1246. //
  1247. LPWSTR pszName = NULL;
  1248. //
  1249. // hold the key property value
  1250. //
  1251. VARIANT* pVar = NULL;
  1252. //
  1253. // current parsing point
  1254. //
  1255. LPCWSTR pszCur = pszCompKeyStr;
  1256. //
  1257. // next token point
  1258. //
  1259. LPCWSTR pszNext;
  1260. pVar = new VARIANT;
  1261. if (pVar == NULL)
  1262. {
  1263. hr = WBEM_E_OUT_OF_MEMORY;
  1264. }
  1265. else
  1266. {
  1267. hr = ::ParseCompoundKeyString(pszCur, &pszName, pVar, &pszNext);
  1268. while (SUCCEEDED(hr) && hr != WBEM_S_FALSE)
  1269. {
  1270. //
  1271. // find the index to which the name occupies. Since the number of key properties
  1272. // are always relatively small, we opt not to use fancy algorithms for lookup
  1273. //
  1274. for (DWORD dwIndex = 0; dwIndex < dwKeyPropCount; dwIndex++)
  1275. {
  1276. if (_wcsicmp((*m_pVecNames)[dwIndex], pszName) == 0)
  1277. {
  1278. break;
  1279. }
  1280. }
  1281. //
  1282. // dwIndex >= dwKeyPropCount indicates that the name is not recognized!
  1283. //
  1284. //
  1285. // since we don't care about the names anymore, release it here
  1286. //
  1287. delete [] pszName;
  1288. pszName = NULL;
  1289. //
  1290. // a valid name, add it to the compound key, it takes the ownership of the variant memory
  1291. //
  1292. if (dwIndex < dwKeyPropCount)
  1293. {
  1294. //
  1295. // if successfully added, pVar will be set to NULL by the function
  1296. //
  1297. hr = (*ppCompKey)->AddKeyPropertyValue(dwIndex, &pVar);
  1298. }
  1299. else
  1300. {
  1301. //
  1302. // not recognized name, discard the variant, won't consider as an error
  1303. //
  1304. ::VariantClear(pVar);
  1305. delete pVar;
  1306. pVar = NULL;
  1307. }
  1308. //
  1309. // start our next around
  1310. //
  1311. if (SUCCEEDED(hr))
  1312. {
  1313. pVar = new VARIANT;
  1314. if (pVar == NULL)
  1315. {
  1316. hr = WBEM_E_OUT_OF_MEMORY;
  1317. }
  1318. }
  1319. if (SUCCEEDED(hr))
  1320. {
  1321. pszCur = pszNext;
  1322. hr = ::ParseCompoundKeyString(pszCur, &pszName, pVar, &pszNext);
  1323. }
  1324. }
  1325. //
  1326. // final cleanup, regarless of success
  1327. //
  1328. if (pVar)
  1329. {
  1330. ::VariantClear(pVar);
  1331. delete pVar;
  1332. }
  1333. }
  1334. //
  1335. // if error occurs, clean up our partially created compound key
  1336. //
  1337. if (FAILED(hr) && *ppCompKey != NULL)
  1338. {
  1339. delete *ppCompKey;
  1340. *ppCompKey = NULL;
  1341. }
  1342. return hr;
  1343. }
  1344. /*
  1345. Routine Description:
  1346. Name:
  1347. CExtClassInstCookieList::CreateCompoundKeyString
  1348. Functionality:
  1349. Given a compound key, the function creates a string version of the compound key
  1350. and pass it back to the caller.
  1351. Virtual:
  1352. No.
  1353. Arguments:
  1354. pszCompKeyStr - string version of the compound key
  1355. ppCompKey - out-bound compound key if the string can be successfully interpreted as
  1356. compound key
  1357. Return Value:
  1358. Success: Any success code (use SUCCEEDED(hr) to test) indicates success.
  1359. Failure: any failure code indicates failure.
  1360. Notes:
  1361. (1) No thread safety. Caller must be aware.
  1362. (2) As normal, caller is responsible to release *pbstrCompKey.
  1363. */
  1364. HRESULT
  1365. CExtClassInstCookieList::CreateCompoundKeyString (
  1366. OUT BSTR* pbstrCompKey,
  1367. IN const CCompoundKey* pKey
  1368. )
  1369. {
  1370. HRESULT hr = WBEM_NO_ERROR;
  1371. if (pbstrCompKey == NULL)
  1372. {
  1373. hr = WBEM_E_INVALID_PARAMETER;
  1374. }
  1375. //
  1376. // if no names, or 0 names, or no compound key, then return Null_Key
  1377. //
  1378. else if (m_pVecNames == NULL || m_pVecNames->size() == 0 || pKey == NULL)
  1379. {
  1380. *pbstrCompKey = ::SysAllocString(pszNullKey);
  1381. if (*pbstrCompKey == NULL)
  1382. {
  1383. hr = WBEM_E_OUT_OF_MEMORY;
  1384. }
  1385. }
  1386. else
  1387. {
  1388. *pbstrCompKey = NULL;
  1389. DWORD dwCount = m_pVecNames->size();
  1390. //
  1391. // Somehow, CComBSTR's += operator doesn't work inside loops for several
  1392. // compilations!
  1393. //
  1394. CComBSTR *pbstrParts = new CComBSTR[dwCount];
  1395. if (pbstrParts == NULL)
  1396. {
  1397. return WBEM_E_OUT_OF_MEMORY;
  1398. }
  1399. DWORD dwTotalLen = 0;
  1400. //
  1401. // for each key property, we will format the (prop, value) pair
  1402. // into prop<vt:value> format. All each individual prop<vt:value>
  1403. // will be saved in our arrary for later assembling.
  1404. //
  1405. for (DWORD dwIndex = 0; dwIndex < dwCount; dwIndex++)
  1406. {
  1407. //
  1408. // don't move these CComXXX out of the loop unless you know precisely
  1409. // what needs to be done for these ATL classes
  1410. //
  1411. CComVariant var;
  1412. hr = pKey->GetPropertyValue(dwIndex, &var);
  1413. if (FAILED(hr))
  1414. {
  1415. break;
  1416. }
  1417. CComBSTR bstrData;
  1418. //
  1419. // get the <vt:value> into bstrData
  1420. //
  1421. hr = ::FormatVariant(&var, &bstrData);
  1422. if (SUCCEEDED(hr))
  1423. {
  1424. //
  1425. // create the Name<vt:Value> formatted string
  1426. //
  1427. pbstrParts[dwIndex] = CComBSTR( (*m_pVecNames)[dwIndex] );
  1428. pbstrParts[dwIndex] += bstrData;
  1429. }
  1430. else
  1431. {
  1432. break;
  1433. }
  1434. dwTotalLen += wcslen(pbstrParts[dwIndex]);
  1435. }
  1436. //
  1437. // Do the final assembling - pack all the bstr's in pbstrParts into the
  1438. // out-bound parameter *pbstrCompKey
  1439. //
  1440. if (SUCCEEDED(hr) && hr != WBEM_S_FALSE)
  1441. {
  1442. *pbstrCompKey = ::SysAllocStringLen(NULL, dwTotalLen + 1);
  1443. if (*pbstrCompKey != NULL)
  1444. {
  1445. //
  1446. // current copying point
  1447. //
  1448. LPWSTR pszCur = *pbstrCompKey;
  1449. DWORD dwLen;
  1450. for (dwIndex = 0; dwIndex < dwCount; dwIndex++)
  1451. {
  1452. dwLen = wcslen(pbstrParts[dwIndex]);
  1453. ::memcpy(pszCur, (const void*)(LPCWSTR)(pbstrParts[dwIndex]), dwLen * sizeof(WCHAR));
  1454. pszCur += dwLen;
  1455. }
  1456. //
  1457. // 0 terminate it
  1458. //
  1459. (*pbstrCompKey)[dwTotalLen] = L'\0';
  1460. }
  1461. else
  1462. {
  1463. hr = WBEM_E_OUT_OF_MEMORY;
  1464. }
  1465. }
  1466. delete [] pbstrParts;
  1467. }
  1468. return hr;
  1469. }
  1470. /*
  1471. Routine Description:
  1472. Name:
  1473. CExtClassInstCookieList::Cleanup
  1474. Functionality:
  1475. Cleanup.
  1476. Virtual:
  1477. No.
  1478. Arguments:
  1479. none
  1480. Return Value:
  1481. none
  1482. Notes:
  1483. Since we want to clean up after some partial construction.
  1484. */
  1485. void
  1486. CExtClassInstCookieList::Cleanup ()
  1487. {
  1488. //
  1489. // all those heap CCompoundKey's are released here.
  1490. //
  1491. ExtClassCookieIterator it = m_mapCookies.begin();
  1492. ExtClassCookieIterator itEnd = m_mapCookies.end();
  1493. while(it != itEnd)
  1494. {
  1495. delete (*it).first;
  1496. it++;
  1497. }
  1498. m_mapCookies.clear();
  1499. //
  1500. // m_vecCookies's content (CookieKeyPair) has a compound key,
  1501. // but that memory is not managed by this vector, (released in the map cleanup above).
  1502. //
  1503. for (int i = 0; i < m_vecCookies.size(); i++)
  1504. {
  1505. delete m_vecCookies[i];
  1506. }
  1507. m_vecCookies.clear();
  1508. m_dwMaxCookie = 0;
  1509. m_dwCookieArrayCount = 0;
  1510. }