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.

6332 lines
128 KiB

  1. // persistmgr.cpp: implementation of the SCE provider persistence related classes
  2. // declared inside persistmgr.h.
  3. // Copyright (c)1997-2001 Microsoft Corporation
  4. //
  5. //////////////////////////////////////////////////////////////////////
  6. // original author: shawnwu
  7. // creation date: 1/3/2001
  8. #include "precomp.h"
  9. #include <wininet.h>
  10. #include "genericclass.h"
  11. #include "persistmgr.h"
  12. #include "requestobject.h"
  13. #include "extbase.h"
  14. //
  15. // some global constants
  16. //
  17. const WCHAR wchCookieSep = L':';
  18. const WCHAR wchTypeValSep = L':';
  19. const WCHAR wchValueSep = L':';
  20. const WCHAR wchParamSep = L',';
  21. const WCHAR wchTypeValLeft = L'<';
  22. const WCHAR wchTypeValRight = L'>';
  23. const WCHAR wchMethodLeft = L'(';
  24. const WCHAR wchMethodRight = L')';
  25. const WCHAR wchMethodSep = L';';
  26. const WCHAR wchCySeparator = L'.';
  27. const WCHAR wchQuote = L'\"';
  28. LPCWSTR pszListPrefix = L"A";
  29. LPCWSTR pszKeyPrefix = L"K";
  30. LPCWSTR pszAttachSectionValue = L"1";
  31. LPCWSTR pszNullKey = L"NULL_KEY";
  32. //
  33. // the types that we support
  34. //
  35. VtTypeStruct gVtTypeToStructArray[] =
  36. {
  37. {L"VT_BOOL", VT_BOOL},
  38. {L"VT_I2", VT_I2},
  39. {L"VT_I4", VT_I4},
  40. //{L"VT_I8", VT_I8},
  41. {L"VT_R4", VT_R4},
  42. {L"VT_R8", VT_R8},
  43. {L"VT_CY", VT_CY},
  44. {L"VT_DATE", VT_DATE},
  45. {L"VT_BSTR", VT_BSTR},
  46. {L"VT_UI1", VT_UI1},
  47. {L"VT_UI2", VT_UI2},
  48. {L"VT_UI4", VT_UI4}, // somehow, WMI doesn't work with VT_UI4
  49. {L"VT_UINT", VT_UINT},
  50. //{L"VT_UI8", VT_UI8},
  51. {L"VT_ARRAY(VT_BOOL)", VT_ARRAY | VT_BOOL},
  52. {L"VT_ARRAY(VT_I2)", VT_ARRAY | VT_I2},
  53. {L"VT_ARRAY(VT_I4)", VT_ARRAY | VT_I4},
  54. //{L"VT_ARRAY(VT_I8)", VT_ARRAY | VT_I8},
  55. {L"VT_ARRAY(VT_R4)", VT_ARRAY | VT_R4},
  56. {L"VT_ARRAY(VT_R8)", VT_ARRAY | VT_R8},
  57. {L"VT_ARRAY(VT_CY)", VT_ARRAY | VT_CY},
  58. {L"VT_ARRAY(VT_DATE)", VT_ARRAY | VT_DATE},
  59. {L"VT_ARRAY(VT_BSTR)", VT_ARRAY | VT_BSTR},
  60. {L"VT_ARRAY(VT_UI1)", VT_ARRAY | VT_UI1},
  61. {L"VT_ARRAY(VT_UI2)", VT_ARRAY | VT_UI2},
  62. {L"VT_ARRAY(VT_UI4)", VT_ARRAY | VT_I4}, // somehow, WMI doesn't work with VT_ARRAY(VT_UI4)
  63. {L"VT_ARRAY(VT_UINT)", VT_ARRAY | VT_UINT},
  64. //{L"VT_ARRAY(VT_UI8)", VT_ARRAY | VT_UI8},
  65. };
  66. /*
  67. Routine Description:
  68. Name:
  69. IsVT_Array
  70. Functionality:
  71. test if a VARTYPE is a safearray.
  72. Virtual:
  73. N/A.
  74. Arguments:
  75. vt - The VARTYPE to test.
  76. Return Value:
  77. true if yes, false if no.
  78. Notes:
  79. */
  80. bool
  81. IsVT_Array (
  82. IN VARTYPE vt
  83. )
  84. {
  85. return ( (vt & VT_ARRAY) == VT_ARRAY );
  86. }
  87. /*
  88. Routine Description:
  89. Name:
  90. GetSubType
  91. Functionality:
  92. Get the safearray's element type.
  93. Virtual:
  94. N/A.
  95. Arguments:
  96. vt - The VARTYPE to get the sub-type. The result is not defined if vt is not representing
  97. a safearray type.
  98. Return Value:
  99. true if yes, false if no.
  100. Notes:
  101. */
  102. VARTYPE
  103. GetSubType (
  104. IN VARTYPE vt
  105. )
  106. {
  107. return (vt & (~VT_ARRAY));
  108. }
  109. //
  110. // global instance of maps from string to vt and from vt to string
  111. //
  112. CMapVtToString gVtToStringMap(sizeof(gVtTypeToStructArray)/sizeof(VtTypeStruct), gVtTypeToStructArray);
  113. CMapStringToVt gStringToVtMap(sizeof(gVtTypeToStructArray)/sizeof(VtTypeStruct), gVtTypeToStructArray);
  114. /*
  115. Routine Description:
  116. Name:
  117. IsEscapedChar
  118. Functionality:
  119. test if the wchar is a char that we need to be escaped.
  120. Virtual:
  121. N/A.
  122. Arguments:
  123. ch - The wchar to test.
  124. Return Value:
  125. true if yes, false if no.
  126. Notes:
  127. */
  128. bool
  129. IsEscapedChar (
  130. IN WCHAR ch
  131. )
  132. {
  133. return (ch == L'\\' || ch == L'"');
  134. }
  135. /*
  136. Routine Description:
  137. Name:
  138. GetEscapeCharCount
  139. Functionality:
  140. will return the count of characters that needs to be escaped - determined by
  141. ::IsEscapedChar function
  142. Virtual:
  143. N/A.
  144. Arguments:
  145. pszStr - The string to count the escape characters.
  146. Return Value:
  147. The count of escape characters.
  148. Notes:
  149. */
  150. DWORD
  151. GetEscapeCharCount (
  152. IN LPCWSTR pszStr
  153. )
  154. {
  155. DWORD dwCount = 0;
  156. while (*pszStr != L'\0')
  157. {
  158. if (::IsEscapedChar(*pszStr))
  159. {
  160. ++dwCount;
  161. }
  162. ++pszStr;
  163. }
  164. return dwCount;
  165. };
  166. /*
  167. Routine Description:
  168. Name:
  169. TrimCopy
  170. Functionality:
  171. Will copy the portion from pSource that is of length iLen. The difference is
  172. that the result string won't have leading and trailing white spaces (determined
  173. by iswspace)
  174. Virtual:
  175. N/A.
  176. Arguments:
  177. pDest - Receives the copied sub-string.
  178. pSource - The source.
  179. iLen - The length the sub-string is.
  180. Return Value:
  181. None.
  182. Notes:
  183. Caller must guarantee pSource/pDest to have enough room, including the L'\0'. That is
  184. the buffer size is >= iLen + 1.
  185. */
  186. void
  187. TrimCopy (
  188. OUT LPWSTR pDest,
  189. IN LPCWSTR pSource,
  190. IN int iLen
  191. )
  192. {
  193. LPCWSTR pHead = pSource;
  194. //
  195. // avoid modifying iLen
  196. //
  197. int iRealLen = iLen;
  198. //
  199. // skip the leading white spaces. Make sure that our target
  200. // is decreasing at the same rate.
  201. while (*pHead != L'\0' && iswspace(*pHead) && iRealLen)
  202. {
  203. ++pHead;
  204. --iRealLen;
  205. }
  206. if (iRealLen <= 0)
  207. {
  208. pDest[0] = L'\0';
  209. }
  210. else
  211. {
  212. //
  213. // caller guarantees the pDest if long enough
  214. //
  215. wcsncpy(pDest, pHead, iRealLen);
  216. while (iLen > 1 && iswspace(pDest[iRealLen - 1]))
  217. {
  218. --iRealLen;
  219. }
  220. //
  221. // 0 terminate it
  222. //
  223. pDest[iRealLen] = '\0';
  224. }
  225. };
  226. /*
  227. Routine Description:
  228. Name:
  229. EscSeekToChar
  230. Functionality:
  231. Will find the target character (wchChar) in the pszSource. If found, the return
  232. pointer points to that character. Any backslash characeter L'\\' will cause an escape.
  233. If such escape happens, then pbEscaped parameter will pass back true.
  234. If no escape is found, then, pbEscaped will pass back false. The return result in case of
  235. of no escape depends on bEndIfNotFound. If bEndIfNotFound is true, then the return value
  236. points to the 0 terminator the source pszSource, otherwise, it returns NULL.
  237. This escaping won't happen if the special characters (wchChar and the escaped chars) are
  238. inside a quoted string.
  239. Virtual:
  240. N/A.
  241. Arguments:
  242. pszSource - source.
  243. wchChar - The sought wchar.
  244. pbEscaped - passback whether it has really been escaped.
  245. bEndIfNotFound - whether we should return the end of the source or not
  246. if the sought char is not found
  247. Return Value:
  248. If the wchar is not found:
  249. NULL if bEndIfNotFound == false;
  250. End of the source if bEndIfNotFound == true;
  251. If the wchar is found:
  252. address of the sought character.
  253. Notes:
  254. User must pass in valid parameter values.
  255. */
  256. LPCWSTR
  257. EscSeekToChar (
  258. IN LPCWSTR pszSource,
  259. IN WCHAR wchChar,
  260. OUT bool * pbEscaped,
  261. IN bool bEndIfNotFound
  262. )
  263. {
  264. *pbEscaped = false;
  265. //
  266. // flag if we are currently escaping
  267. //
  268. bool bIsEscaping = false;
  269. //
  270. // flag if we are currently inside a quoted string
  271. //
  272. bool bIsInsideQuote = false;
  273. while (*pszSource != L'\0')
  274. {
  275. if (bIsEscaping)
  276. {
  277. bIsEscaping = false;
  278. ++pszSource;
  279. }
  280. else if (*pszSource == L'\\')
  281. {
  282. ++pszSource;
  283. bIsEscaping = true;
  284. *pbEscaped = true;
  285. }
  286. else if (*pszSource == wchChar && !bIsInsideQuote)
  287. {
  288. //
  289. // found it
  290. //
  291. return pszSource;
  292. }
  293. else
  294. {
  295. //
  296. // see if we are starting a quoted section
  297. //
  298. if (*pszSource == L'"')
  299. {
  300. bIsInsideQuote = !bIsInsideQuote;
  301. }
  302. ++pszSource;
  303. }
  304. }
  305. if (bEndIfNotFound)
  306. {
  307. return pszSource;
  308. }
  309. else
  310. {
  311. return NULL;
  312. }
  313. }
  314. /*
  315. Routine Description:
  316. Name:
  317. EscapeStringData
  318. Functionality:
  319. Given source (pszStr) string, we will produce a destination string, which will
  320. have the backslash character added in front of the characters that need escape.
  321. Virtual:
  322. N/A.
  323. Arguments:
  324. pszStr - source.
  325. pbstr - receives the result.
  326. bQuote - flag if we should quote the result string or not.
  327. Return Value:
  328. Success: WBEM_NO_ERROR
  329. Failure: (1) WBEM_E_INVALID_PARAMETER.
  330. (2) WBEM_E_OUT_OF_MEMORY.
  331. Notes:
  332. */
  333. HRESULT
  334. EscapeStringData (
  335. IN LPCWSTR pszStr,
  336. OUT BSTR * pbstr,
  337. IN bool bQuote
  338. )
  339. {
  340. if (pszStr == NULL || pbstr == NULL)
  341. {
  342. return WBEM_E_INVALID_PARAMETER;
  343. }
  344. DWORD dwEscCharCount = GetEscapeCharCount(pszStr);
  345. DWORD dwStrLen = wcslen(pszStr);
  346. DWORD dwTotalLen = dwStrLen + dwEscCharCount + (bQuote ? 2 : 0) + 1;
  347. *pbstr = ::SysAllocStringLen(NULL, dwTotalLen);
  348. if (*pbstr == NULL)
  349. {
  350. return WBEM_E_OUT_OF_MEMORY;
  351. }
  352. //
  353. // nothing to escape
  354. //
  355. if (dwEscCharCount == 0)
  356. {
  357. //
  358. // add quote if necessary
  359. //
  360. LPWSTR lpszCur = *pbstr;
  361. if (bQuote)
  362. {
  363. lpszCur[0] = wchQuote;
  364. ++lpszCur;
  365. }
  366. ::memcpy(lpszCur, pszStr, dwStrLen * sizeof(WCHAR));
  367. if (bQuote)
  368. {
  369. (*pbstr)[dwTotalLen - 2] = wchQuote;
  370. }
  371. (*pbstr)[dwTotalLen - 1] = L'\0';
  372. }
  373. else
  374. {
  375. //
  376. // do some real escaping here
  377. //
  378. LPWSTR pszCur = *pbstr;
  379. //
  380. // add L'\"' if necessary
  381. //
  382. if (bQuote)
  383. {
  384. *pszCur = wchQuote;
  385. ++pszCur;
  386. }
  387. //
  388. // do escaping copy
  389. //
  390. bool bIsEscaping = false;
  391. while (*pszStr != L'\0')
  392. {
  393. if (!bIsEscaping && ::IsEscapedChar(*pszStr))
  394. {
  395. *pszCur = L'\\';
  396. ++pszCur;
  397. }
  398. if (!bIsEscaping && *pszStr == L'\\')
  399. {
  400. bIsEscaping = true;
  401. }
  402. else if (bIsEscaping)
  403. {
  404. bIsEscaping = false;
  405. }
  406. *pszCur = *pszStr;
  407. ++pszCur;
  408. ++pszStr;
  409. }
  410. //
  411. // add L'\"' if necessary
  412. //
  413. if (bQuote)
  414. {
  415. *pszCur = wchQuote;
  416. ++pszCur;
  417. }
  418. *pszCur = L'\0';
  419. }
  420. return WBEM_NO_ERROR;
  421. }
  422. /*
  423. Routine Description:
  424. Name:
  425. DeEscapeStringData
  426. Functionality:
  427. Inverse of EscapeStringData. See EscapeStringData for functionality.
  428. Virtual:
  429. N/A.
  430. Arguments:
  431. pszStr - source.
  432. pbstr - receives the result.
  433. bQuote - flag if we should get rid of the startind and ending quote.
  434. Return Value:
  435. Success: WBEM_NO_ERROR
  436. Failure: (1) WBEM_E_INVALID_PARAMETER.
  437. (2) WBEM_E_OUT_OF_MEMORY.
  438. Notes:
  439. */
  440. HRESULT
  441. DeEscapeStringData (
  442. IN LPCWSTR pszStr,
  443. OUT BSTR * pbstr,
  444. IN bool bTrimQuote
  445. )
  446. {
  447. if (pszStr == NULL || pbstr == NULL)
  448. {
  449. return WBEM_E_INVALID_PARAMETER;
  450. }
  451. *pbstr = NULL;
  452. DWORD dwLen = wcslen(pszStr);
  453. LPCWSTR pszCurSrc = pszStr;
  454. //
  455. // there is a start quote
  456. //
  457. if (bTrimQuote && *pszCurSrc == wchQuote)
  458. {
  459. //
  460. // there must be an ending quote
  461. //
  462. if (dwLen < 2 || pszCurSrc[dwLen - 1] != wchQuote)
  463. {
  464. return WBEM_E_INVALID_PARAMETER;
  465. }
  466. //
  467. // skip the leading quote
  468. //
  469. ++pszCurSrc;
  470. //
  471. // need two characters less
  472. //
  473. dwLen -= 2;
  474. }
  475. *pbstr = ::SysAllocStringLen(NULL, dwLen + 1);
  476. if (*pbstr != NULL)
  477. {
  478. LPWSTR pszCur = *pbstr;
  479. do
  480. {
  481. if (*pszCurSrc == L'\\')
  482. {
  483. //
  484. // escape it
  485. //
  486. ++pszCurSrc;
  487. }
  488. *pszCur = *pszCurSrc;
  489. ++pszCur;
  490. if (*pszCurSrc == L'\0')
  491. {
  492. break;
  493. }
  494. ++pszCurSrc;
  495. } while ((pszCurSrc - pszStr) <= dwLen);
  496. *pszCur = L'\0';
  497. }
  498. return (*pbstr != NULL) ? WBEM_NO_ERROR : WBEM_E_OUT_OF_MEMORY;
  499. }
  500. //=========================================================================
  501. /*
  502. Routine Description:
  503. Name:
  504. CMapStringToVt::CMapStringToVt
  505. Functionality:
  506. constructor. We will create the map using the passed in array information.
  507. Virtual:
  508. No.
  509. Arguments:
  510. dwCount - The count of the array pInfoArray.
  511. pInfoArray - The array that has the information.
  512. Return Value:
  513. none
  514. Notes:
  515. Caller must guarantee that pInfoArray is at least as many elements as dwCount.
  516. */
  517. CMapStringToVt::CMapStringToVt (
  518. IN DWORD dwCount,
  519. IN VtTypeStruct * pInfoArray
  520. )
  521. {
  522. for (DWORD dwIndex = 0; dwIndex < dwCount; ++dwIndex)
  523. {
  524. m_Map.insert(MapStringToVt::value_type(pInfoArray[dwIndex].pszVtTypeString, pInfoArray[dwIndex].vt));
  525. }
  526. }
  527. /*
  528. Routine Description:
  529. Name:
  530. CMapStringToVt::GetType
  531. Functionality:
  532. Given the string version of variant type information, translate it to VARTYPE value.
  533. Virtual:
  534. No.
  535. Arguments:
  536. pszTypeStr - The string version of the VARTYPE info.
  537. pSubType - The array element's type if pszTypeStr is an array's type string.
  538. Return Value:
  539. If pszTypeStr is in correct format, we return the appropriate VARTYPE.
  540. Otherwise, we return VT_EMPTY
  541. Notes:
  542. */
  543. VARTYPE CMapStringToVt::GetType (
  544. IN LPCWSTR pszTypeStr,
  545. OUT VARTYPE * pSubType OPTIONAL
  546. )
  547. {
  548. //
  549. // look up
  550. //
  551. MapStringToVt::iterator it = m_Map.find(pszTypeStr);
  552. if (pSubType)
  553. {
  554. *pSubType = VT_EMPTY;
  555. }
  556. if (it != m_Map.end())
  557. {
  558. VARTYPE vt = (*it).second;
  559. if (::IsVT_Array(vt))
  560. {
  561. if (pSubType)
  562. {
  563. *pSubType = ::GetSubType(vt);
  564. }
  565. return VT_ARRAY;
  566. }
  567. else
  568. {
  569. return vt;
  570. }
  571. }
  572. return VT_EMPTY;
  573. }
  574. /*
  575. Routine Description:
  576. Name:
  577. CMapVtToString::CMapVtToString
  578. Functionality:
  579. Constructor. We will create the map.
  580. Virtual:
  581. No.
  582. Arguments:
  583. dwCount - The count of the array pInfoArray.
  584. pInfoArray - The array that has the information.
  585. Return Value:
  586. None.
  587. Notes:
  588. Caller must guarantee that pInfoArray is at least as many elements as dwCount.
  589. */
  590. CMapVtToString::CMapVtToString (
  591. IN DWORD dwCount,
  592. IN VtTypeStruct * pInfoArray
  593. )
  594. {
  595. for (DWORD dwIndex = 0; dwIndex < dwCount; ++dwIndex)
  596. m_Map.insert(MapVtToString::value_type(pInfoArray[dwIndex].vt, pInfoArray[dwIndex].pszVtTypeString));
  597. }
  598. /*
  599. Routine Description:
  600. Name:
  601. CMapVtToString::GetTypeString
  602. Functionality:
  603. Given VARTYPE and (if vt == VT_ARRAY) array element's type, it returns
  604. our formatted string representation of the type.
  605. Virtual:
  606. No.
  607. Arguments:
  608. vt - The VARTYPE.
  609. vtSub - The array's element's type if vt == VT_ARRAY. Otherwise, it's ignored.
  610. Return Value:
  611. NULL if the type is not supported.
  612. The global string. As the prototype indicates, this return value is constant.
  613. Notes:
  614. If vt == VT_ARRAY, then vtSub must contain a valid vt type that we support
  615. */
  616. LPCWSTR
  617. CMapVtToString::GetTypeString (
  618. IN VARTYPE vt,
  619. IN VARTYPE vtSub
  620. )
  621. {
  622. MapVtToString::iterator it;
  623. if (::IsVT_Array(vt))
  624. {
  625. it = m_Map.find(vt | vtSub);
  626. }
  627. else
  628. {
  629. it = m_Map.find(vt);
  630. }
  631. if (it != m_Map.end())
  632. {
  633. return (*it).second;
  634. }
  635. return NULL;
  636. }
  637. /*
  638. Routine Description:
  639. Name:
  640. CMapVtToString::GetTypeString
  641. Functionality:
  642. Given VARTYPE, it returns our formatted string representation of the type.
  643. Virtual:
  644. No.
  645. Arguments:
  646. vt - The VARTYPE.
  647. Return Value:
  648. NULL if the type is not supported.
  649. The global string. As the prototype indicates, this return value is constant.
  650. Notes:
  651. (1) If vt == VT_ARRAY, then vtSub must contain a valid vt type that we support.
  652. (2) This version of the override doesn't work for array types.
  653. */
  654. LPCWSTR
  655. CMapVtToString::GetTypeString (
  656. IN VARTYPE vt
  657. )
  658. {
  659. MapVtToString::iterator it = m_Map.find(vt);
  660. if (it != m_Map.end())
  661. {
  662. return (*it).second;
  663. }
  664. else
  665. {
  666. return NULL;
  667. }
  668. }
  669. //=========================================================================
  670. // implementations for class CScePropertyMgr
  671. /*
  672. Routine Description:
  673. Name:
  674. CScePropertyMgr::CScePropertyMgr
  675. Functionality:
  676. constructor. Trivial
  677. Virtual:
  678. No.
  679. Arguments:
  680. None.
  681. Return Value:
  682. none
  683. Notes:
  684. Consider initializing additional members if you need to add them.
  685. */
  686. CScePropertyMgr::CScePropertyMgr ()
  687. {
  688. }
  689. /*
  690. Routine Description:
  691. Name:
  692. CScePropertyMgr::~CScePropertyMgr
  693. Functionality:
  694. Destructor. Trivial since we only have smart pointer members that automatically initialize themselves.
  695. Virtual:
  696. No. Since we never intend to have sub-classes.
  697. Arguments:
  698. None.
  699. Return Value:
  700. none
  701. Notes:
  702. Consider freeing additional members if you need to add them.
  703. */
  704. CScePropertyMgr::~CScePropertyMgr()
  705. {
  706. }
  707. /*
  708. Routine Description:
  709. Name:
  710. CScePropertyMgr::Attach
  711. Functionality:
  712. Attach the object to our property manager. You can safely reattach another
  713. object to this manager.
  714. Virtual:
  715. No.
  716. Arguments:
  717. pObj - the object this manager will be attached to.
  718. Return Value:
  719. none
  720. Notes:
  721. Caller must not call any property access functions until a valid attachment has
  722. been established.
  723. */
  724. void
  725. CScePropertyMgr::Attach (
  726. IN IWbemClassObject *pObj
  727. )
  728. {
  729. m_srpClassObj.Release();
  730. m_srpClassObj = pObj;
  731. }
  732. /*
  733. Routine Description:
  734. Name:
  735. CScePropertyMgr::PutProperty
  736. Functionality:
  737. Put a variant property for the given property.
  738. Virtual:
  739. No.
  740. Arguments:
  741. pszProperty - The property's name.
  742. pVar - The value for the property.
  743. Return Value:
  744. Whatever IWbemClassObject::Put returns.
  745. Notes:
  746. */
  747. HRESULT
  748. CScePropertyMgr::PutProperty (
  749. IN LPCWSTR pszProperty,
  750. IN VARIANT * pVar
  751. )
  752. {
  753. return m_srpClassObj->Put(pszProperty, 0, pVar, CIM_EMPTY);
  754. }
  755. /*
  756. Routine Description:
  757. Name:
  758. CScePropertyMgr::PutProperty
  759. Functionality:
  760. Put a string valued property for the given property.
  761. Virtual:
  762. No.
  763. Arguments:
  764. pszProperty - The property's name.
  765. pszValue - The string value for the property.
  766. Return Value:
  767. Success: Whatever IWbemClassObject::Put returns.
  768. Failure: Either WBEM_E_OUT_OF_MEMORY or whatever IWbemClassObject::Put returns.
  769. Notes:
  770. */
  771. HRESULT
  772. CScePropertyMgr::PutProperty (
  773. IN LPCWSTR pszProperty,
  774. IN LPCWSTR pszValue
  775. )
  776. {
  777. HRESULT hr = WBEM_NO_ERROR;
  778. //
  779. // WMI always wants variant
  780. //
  781. CComVariant var(pszValue);
  782. if (var.vt != VT_ERROR)
  783. {
  784. hr = m_srpClassObj->Put(pszProperty, 0, &var, CIM_EMPTY);
  785. }
  786. else
  787. {
  788. hr = WBEM_E_OUT_OF_MEMORY;
  789. }
  790. return hr;
  791. }
  792. /*
  793. Routine Description:
  794. Name:
  795. CScePropertyMgr::PutProperty
  796. Functionality:
  797. Put an integral valued property for the given property.
  798. Virtual:
  799. No.
  800. Arguments:
  801. pszProperty - The property's name.
  802. dwValue - The value for the property. SCE_NULL_INTEGER is an invalid SCE integral value
  803. Return Value:
  804. Success: Whatever IWbemClassObject::Put returns.
  805. Failure: whatever IWbemClassObject::Put returns.
  806. Notes:
  807. We have observed that WMI will always promote all 4-byte integral types to VT_I4.
  808. */
  809. HRESULT
  810. CScePropertyMgr::PutProperty (
  811. IN LPCWSTR pszProperty,
  812. IN DWORD dwValue
  813. )
  814. {
  815. HRESULT hr = WBEM_NO_ERROR;
  816. //
  817. // no need to worry about resource leaking, so, use straight forward variant
  818. //
  819. VARIANT var;
  820. V_VT(&var) = VT_I4;
  821. if (dwValue == SCE_NULL_INTEGER)
  822. {
  823. hr = WBEM_E_INVALID_PARAMETER;
  824. }
  825. else
  826. {
  827. V_I4(&var) = dwValue;
  828. hr = m_srpClassObj->Put(pszProperty, 0, &var, CIM_EMPTY);
  829. }
  830. return hr;
  831. }
  832. /*
  833. Routine Description:
  834. Name:
  835. CScePropertyMgr::PutProperty
  836. Functionality:
  837. Put an float valued property for the given property.
  838. Virtual:
  839. No.
  840. Arguments:
  841. pszProperty - The property's name.
  842. fValue - The value for the property.
  843. Return Value:
  844. Success: Whatever IWbemClassObject::Put returns.
  845. Failure: whatever IWbemClassObject::Put returns.
  846. Notes:
  847. */
  848. HRESULT
  849. CScePropertyMgr::PutProperty (
  850. IN LPCWSTR pszProperty,
  851. IN float fValue
  852. )
  853. {
  854. //
  855. // no need to worry about resource leaking, so, use straight forward variant
  856. //
  857. VARIANT var;
  858. V_VT(&var) = VT_R4;
  859. V_R4(&var) = fValue;
  860. return m_srpClassObj->Put(pszProperty, 0, &var, CIM_EMPTY);
  861. }
  862. /*
  863. Routine Description:
  864. Name:
  865. CScePropertyMgr::PutProperty
  866. Functionality:
  867. Put a double value property for the given property.
  868. Virtual:
  869. No.
  870. Arguments:
  871. pszProperty - The property's name.
  872. dValue - The value for the property.
  873. Return Value:
  874. Success: Whatever IWbemClassObject::Put returns.
  875. Failure: whatever IWbemClassObject::Put returns.
  876. Notes:
  877. */
  878. HRESULT
  879. CScePropertyMgr::PutProperty (
  880. IN LPCWSTR pszProperty,
  881. IN double dValue
  882. )
  883. {
  884. //
  885. // no need to worry about resource leaking, so, use straight forward variant
  886. //
  887. VARIANT var;
  888. V_VT(&var) = VT_R8;
  889. V_DATE(&var) = dValue;
  890. return m_srpClassObj->Put(pszProperty, 0, &var, CIM_DATETIME);
  891. }
  892. /*
  893. Routine Description:
  894. Name:
  895. CScePropertyMgr::PutProperty
  896. Functionality:
  897. Put a boolean value property for the given property.
  898. Virtual:
  899. No.
  900. Arguments:
  901. pszProperty - The property's name.
  902. bValue - The value for the property.
  903. Return Value:
  904. Success: Whatever IWbemClassObject::Put returns.
  905. Failure: whatever IWbemClassObject::Put returns.
  906. Notes:
  907. */
  908. HRESULT
  909. CScePropertyMgr::PutProperty (
  910. IN LPCWSTR pszProperty,
  911. IN bool bValue
  912. )
  913. {
  914. //
  915. // no need to worry about resource leaking, so, use straight forward variant
  916. //
  917. VARIANT var;
  918. V_VT(&var) = VT_BOOL;
  919. V_BOOL(&var) = bValue ? VARIANT_TRUE : VARIANT_FALSE;
  920. return m_srpClassObj->Put(pszProperty, 0, &var, CIM_EMPTY);
  921. }
  922. /*
  923. Routine Description:
  924. Name:
  925. CScePropertyMgr::PutProperty
  926. Functionality:
  927. Put a name list (string) value property for the given property.
  928. Virtual:
  929. No.
  930. Arguments:
  931. pszProperty - The property's name.
  932. strList - A SCE specific linked list.
  933. Return Value:
  934. Success: Whatever IWbemClassObject::Put returns.
  935. Failure: whatever IWbemClassObject::Put returns.
  936. Notes:
  937. */
  938. HRESULT
  939. CScePropertyMgr::PutProperty (
  940. IN LPCWSTR pszProperty,
  941. IN PSCE_NAME_LIST strList
  942. )
  943. {
  944. //
  945. // make sure that our parameters are in good shape to proceed
  946. //
  947. if (NULL == pszProperty || *pszProperty == 0 || NULL == strList)
  948. {
  949. return WBEM_E_INVALID_PARAMETER;
  950. }
  951. else if (NULL == strList)
  952. {
  953. //
  954. // nothing to save
  955. //
  956. return WBEM_NO_ERROR;
  957. }
  958. HRESULT hr = WBEM_NO_ERROR;
  959. //
  960. // find count of the list
  961. //
  962. long lCount = 0;
  963. PSCE_NAME_LIST pTemp;
  964. for ( pTemp = strList; pTemp != NULL; pTemp=pTemp->Next)
  965. {
  966. lCount++;
  967. }
  968. if ( lCount == 0 )
  969. {
  970. //
  971. // nothing to save
  972. //
  973. return hr;
  974. }
  975. CComVariant varValueArray;
  976. //
  977. // create a bstr safearray
  978. //
  979. SAFEARRAYBOUND sbArrayBounds ;
  980. sbArrayBounds.cElements = lCount;
  981. sbArrayBounds.lLbound = 0;
  982. //
  983. // will put all the names inside SCE_NAME_LIST into the safe array
  984. //
  985. if (V_ARRAY(&varValueArray) = ::SafeArrayCreate(VT_BSTR, 1, &sbArrayBounds))
  986. {
  987. V_VT(&varValueArray) = VT_BSTR | VT_ARRAY ;
  988. pTemp = strList;
  989. for (long j = 0; SUCCEEDED(hr) && pTemp != NULL ; pTemp=pTemp->Next)
  990. {
  991. CComVariant varVal(pTemp->Name);
  992. if (varVal.vt == VT_BSTR)
  993. {
  994. hr = ::SafeArrayPutElement(V_ARRAY(&varValueArray), &j, varVal.bstrVal);
  995. }
  996. else
  997. {
  998. hr = WBEM_E_OUT_OF_MEMORY;
  999. break;
  1000. }
  1001. j++;
  1002. }
  1003. //
  1004. // only put if we succeeded in the previous actions
  1005. //
  1006. if (SUCCEEDED(hr))
  1007. {
  1008. hr = m_srpClassObj->Put(pszProperty, 0, &varValueArray, CIM_EMPTY);
  1009. }
  1010. }
  1011. else
  1012. {
  1013. hr = WBEM_E_FAILED;
  1014. }
  1015. return hr;
  1016. }
  1017. /*
  1018. Routine Description:
  1019. Name:
  1020. CScePropertyMgr::GetProperty
  1021. Functionality:
  1022. Get the property's value in variant form.
  1023. Virtual:
  1024. No.
  1025. Arguments:
  1026. pszProperty - The property's name.
  1027. pVar - receives the value.
  1028. Return Value:
  1029. Success: Whatever IWbemClassObject::Get returns.
  1030. Failure: whatever IWbemClassObject::Get returns.
  1031. Notes:
  1032. */
  1033. HRESULT
  1034. CScePropertyMgr::GetProperty (
  1035. IN LPCWSTR pszProperty,
  1036. OUT VARIANT * pVar
  1037. )
  1038. {
  1039. return m_srpClassObj->Get(pszProperty, 0, pVar, NULL, NULL);
  1040. }
  1041. /*
  1042. Routine Description:
  1043. Name:
  1044. CScePropertyMgr::GetProperty
  1045. Functionality:
  1046. Get the property's value in bstr form.
  1047. Virtual:
  1048. No.
  1049. Arguments:
  1050. pszProperty - The property's name.
  1051. pbstrValues - receives bstr value.
  1052. Return Value:
  1053. Success: Whatever IWbemClassObject::Get returns, or
  1054. WBEM_S_RESET_TO_DEFAULT if the value is not returned from the wbem object.
  1055. Failure: whatever IWbemClassObject::Get returns.
  1056. Notes:
  1057. Caller must not pass NULL for the out parameter.
  1058. Caller is responsible for releasing the received bstr.
  1059. */
  1060. HRESULT
  1061. CScePropertyMgr::GetProperty (
  1062. IN LPCWSTR pszProperty,
  1063. OUT BSTR * pbstrValue
  1064. )
  1065. {
  1066. *pbstrValue = NULL;
  1067. //
  1068. // we don't know what this Get will give us, but we are asking for BSTR
  1069. // so, let the CComVariant take care of the resource issues
  1070. CComVariant varVal;
  1071. HRESULT hr = m_srpClassObj->Get(pszProperty, 0, &varVal, NULL, NULL);
  1072. if (varVal.vt == VT_BSTR && wcslen(varVal.bstrVal) > INTERNET_MAX_PATH_LENGTH)
  1073. {
  1074. hr = WBEM_E_INVALID_METHOD_PARAMETERS;
  1075. }
  1076. else if (varVal.vt == VT_BSTR)
  1077. {
  1078. *pbstrValue = ::SysAllocString(varVal.bstrVal);
  1079. if (*pbstrValue == NULL)
  1080. {
  1081. hr = WBEM_E_OUT_OF_MEMORY;
  1082. }
  1083. }
  1084. else if(varVal.vt == VT_EMPTY || varVal.vt == VT_NULL )
  1085. {
  1086. hr = WBEM_S_RESET_TO_DEFAULT;
  1087. }
  1088. return hr;
  1089. }
  1090. /*
  1091. Routine Description:
  1092. Name:
  1093. CScePropertyMgr::GetProperty
  1094. Functionality:
  1095. Get the property's value in DWORD form.
  1096. Virtual:
  1097. No.
  1098. Arguments:
  1099. pszProperty - The property's name.
  1100. pdwValue - receives DWORD value.
  1101. Return Value:
  1102. Success: Whatever IWbemClassObject::Get returns, or
  1103. WBEM_S_RESET_TO_DEFAULT if the value is not returned from the wbem object.
  1104. Failure: whatever IWbemClassObject::Get returns.
  1105. Notes:
  1106. Caller must not pass NULL for the out parameter.
  1107. */
  1108. HRESULT
  1109. CScePropertyMgr::GetProperty (
  1110. IN LPCWSTR pszProperty,
  1111. OUT DWORD * pdwValue
  1112. )
  1113. {
  1114. //
  1115. // this is a unusable integer for SCE
  1116. //
  1117. *pdwValue = SCE_NULL_INTEGER;
  1118. //
  1119. // we are asking for int, but Get may not give us that
  1120. //
  1121. CComVariant var;
  1122. HRESULT hr = m_srpClassObj->Get(pszProperty, 0, &var, NULL, NULL);
  1123. if (SUCCEEDED(hr))
  1124. {
  1125. if (var.vt == VT_I4)
  1126. {
  1127. *pdwValue = var.lVal;
  1128. }
  1129. else if (var.vt == VT_UI4)
  1130. {
  1131. *pdwValue = var.ulVal;
  1132. }
  1133. else if (var.vt == VT_BOOL)
  1134. {
  1135. *pdwValue = (var.boolVal == VARIANT_TRUE) ? 1 : 0;
  1136. }
  1137. else if (var.vt == VT_EMPTY || var.vt == VT_NULL )
  1138. {
  1139. *pdwValue = SCE_NO_VALUE;
  1140. hr = WBEM_S_RESET_TO_DEFAULT;
  1141. }
  1142. }
  1143. return hr;
  1144. }
  1145. /*
  1146. Routine Description:
  1147. Name:
  1148. CScePropertyMgr::GetProperty
  1149. Functionality:
  1150. Get the property's value in boolean form.
  1151. Virtual:
  1152. No.
  1153. Arguments:
  1154. pszProperty - The property's name.
  1155. pbValue - receives DWORD value.
  1156. Return Value:
  1157. Success: Whatever IWbemClassObject::Get returns, or
  1158. WBEM_S_RESET_TO_DEFAULT if the value is not returned from the wbem object.
  1159. Failure: whatever IWbemClassObject::Get returns.
  1160. Notes:
  1161. Caller must not pass NULL for the out parameter.
  1162. */
  1163. HRESULT
  1164. CScePropertyMgr::GetProperty (
  1165. IN LPCWSTR pszProperty,
  1166. OUT bool *pbValue
  1167. )
  1168. {
  1169. *pbValue = false;
  1170. CComVariant var;
  1171. HRESULT hr = m_srpClassObj->Get(pszProperty, 0, &var, NULL, NULL);
  1172. if (var.vt == VT_BOOL)
  1173. {
  1174. *pbValue = (var.boolVal == VARIANT_TRUE) ? true : false;
  1175. }
  1176. else if (var.vt == VT_EMPTY || var.vt == VT_NULL )
  1177. {
  1178. *pbValue = false;
  1179. hr = WBEM_S_RESET_TO_DEFAULT;
  1180. }
  1181. return hr;
  1182. }
  1183. /*
  1184. Routine Description:
  1185. Name:
  1186. CScePropertyMgr::GetProperty
  1187. Functionality:
  1188. Get the property's value in string list form (SCE specific)
  1189. Virtual:
  1190. No.
  1191. Arguments:
  1192. pszProperty - The property's name.
  1193. strList - receives names list.
  1194. Return Value:
  1195. Success: Whatever IWbemClassObject::Get returns, or
  1196. WBEM_S_RESET_TO_DEFAULT if the value is not returned from the wbem object.
  1197. Failure: whatever IWbemClassObject::Get returns.
  1198. Notes:
  1199. Caller must not pass NULL for the out parameter.
  1200. */
  1201. HRESULT
  1202. CScePropertyMgr::GetProperty (
  1203. IN LPCWSTR pszProperty,
  1204. OUT PSCE_NAME_LIST * strList
  1205. )
  1206. {
  1207. *strList = NULL;
  1208. CComVariant var;
  1209. HRESULT hr = m_srpClassObj->Get(pszProperty, 0, &var, NULL, NULL);
  1210. if (SUCCEEDED(hr))
  1211. {
  1212. if ( var.vt == (VT_BSTR | VT_ARRAY) )
  1213. {
  1214. //
  1215. // walk the array
  1216. //
  1217. if( var.parray )
  1218. {
  1219. LONG lDimension = 1;
  1220. LONG lLowerBound = 0;
  1221. LONG lUpperBound = 0;
  1222. BSTR bstrElement = NULL;
  1223. SafeArrayGetLBound ( var.parray , lDimension , &lLowerBound ) ;
  1224. SafeArrayGetUBound ( var.parray , lDimension , &lUpperBound ) ;
  1225. for ( LONG lIndex = lLowerBound ; lIndex <= lUpperBound ; lIndex++ )
  1226. {
  1227. ::SafeArrayGetElement ( var.parray , &lIndex , &bstrElement ) ;
  1228. if ( bstrElement )
  1229. {
  1230. //
  1231. // add it to the list
  1232. //
  1233. SCESTATUS rc = SceAddToNameList(strList, bstrElement, 0);
  1234. ::SysFreeString(bstrElement);
  1235. bstrElement = NULL;
  1236. if ( rc != SCESTATUS_SUCCESS )
  1237. {
  1238. //
  1239. // SCE returned errors needs to be translated to HRESULT.
  1240. // In case this is not an error, hr will be assigned to WBEM_NO_ERROR
  1241. //
  1242. hr = ProvDosErrorToWbemError(ProvSceStatusToDosError(rc));
  1243. break;
  1244. }
  1245. }
  1246. }
  1247. }
  1248. }
  1249. else if (var.vt == VT_EMPTY || var.vt == VT_NULL )
  1250. {
  1251. hr = WBEM_S_RESET_TO_DEFAULT;
  1252. }
  1253. }
  1254. if ( FAILED(hr) && *strList )
  1255. {
  1256. SceFreeMemory(*strList, SCE_STRUCT_NAME_LIST);
  1257. *strList = NULL;
  1258. }
  1259. return hr;
  1260. }
  1261. /*
  1262. Routine Description:
  1263. Name:
  1264. CScePropertyMgr::GetExpandedPath
  1265. Functionality:
  1266. Given a path's property name, we will get the path property and expand it, if necessary,
  1267. and then pass back the expanded path to the caller.
  1268. Virtual:
  1269. No.
  1270. Arguments:
  1271. pszPathName - Property name for the path.
  1272. pbstrExpandedPath - receives the expanded path.
  1273. pbIsDB - Confirms if this is a database (.sdb) path or not.
  1274. Return Value:
  1275. Success: Various success code.
  1276. Failure: various error code. Any of them indicates failure to get the property and
  1277. expanded it.
  1278. Notes:
  1279. Caller must not pass NULL for the out parameters.
  1280. */
  1281. HRESULT
  1282. CScePropertyMgr::GetExpandedPath (
  1283. IN LPCWSTR pszPathName,
  1284. OUT BSTR * pbstrExpandedPath,
  1285. OUT BOOL * pbIsDB
  1286. )
  1287. {
  1288. if (pbstrExpandedPath == NULL || pbIsDB == NULL)
  1289. {
  1290. return WBEM_E_INVALID_PARAMETER;
  1291. }
  1292. *pbstrExpandedPath = NULL;
  1293. *pbIsDB = false;
  1294. CComBSTR bstrPath;
  1295. HRESULT hr = GetProperty(pszPathName, &bstrPath);
  1296. if (SUCCEEDED(hr) && hr != WBEM_S_RESET_TO_DEFAULT)
  1297. {
  1298. hr = CheckAndExpandPath(bstrPath, pbstrExpandedPath, pbIsDB);
  1299. }
  1300. else
  1301. {
  1302. hr = WBEM_E_NOT_AVAILABLE;
  1303. }
  1304. return hr;
  1305. }
  1306. //========================================================================================
  1307. // implementation of CSceStore
  1308. /*
  1309. Routine Description:
  1310. Name:
  1311. CSceStore::CSceStore
  1312. Functionality:
  1313. constructor. Trivial
  1314. Virtual:
  1315. No.
  1316. Arguments:
  1317. None.
  1318. Return Value:
  1319. none
  1320. Notes:
  1321. Consider initializing additional members if you need to add them.
  1322. */
  1323. CSceStore::CSceStore()
  1324. :
  1325. m_SceStoreType(SCE_STORE_TYPE_INVALID)
  1326. {
  1327. }
  1328. /*
  1329. Routine Description:
  1330. Name:
  1331. CSceStore::SetPersistProperties
  1332. Functionality:
  1333. Inform the store what type of persistence context it is expected to handle.
  1334. The caller calls this function to indicate that it is expected to handle persistence
  1335. on behalf of this wbem object. The store path is available as the property value
  1336. of the given proeprty name.
  1337. Virtual:
  1338. No.
  1339. Arguments:
  1340. pClassObj - the object.
  1341. lpszPathPropertyName - path's property name.
  1342. Return Value:
  1343. Whatever CScePropertyMgr::GetExpandedPath returns.
  1344. Notes:
  1345. */
  1346. HRESULT
  1347. CSceStore::SetPersistProperties (
  1348. IN IWbemClassObject * pClassObj,
  1349. IN LPCWSTR lpszPathPropertyName
  1350. )
  1351. {
  1352. //
  1353. // CScePropertyMgr helps us to access WMI object's properties
  1354. // create an instance and attach the WMI object to it.
  1355. // This will always succeed.
  1356. //
  1357. CScePropertyMgr ScePropMgr;
  1358. ScePropMgr.Attach(pClassObj);
  1359. //
  1360. // get the expanded persist path
  1361. //
  1362. m_bstrExpandedPath.Empty();
  1363. //
  1364. // now, we need to get the path property and see what type of store we are expectig to deal with
  1365. //
  1366. BOOL bIsDB = FALSE;
  1367. HRESULT hr = ScePropMgr.GetExpandedPath(lpszPathPropertyName, &m_bstrExpandedPath, &bIsDB);
  1368. //
  1369. // cache our store type information.
  1370. //
  1371. m_SceStoreType = (SCE_STORE_TYPE)(bIsDB ? SCE_STORE_TYPE_CONFIG_DB : SCE_STORE_TYPE_TEMPLATE);
  1372. return hr;
  1373. }
  1374. /*
  1375. Routine Description:
  1376. Name:
  1377. CSceStore::SetPersistPath
  1378. Functionality:
  1379. Inform the store what type of persistence context it is expected to handle by directly
  1380. giving the store path. Since store type is determined by the path name, this is all we need.
  1381. Virtual:
  1382. No.
  1383. Arguments:
  1384. pszPath - the given path.
  1385. Return Value:
  1386. Success: whatever MakeSingleBackSlashPath returns.
  1387. Failure: WBEM_E_INVALID_PARAMETER or
  1388. whatever CheckAndExpandPath returns or whatever MakeSingleBackSlashPath returns.
  1389. Notes:
  1390. */
  1391. HRESULT
  1392. CSceStore::SetPersistPath (
  1393. IN LPCWSTR pszPath
  1394. )
  1395. {
  1396. if (pszPath == NULL || *pszPath == L'\0')
  1397. {
  1398. return WBEM_E_INVALID_PARAMETER;
  1399. }
  1400. //
  1401. // clean up first
  1402. //
  1403. m_bstrExpandedPath.Empty();
  1404. m_SceStoreType = SCE_STORE_TYPE_INVALID;
  1405. //
  1406. // now expand the path if necessary
  1407. //
  1408. CComBSTR bstrStorePath;
  1409. BOOL bIsDB = FALSE;
  1410. HRESULT hr = ::CheckAndExpandPath(pszPath, &bstrStorePath, &bIsDB);
  1411. if (SUCCEEDED(hr))
  1412. {
  1413. hr = ::MakeSingleBackSlashPath(bstrStorePath, L'\\', &m_bstrExpandedPath);
  1414. //
  1415. // cache our store type
  1416. //
  1417. if (SUCCEEDED(hr) && m_bstrExpandedPath)
  1418. {
  1419. m_SceStoreType = (SCE_STORE_TYPE)(bIsDB ? SCE_STORE_TYPE_CONFIG_DB : SCE_STORE_TYPE_TEMPLATE);
  1420. }
  1421. }
  1422. return hr;
  1423. }
  1424. /*
  1425. Routine Description:
  1426. Name:
  1427. CSceStore::WriteSecurityProfileInfo
  1428. Functionality:
  1429. Delegate the call to Sce backend supported function in a hope to isolate persistence
  1430. functionalities. See Sce API for detail.
  1431. Virtual:
  1432. No.
  1433. Arguments:
  1434. Area - Area info.
  1435. ppInfoBuffer - buffer
  1436. pErrlog - Error log
  1437. bAppend - Whether this is appending or not.
  1438. Return Value:
  1439. Translated HRESULT from whatever SceWriteSecurityProfileInfo or
  1440. SceAppendSecurityProfileInfo returns.
  1441. Notes:
  1442. See Sce API for detail.
  1443. */
  1444. HRESULT
  1445. CSceStore::WriteSecurityProfileInfo (
  1446. IN AREA_INFORMATION Area,
  1447. IN PSCE_PROFILE_INFO ppInfoBuffer,
  1448. OUT PSCE_ERROR_LOG_INFO * pErrlog,
  1449. IN bool bAppend
  1450. )const
  1451. {
  1452. HRESULT hr = WBEM_NO_ERROR;
  1453. if (m_SceStoreType == SCE_STORE_TYPE_TEMPLATE)
  1454. {
  1455. SCESTATUS rc = SCESTATUS_SUCCESS;
  1456. if (bAppend)
  1457. {
  1458. rc = ::SceAppendSecurityProfileInfo(m_bstrExpandedPath, Area, ppInfoBuffer, pErrlog);
  1459. }
  1460. else
  1461. {
  1462. rc = ::SceWriteSecurityProfileInfo(m_bstrExpandedPath, Area, ppInfoBuffer, pErrlog);
  1463. }
  1464. if ( rc != SCESTATUS_SUCCESS )
  1465. {
  1466. //
  1467. // SCE returned errors needs to be translated to HRESULT.
  1468. // In case this is not an error, hr will be assigned to WBEM_NO_ERROR
  1469. //
  1470. hr = ProvDosErrorToWbemError(ProvSceStatusToDosError(rc));
  1471. }
  1472. }
  1473. return hr;
  1474. }
  1475. /*
  1476. Routine Description:
  1477. Name:
  1478. CSceStore::SavePropertyToDB
  1479. Functionality:
  1480. Will save the string data into a database store.
  1481. Virtual:
  1482. No.
  1483. Arguments:
  1484. pszSection - Section name.
  1485. pszKey - Key name
  1486. pszData - string data
  1487. Return Value:
  1488. Translated HRESULT from whatever SceOpenProfile or SceSetDatabaseSetting returns.
  1489. Notes:
  1490. See Sce API for detail.
  1491. */
  1492. HRESULT
  1493. CSceStore::SavePropertyToDB (
  1494. IN LPCWSTR pszSection,
  1495. IN LPCWSTR pszKey,
  1496. IN LPCWSTR pszData
  1497. )const
  1498. {
  1499. PVOID hProfile = NULL;
  1500. SCESTATUS rc = ::SceOpenProfile(m_bstrExpandedPath, SCE_JET_FORMAT, &hProfile);
  1501. HRESULT hr;
  1502. if ( SCESTATUS_SUCCESS == rc )
  1503. {
  1504. DWORD dwDataSize = (pszData != NULL) ? wcslen(pszData) * sizeof(*pszData) : 0;
  1505. rc = ::SceSetDatabaseSetting(
  1506. hProfile,
  1507. SCE_ENGINE_SMP,
  1508. (PWSTR)pszSection, // these casting are caused by SceSetDatabaseSetting prototyping errors
  1509. (PWSTR)pszKey, // prototyping errors
  1510. (PWSTR)pszData, // prototyping errors
  1511. dwDataSize);
  1512. //
  1513. // SCE returned errors needs to be translated to HRESULT.
  1514. // In case this is not an error, hr will be assigned to WBEM_NO_ERROR
  1515. //
  1516. hr = ProvDosErrorToWbemError(ProvSceStatusToDosError(rc));
  1517. ::SceCloseProfile(&hProfile);
  1518. }
  1519. else
  1520. {
  1521. //
  1522. // SCE returned errors needs to be translated to HRESULT.
  1523. //
  1524. hr = ProvDosErrorToWbemError(ProvSceStatusToDosError(rc));
  1525. }
  1526. return hr;
  1527. }
  1528. /*
  1529. Routine Description:
  1530. Name:
  1531. CSceStore::SavePropertyToStore
  1532. Functionality:
  1533. Will save the string data into a store. This is store neutral call.
  1534. Virtual:
  1535. No.
  1536. Arguments:
  1537. pszSection - Section name.
  1538. pszKey - Key name
  1539. pszValue - string data
  1540. Return Value:
  1541. Translated HRESULT from whatever WritePrivateProfileSection/ WritePrivateProfileString
  1542. or SavePropertyToDB returns.
  1543. Notes:
  1544. See Sce API for detail.
  1545. There is a very legacy (rooted at .INF) problem: save and delete uses the same function.
  1546. its behavior depends on the parameters passed in. This is confusing at least.
  1547. */
  1548. HRESULT
  1549. CSceStore::SavePropertyToStore (
  1550. IN LPCWSTR pszSection,
  1551. IN LPCWSTR pszKey,
  1552. IN LPCWSTR pszValue
  1553. )const
  1554. {
  1555. if ( wcslen(m_bstrExpandedPath) == 0 || pszSection == NULL )
  1556. {
  1557. return WBEM_E_INVALID_PARAMETER;
  1558. }
  1559. else if (m_SceStoreType == SCE_STORE_TYPE_STREAM)
  1560. {
  1561. //
  1562. //we don't not supporting custom persistence yet
  1563. //
  1564. return WBEM_E_NOT_SUPPORTED;
  1565. }
  1566. HRESULT hr = WBEM_E_NOT_SUPPORTED;
  1567. if (m_SceStoreType == SCE_STORE_TYPE_CONFIG_DB)
  1568. {
  1569. hr = SavePropertyToDB(pszSection, pszKey, pszValue);
  1570. }
  1571. else if (m_SceStoreType == SCE_STORE_TYPE_TEMPLATE)
  1572. {
  1573. hr = WBEM_NO_ERROR;
  1574. BOOL bWriteResult = FALSE;
  1575. if ( pszKey == NULL )
  1576. {
  1577. //
  1578. // delete the key
  1579. //
  1580. bWriteResult = ::WritePrivateProfileSection(pszSection, NULL, m_bstrExpandedPath);
  1581. }
  1582. else
  1583. {
  1584. //
  1585. // may be deleting the (key, value) if pszValue == NULL
  1586. //
  1587. bWriteResult = ::WritePrivateProfileString(pszSection, pszKey, pszValue, m_bstrExpandedPath);
  1588. }
  1589. if (!bWriteResult)
  1590. {
  1591. //
  1592. // GetLastError() eeds to be translated to HRESULT.
  1593. // In case this is not an error, hr will be assigned to WBEM_NO_ERROR
  1594. //
  1595. hr = ProvDosErrorToWbemError(GetLastError());
  1596. }
  1597. }
  1598. return hr;
  1599. }
  1600. /*
  1601. Routine Description:
  1602. Name:
  1603. CSceStore::SavePropertyToStore
  1604. Functionality:
  1605. Will save the DWORD data property into a store. This is store neutral call.
  1606. Virtual:
  1607. No.
  1608. Arguments:
  1609. pszSection - Section name.
  1610. pszKey - Key name
  1611. dwData - DWORD data
  1612. Return Value:
  1613. if error happens before writing.
  1614. WBEM_E_NOT_SUPPORTED,
  1615. WBEM_E_INVALID_PARAMETER and
  1616. WBEM_E_OUT_OF_MEMORY
  1617. If writing is attempted, then
  1618. Translated HRESULT from whatever WritePrivateProfileSection/WritePrivateProfileString
  1619. or SavePropertyToDB returns.
  1620. Notes:
  1621. See MSDN for INF file API's.
  1622. There is a very legacy (rooted at .INF) problem: save and delete uses the same function.
  1623. its behavior depends on the parameters passed in. This is confusing at least.
  1624. */
  1625. HRESULT
  1626. CSceStore::SavePropertyToStore (
  1627. IN LPCWSTR pszSection,
  1628. IN LPCWSTR pszKey,
  1629. IN DWORD dwData
  1630. )const
  1631. {
  1632. if ( wcslen(m_bstrExpandedPath) == 0 || pszSection == NULL )
  1633. {
  1634. return WBEM_E_INVALID_PARAMETER;
  1635. }
  1636. else if (m_SceStoreType == SCE_STORE_TYPE_STREAM)
  1637. {
  1638. //
  1639. //we don't not supporting custom persistence yet
  1640. //
  1641. return WBEM_E_NOT_SUPPORTED;
  1642. }
  1643. LPCWSTR pszData = NULL;
  1644. WCHAR wchData[MAX_INT_LENGTH];
  1645. //
  1646. // need to format pszData to write
  1647. //
  1648. if (pszKey != NULL && dwData != SCE_NO_VALUE)
  1649. {
  1650. //
  1651. // this is safe even though prefast will complain
  1652. //
  1653. swprintf(wchData, L"%d", dwData);
  1654. pszData = wchData;
  1655. }
  1656. HRESULT hr;
  1657. //
  1658. // if it is saving to database store
  1659. //
  1660. if (m_SceStoreType == SCE_STORE_TYPE_CONFIG_DB)
  1661. {
  1662. hr = SavePropertyToDB(pszSection, pszKey, pszData);
  1663. }
  1664. else if (m_SceStoreType == SCE_STORE_TYPE_TEMPLATE)
  1665. {
  1666. BOOL bWriteResult = FALSE;
  1667. if ( pszKey == NULL )
  1668. {
  1669. //
  1670. // delete the section
  1671. //
  1672. bWriteResult = ::WritePrivateProfileSection(pszSection, NULL, m_bstrExpandedPath);
  1673. }
  1674. else
  1675. {
  1676. //
  1677. // set data, might be deleting when pszData == NULL
  1678. //
  1679. bWriteResult = ::WritePrivateProfileString(pszSection, pszKey, pszData, m_bstrExpandedPath);
  1680. }
  1681. if (!bWriteResult)
  1682. {
  1683. //
  1684. // GetLastError() eeds to be translated to HRESULT.
  1685. // In case this is not an error, hr will be assigned to WBEM_NO_ERROR
  1686. //
  1687. hr = ProvDosErrorToWbemError(GetLastError());
  1688. }
  1689. }
  1690. return hr;
  1691. }
  1692. /*
  1693. Routine Description:
  1694. Name:
  1695. CSceStore::SavePropertyToStore
  1696. Functionality:
  1697. This is a very SCE specific save. It pretty much format the data and save.
  1698. See its use for any samples.
  1699. Virtual:
  1700. No.
  1701. Arguments:
  1702. pszSection - Section name.
  1703. pszKey - Key name
  1704. dwData - DWORD data
  1705. Return Value:
  1706. if error happens before writing.
  1707. WBEM_E_NOT_SUPPORTED,
  1708. WBEM_E_INVALID_PARAMETER and
  1709. WBEM_E_OUT_OF_MEMORY
  1710. If writing is attempted, then
  1711. Translated HRESULT from whatever WritePrivateProfileSection/WritePrivateProfileString
  1712. or SavePropertyToDB returns.
  1713. Notes:
  1714. See MSDN for INF file API's
  1715. */
  1716. HRESULT CSceStore::SavePropertyToStore (
  1717. IN LPCWSTR pszSection,
  1718. IN LPCWSTR pszKey,
  1719. IN DWORD dwData,
  1720. IN WCHAR delim,
  1721. IN LPCWSTR pszValue
  1722. )const
  1723. {
  1724. if ( wcslen(m_bstrExpandedPath) == 0 || pszSection == NULL )
  1725. {
  1726. return WBEM_E_INVALID_PARAMETER;
  1727. }
  1728. else if (m_SceStoreType == SCE_STORE_TYPE_STREAM)
  1729. {
  1730. //
  1731. //we don't not supporting custom persistence yet
  1732. //
  1733. return WBEM_E_NOT_SUPPORTED;
  1734. }
  1735. LPWSTR pszData = NULL;
  1736. //
  1737. // need to format pszData
  1738. //
  1739. if (pszKey != NULL && dwData != SCE_NO_VALUE)
  1740. {
  1741. pszData = new WCHAR[MAX_INT_LENGTH + 1 + wcslen(pszValue) + 1];
  1742. if (pszData == NULL)
  1743. {
  1744. return WBEM_E_OUT_OF_MEMORY;
  1745. }
  1746. if ( pszValue )
  1747. {
  1748. swprintf(pszData, L"%d%c%s", dwData, delim, pszValue);
  1749. }
  1750. else
  1751. {
  1752. swprintf(pszData, L"%d", dwData);
  1753. }
  1754. }
  1755. HRESULT hr;
  1756. if (m_SceStoreType == SCE_STORE_TYPE_CONFIG_DB)
  1757. {
  1758. hr = SavePropertyToDB(pszSection, pszKey, pszData);
  1759. }
  1760. else if (m_SceStoreType == SCE_STORE_TYPE_TEMPLATE)
  1761. {
  1762. BOOL bWriteResult = FALSE;
  1763. if ( pszKey == NULL )
  1764. {
  1765. //
  1766. // delete the section
  1767. //
  1768. bWriteResult = ::WritePrivateProfileSection(pszSection, NULL, m_bstrExpandedPath);
  1769. }
  1770. else
  1771. {
  1772. //
  1773. // when ( dwData == SCE_NO_VALUE ) we will delete the key, that is accomplished by pszData == NULL
  1774. //
  1775. bWriteResult = ::WritePrivateProfileString(pszSection, pszKey, pszData, m_bstrExpandedPath);
  1776. }
  1777. if (!bWriteResult)
  1778. {
  1779. //
  1780. // GetLastError() eeds to be translated to HRESULT.
  1781. // In case this is not an error, hr will be assigned to WBEM_NO_ERROR
  1782. //
  1783. hr = ProvDosErrorToWbemError(GetLastError());
  1784. }
  1785. }
  1786. delete [] pszData;
  1787. return hr;
  1788. }
  1789. /*
  1790. Routine Description:
  1791. Name:
  1792. CSceStore::WriteAttachmentSection
  1793. Functionality:
  1794. SCE backend won't be able to import an INF template for non-native sections
  1795. unless there is a entry in its Attachments section. This is to write (for a
  1796. particular non-native section) such an entry.
  1797. Virtual:
  1798. No.
  1799. Arguments:
  1800. pszKey - The section name.
  1801. pszData - value for the key. This is not pretty much ignored for now.
  1802. Return Value:
  1803. Success: WBEM_NO_ERROR
  1804. Failure: Translated HRESULT from whatever WritePrivateProfileString returns.
  1805. Notes:
  1806. (1) See MSDN for INF file API's.
  1807. (2) This is No-Op for database store.
  1808. */
  1809. HRESULT
  1810. CSceStore::WriteAttachmentSection (
  1811. IN LPCWSTR pszKey,
  1812. IN LPCWSTR pszData
  1813. )const
  1814. {
  1815. HRESULT hr = WBEM_NO_ERROR;
  1816. if (m_SceStoreType == SCE_STORE_TYPE_TEMPLATE)
  1817. {
  1818. BOOL bWriteResult = ::WritePrivateProfileString(pAttachmentSections, pszKey, pszData, m_bstrExpandedPath);
  1819. if (!bWriteResult)
  1820. {
  1821. //
  1822. // GetLastError() eeds to be translated to HRESULT.
  1823. // In case this is not an error, hr will be assigned to WBEM_NO_ERROR
  1824. //
  1825. hr = ProvDosErrorToWbemError(GetLastError());
  1826. }
  1827. }
  1828. return hr;
  1829. }
  1830. /*
  1831. Routine Description:
  1832. Name:
  1833. CSceStore::DeleteSectionFromStore
  1834. Functionality:
  1835. remove the entire section.
  1836. Virtual:
  1837. No.
  1838. Arguments:
  1839. pszSection - The section name. Must NOT be NULL.
  1840. Return Value:
  1841. Success: WBEM_NO_ERROR.
  1842. Failure: Whatever SavePropertyToStore or WriteAttachmentSection returns.
  1843. Notes:
  1844. */
  1845. HRESULT
  1846. CSceStore::DeleteSectionFromStore (
  1847. IN LPCWSTR pszSection
  1848. )const
  1849. {
  1850. HRESULT hr = SavePropertyToStore(pszSection, (LPCWSTR)NULL, (LPCWSTR)NULL);
  1851. //
  1852. // we should also delete the attachment entry because all are gone now.
  1853. //
  1854. if (SUCCEEDED(hr))
  1855. {
  1856. hr = WriteAttachmentSection(pszSection, (LPCWSTR)NULL);
  1857. }
  1858. return hr;
  1859. }
  1860. /*
  1861. Routine Description:
  1862. Name:
  1863. CSceStore::GetPropertyFromStore
  1864. Functionality:
  1865. Get the named property value into a string buffer. This is store neutral.
  1866. Virtual:
  1867. No.
  1868. Arguments:
  1869. pszSection - The section name. Must NOT be NULL.
  1870. pszKey - The key name.
  1871. ppszBuffer - Receiving heap allocated memory containing the string. Must NOT be NULL.
  1872. pdwRead - receives information about how many bytes we have read. Must NOT be NULL.
  1873. Return Value:
  1874. Success: WBEM_NO_ERROR
  1875. Failure: Translated HRESULT from whatever GetPrivateProfileString returns.
  1876. Notes:
  1877. (1) caller must free memory allocated by this function
  1878. */
  1879. HRESULT
  1880. CSceStore::GetPropertyFromStore (
  1881. IN LPCWSTR pszSection,
  1882. IN LPCWSTR pszKey,
  1883. IN LPWSTR * ppszBuffer,
  1884. IN DWORD * pdwRead
  1885. )const
  1886. {
  1887. if ( wcslen(m_bstrExpandedPath) == 0 ||
  1888. pszSection == NULL ||
  1889. ppszBuffer == NULL ||
  1890. pdwRead == NULL )
  1891. {
  1892. return WBEM_E_INVALID_PARAMETER;
  1893. }
  1894. *pdwRead = 0;
  1895. *ppszBuffer = NULL;
  1896. HRESULT hr;
  1897. if (m_SceStoreType == SCE_STORE_TYPE_CONFIG_DB)
  1898. {
  1899. hr = GetPropertyFromDB(pszSection, pszKey, ppszBuffer, pdwRead);
  1900. }
  1901. else if (m_SceStoreType == SCE_STORE_TYPE_STREAM)
  1902. {
  1903. //
  1904. //we don't not supporting custom persistence yet
  1905. //
  1906. return WBEM_E_NOT_SUPPORTED;
  1907. }
  1908. else if (m_SceStoreType == SCE_STORE_TYPE_TEMPLATE)
  1909. {
  1910. int TotalLength = MAX_PATH;
  1911. *ppszBuffer = new WCHAR[TotalLength];
  1912. if (ppszBuffer == NULL)
  1913. {
  1914. hr = WBEM_E_OUT_OF_MEMORY;
  1915. }
  1916. else
  1917. {
  1918. //
  1919. // try to read the buffer out
  1920. //
  1921. while (true)
  1922. {
  1923. *pdwRead = ::GetPrivateProfileString(pszSection, pszKey, NULL, *ppszBuffer, TotalLength, m_bstrExpandedPath);
  1924. if (*pdwRead > 0 && *pdwRead < TotalLength - 1)
  1925. {
  1926. //
  1927. // everything is read out
  1928. //
  1929. hr = WBEM_NO_ERROR;
  1930. break;
  1931. }
  1932. else if (*pdwRead > 0)
  1933. {
  1934. //
  1935. // buffer is most likely truncated, will try to continue unless out of memory
  1936. //
  1937. delete [] *ppszBuffer;
  1938. if (TotalLength < 0x00010000)
  1939. {
  1940. //
  1941. // if TotalLength is small enough, we will double its length
  1942. //
  1943. TotalLength *= 2;
  1944. }
  1945. else
  1946. {
  1947. //
  1948. // if TotalLength is already big, we will try to add 0x00100000 more bytes
  1949. //
  1950. TotalLength += 0x00010000;
  1951. }
  1952. *ppszBuffer = new WCHAR[TotalLength];
  1953. if (*ppszBuffer == NULL)
  1954. {
  1955. *pdwRead = 0;
  1956. hr = WBEM_E_OUT_OF_MEMORY;
  1957. break;
  1958. }
  1959. }
  1960. else
  1961. {
  1962. //
  1963. // *pdwRead == 0
  1964. //
  1965. //
  1966. // GetLastError() needs to be translated to HRESULT.
  1967. // In case this is not an error, hr will be assigned to WBEM_NO_ERROR
  1968. //
  1969. hr = ProvDosErrorToWbemError(GetLastError());
  1970. //
  1971. // if no error is encountered, then we will simply say we can't find the property
  1972. //
  1973. if (SUCCEEDED(hr))
  1974. {
  1975. hr = WBEM_E_NOT_FOUND;
  1976. }
  1977. break;
  1978. }
  1979. }
  1980. }
  1981. //
  1982. // if we say we failed, then better not return any valid string pointer to caller
  1983. //
  1984. if (FAILED(hr) && *ppszBuffer)
  1985. {
  1986. delete [] *ppszBuffer;
  1987. *ppszBuffer = NULL;
  1988. }
  1989. }
  1990. return hr;
  1991. }
  1992. /*
  1993. Routine Description:
  1994. Name:
  1995. CSceStore::GetPropertyFromDB
  1996. Functionality:
  1997. Get the named property's value into a string buffer. This is database store specific.
  1998. Virtual:
  1999. No.
  2000. Arguments:
  2001. pszSection - The section name. Must NOT be NULL.
  2002. pszKey - The key name.
  2003. ppszBuffer - Receiving heap allocated memory containing the string. Must NOT be NULL.
  2004. pdwRead - receives information about how many bytes we have read. Must NOT be NULL.
  2005. Return Value:
  2006. Success: WBEM_NO_ERROR
  2007. Failure: Translated HRESULT from whatever WritePrivateProfileString returns.
  2008. Notes:
  2009. (1) caller must free memory allocated by this function
  2010. */
  2011. HRESULT
  2012. CSceStore::GetPropertyFromDB (
  2013. IN LPCWSTR pszSection,
  2014. IN LPCWSTR pszKey,
  2015. IN LPWSTR * ppszBuffer,
  2016. IN DWORD * pdwRead
  2017. )const
  2018. {
  2019. if ( wcslen(m_bstrExpandedPath) == 0 || pszSection == NULL )
  2020. {
  2021. return WBEM_E_INVALID_PARAMETER;
  2022. }
  2023. else if (m_SceStoreType == SCE_STORE_TYPE_STREAM)
  2024. {
  2025. //
  2026. //we don't not supporting custom persistence yet
  2027. //
  2028. return WBEM_E_NOT_SUPPORTED;
  2029. }
  2030. *pdwRead = 0;
  2031. *ppszBuffer = NULL;
  2032. HRESULT hr;
  2033. if (m_SceStoreType == SCE_STORE_TYPE_CONFIG_DB)
  2034. {
  2035. //
  2036. // get the information from database
  2037. //
  2038. PVOID hProfile=NULL;
  2039. LPWSTR pszSceBuffer = NULL;
  2040. SCESTATUS rc = ::SceOpenProfile(m_bstrExpandedPath, SCE_JET_FORMAT, &hProfile);
  2041. if ( SCESTATUS_SUCCESS == rc )
  2042. {
  2043. rc = ::SceGetDatabaseSetting (
  2044. hProfile,
  2045. SCE_ENGINE_SMP,
  2046. (PWSTR)pszSection,
  2047. (PWSTR)pszKey,
  2048. &pszSceBuffer, // needs to be freed, use LocalFree!!!
  2049. pdwRead
  2050. );
  2051. ::SceCloseProfile(&hProfile);
  2052. }
  2053. //
  2054. // SCE returned errors needs to be translated to HRESULT.
  2055. // In case this is not an error, hr will be assigned to WBEM_NO_ERROR
  2056. //
  2057. hr = ProvDosErrorToWbemError(ProvSceStatusToDosError(rc));
  2058. if (SUCCEEDED(hr) && *pdwRead > 0 && pszSceBuffer != NULL)
  2059. {
  2060. long lLen = wcslen(pszSceBuffer);
  2061. *ppszBuffer = new WCHAR[lLen + 1];
  2062. if (*ppszBuffer == NULL)
  2063. {
  2064. hr = WBEM_E_OUT_OF_MEMORY;
  2065. }
  2066. else
  2067. {
  2068. ::memcpy(*ppszBuffer, pszSceBuffer, sizeof(WCHAR) * (lLen + 1));
  2069. }
  2070. }
  2071. ::LocalFree(pszSceBuffer);
  2072. }
  2073. return hr;
  2074. }
  2075. /*
  2076. Routine Description:
  2077. Name:
  2078. CSceStore::GetSecurityProfileInfo
  2079. Functionality:
  2080. Delegate the call to SceGetSecurityProfileInfo in an effort to hide the sce
  2081. persistence detail from caller.
  2082. Virtual:
  2083. No.
  2084. Arguments:
  2085. Area - Area of the profile section.
  2086. ppInfo - Receiving the profile info.
  2087. pErrlog - Receiving the error log info.
  2088. Return Value:
  2089. Success: WBEM_NO_ERROR
  2090. Failure: Translated HRESULT from whatever SceOpenProfile/SceGetSecurityProfileInfo returns.
  2091. Notes:
  2092. (1) This is very SCE specific function.
  2093. (2) Caller must remember to call FreeSecurityProfileInfo to free the resource allocated by
  2094. this function through ppInfo.
  2095. (3) See SCE API for detail.
  2096. */
  2097. HRESULT
  2098. CSceStore::GetSecurityProfileInfo (
  2099. IN AREA_INFORMATION Area,
  2100. OUT PSCE_PROFILE_INFO * ppInfo,
  2101. OUT PSCE_ERROR_LOG_INFO * pErrlog
  2102. )const
  2103. {
  2104. if (ppInfo == NULL)
  2105. {
  2106. return WBEM_E_INVALID_PARAMETER;
  2107. }
  2108. *ppInfo = NULL;
  2109. SCETYPE ProfileType = (m_SceStoreType == SCE_INF_FORMAT) ? SCE_ENGINE_SCP : SCE_ENGINE_SMP;
  2110. PVOID hProfile = NULL;
  2111. SCE_FORMAT_TYPE SceFormatType = SCE_INF_FORMAT;
  2112. if (m_SceStoreType == SCE_STORE_TYPE_CONFIG_DB)
  2113. {
  2114. SceFormatType = SCE_JET_FORMAT;
  2115. }
  2116. SCESTATUS rc = SceOpenProfile(m_bstrExpandedPath, SceFormatType, &hProfile);
  2117. if ( rc != SCESTATUS_SUCCESS )
  2118. {
  2119. //
  2120. // SCE returned errors needs to be translated to HRESULT.
  2121. //
  2122. return ProvDosErrorToWbemError(ProvSceStatusToDosError(rc));
  2123. }
  2124. rc = SceGetSecurityProfileInfo(hProfile,
  2125. ProfileType,
  2126. Area,
  2127. ppInfo,
  2128. pErrlog
  2129. );
  2130. SceCloseProfile( &hProfile );
  2131. if ( rc != SCESTATUS_SUCCESS || *ppInfo == NULL )
  2132. {
  2133. //
  2134. // SCE returned errors needs to be translated to HRESULT.
  2135. //
  2136. return ProvDosErrorToWbemError(ProvSceStatusToDosError(rc));
  2137. }
  2138. return WBEM_NO_ERROR;
  2139. }
  2140. /*
  2141. Routine Description:
  2142. Name:
  2143. CSceStore::GetObjectSecurity
  2144. Functionality:
  2145. Delegate the call to SceGetObjectSecurity in an effort to hide the sce
  2146. persistence detail from caller.
  2147. Virtual:
  2148. No.
  2149. Arguments:
  2150. Area - Area of the profile section.
  2151. pszObjectName - Name of the object.
  2152. ppObjSecurity - Receiving the security object.
  2153. Return Value:
  2154. Success: WBEM_NO_ERROR
  2155. Failure: Translated HRESULT from whatever SceOpenProfile/SceGetObjectSecurity returns.
  2156. Notes:
  2157. (1) This is very SCE specific function.
  2158. (2) Caller must remember to call FreeObjectSecurit to free the resource allocated by
  2159. this function through ppObjSecurity.
  2160. (3) See SCE API for detail.
  2161. */
  2162. HRESULT
  2163. CSceStore::GetObjectSecurity (
  2164. IN AREA_INFORMATION Area,
  2165. IN LPCWSTR pszObjectName,
  2166. IN PSCE_OBJECT_SECURITY * ppObjSecurity
  2167. )const
  2168. {
  2169. if (ppObjSecurity == NULL)
  2170. {
  2171. return WBEM_E_INVALID_PARAMETER;
  2172. }
  2173. *ppObjSecurity = NULL;
  2174. SCETYPE ProfileType = (m_SceStoreType == SCE_INF_FORMAT) ? SCE_ENGINE_SCP : SCE_ENGINE_SMP;
  2175. PVOID hProfile = NULL;
  2176. //
  2177. // let's assume INF format
  2178. //
  2179. SCE_FORMAT_TYPE SceFormatType = SCE_INF_FORMAT;
  2180. if (m_SceStoreType == SCE_STORE_TYPE_CONFIG_DB)
  2181. {
  2182. SceFormatType = SCE_JET_FORMAT;
  2183. }
  2184. SCESTATUS rc = ::SceOpenProfile(m_bstrExpandedPath, SceFormatType, &hProfile);
  2185. if ( rc != SCESTATUS_SUCCESS )
  2186. {
  2187. //
  2188. // SCE returned errors needs to be translated to HRESULT.
  2189. //
  2190. return ProvDosErrorToWbemError(ProvSceStatusToDosError(rc));
  2191. }
  2192. //
  2193. // the following cast (to PWSTR) is caused by a mistake in the prototype of SceGetObjectSecurity
  2194. //
  2195. rc = ::SceGetObjectSecurity (
  2196. hProfile,
  2197. ProfileType,
  2198. Area,
  2199. (PWSTR)pszObjectName,
  2200. ppObjSecurity
  2201. );
  2202. ::SceCloseProfile( &hProfile );
  2203. if ( rc != SCESTATUS_SUCCESS || *ppObjSecurity == NULL )
  2204. {
  2205. //
  2206. // SCE returned errors needs to be translated to HRESULT.
  2207. // In case this is not an error, hr will be assigned to WBEM_NO_ERROR
  2208. //
  2209. return ProvDosErrorToWbemError(ProvSceStatusToDosError(rc));
  2210. }
  2211. return WBEM_S_NO_ERROR;
  2212. }
  2213. //=========================================================================================
  2214. // CScePersistMgr implementation
  2215. //=========================================================================================
  2216. /*
  2217. Routine Description:
  2218. Name:
  2219. CScePersistMgr::CScePersistMgr
  2220. Functionality:
  2221. Constructor. trivial since all our current members will automatically create themselves.
  2222. Virtual:
  2223. No.
  2224. Arguments:
  2225. None.
  2226. Return Value:
  2227. none
  2228. Notes:
  2229. Consider initializing your members if you add more non-self-constructing members..
  2230. */
  2231. CScePersistMgr::CScePersistMgr ()
  2232. {
  2233. }
  2234. /*
  2235. Routine Description:
  2236. Name:
  2237. CScePersistMgr::~CScePersistMgr
  2238. Functionality:
  2239. Destructor. Just do a cleanup.
  2240. Virtual:
  2241. No.
  2242. Arguments:
  2243. None.
  2244. Return Value:
  2245. none
  2246. Notes:
  2247. Consider adding cleanup code if you add more non-self-destructing members..
  2248. */
  2249. CScePersistMgr::~CScePersistMgr ()
  2250. {
  2251. }
  2252. /*
  2253. Routine Description:
  2254. Name:
  2255. CScePersistMgr::Attach
  2256. Functionality:
  2257. Attach an object (that knows how to provide properties) to this persistence manager so
  2258. that it knows where to get data for persistence.
  2259. Any use of this class without a successfuly attaching object will cause catastrophic failure.
  2260. This function is the first thing you need to do with CScePersistMgr object.
  2261. Virtual:
  2262. Yes. (function of IScePersistMgr)
  2263. Arguments:
  2264. guid - the in-coming interface pointer (pObj) interface guid. Currently, we only support
  2265. IID_ISceClassObject.
  2266. pObj - the attaching object's interface pointer. Currently, we only take ISceClassObject*.
  2267. Return Value:
  2268. Success: S_OK.
  2269. Failure:
  2270. (1) E_NOINTERFACE if the supplied interface is not supported.
  2271. (2) E_INVALIDARG if pObj is NULL.
  2272. Notes:
  2273. Currently, we only work with ISceClassObject interface.
  2274. */
  2275. STDMETHODIMP
  2276. CScePersistMgr::Attach (
  2277. IN REFIID guid, // [in]
  2278. IN IUnknown * pObj // [iid_is][in]
  2279. )
  2280. {
  2281. if (pObj == NULL)
  2282. {
  2283. return E_INVALIDARG;
  2284. }
  2285. if (guid == IID_ISceClassObject)
  2286. {
  2287. return pObj->QueryInterface(IID_ISceClassObject, (void**)&m_srpObject);
  2288. }
  2289. else
  2290. {
  2291. return E_NOINTERFACE;
  2292. }
  2293. }
  2294. /*
  2295. Routine Description:
  2296. Name:
  2297. CScePersistMgr::Save
  2298. Functionality:
  2299. Save an attached instance into a store.
  2300. Virtual:
  2301. Yes. (function of IScePersistMgr)
  2302. Arguments:
  2303. None.
  2304. Return Value:
  2305. Success: successful code (use SUCCEEDED(hr) to test). No guarantee the return result will be S_OK.
  2306. Failure:
  2307. (1) E_UNEXPECTED no successful attachment was ever done.
  2308. (2) Other error code.
  2309. Notes:
  2310. Since this is a regular COM server interface function, we will in most cases return well known COM
  2311. HRESULTs instead of WMI specific HRESULTs. However, this is no WMI specific, be prepared to see
  2312. your result results in WMI specific HRESULTs.
  2313. */
  2314. STDMETHODIMP
  2315. CScePersistMgr::Save ()
  2316. {
  2317. HRESULT hr = S_OK;
  2318. if (m_srpObject == NULL)
  2319. {
  2320. return E_UNEXPECTED;
  2321. }
  2322. else if (FAILED(hr = m_srpObject->Validate()))
  2323. {
  2324. return hr;
  2325. }
  2326. DWORD dwDump;
  2327. //
  2328. // need to set the store path and we must have a store path.
  2329. //
  2330. CComBSTR bstrPersistPath;
  2331. CComBSTR bstrExpandedPath;
  2332. hr = m_srpObject->GetPersistPath(&bstrPersistPath);
  2333. if (FAILED(hr))
  2334. {
  2335. return hr;
  2336. }
  2337. //
  2338. // Prepare a store (for persistence) for this store path (file)
  2339. //
  2340. CSceStore SceStore;
  2341. hr = SceStore.SetPersistPath(bstrPersistPath);
  2342. if (FAILED(hr))
  2343. {
  2344. return hr;
  2345. }
  2346. //
  2347. // For a new .inf file. Write an empty buffer to the file
  2348. // will creates the file with right header/signature/unicode format
  2349. // this is harmless for existing files.
  2350. // For database store, this is a no-op.
  2351. //
  2352. hr = SceStore.WriteSecurityProfileInfo (
  2353. AreaBogus,
  2354. (PSCE_PROFILE_INFO)&dwDump,
  2355. NULL,
  2356. false // not appending
  2357. );
  2358. //
  2359. // now, we need to form a section, which will be the class name
  2360. //
  2361. CComBSTR bstrSectionName;
  2362. hr = GetSectionName(&bstrSectionName);
  2363. if (FAILED(hr))
  2364. {
  2365. return hr;
  2366. }
  2367. //
  2368. // this is necessary for any extension class
  2369. // SCE doesn't care about the value, so, we are using a static value here
  2370. //
  2371. hr = SceStore.WriteAttachmentSection(bstrSectionName, pszAttachSectionValue);
  2372. if (FAILED(hr))
  2373. {
  2374. return hr;
  2375. }
  2376. //
  2377. // now we need to get all key property names to form a unique key for the section
  2378. //
  2379. DWORD dwCookie = INVALID_COOKIE;
  2380. CComBSTR bstrCompoundKey;
  2381. hr = GetCompoundKey(&bstrCompoundKey);
  2382. if (FAILED(hr))
  2383. {
  2384. return hr;
  2385. }
  2386. //
  2387. // now create the current list of instances in this store for the class
  2388. // so that we can add the new one (its cookie).
  2389. // Extension classes are identified by their instance cookies.
  2390. //
  2391. CExtClassInstCookieList clsInstCookies;
  2392. hr = clsInstCookies.Create(&SceStore, bstrSectionName, GetKeyPropertyNames(NULL, NULL));
  2393. if (SUCCEEDED(hr))
  2394. {
  2395. //
  2396. // add this class to the cookie list
  2397. //
  2398. //
  2399. // We are adding the compound key and potentially requesting (by INVALID_COOKIE) a new cookie.
  2400. //
  2401. hr = clsInstCookies.AddCompKey(bstrCompoundKey, INVALID_COOKIE, &dwCookie);
  2402. if (SUCCEEDED(hr))
  2403. {
  2404. //
  2405. // save the new list of instances.
  2406. // key properties are save with cookie list.
  2407. //
  2408. hr = clsInstCookies.Save(&SceStore, bstrSectionName);
  2409. }
  2410. }
  2411. //
  2412. // non-key properties
  2413. //
  2414. if (SUCCEEDED(hr))
  2415. {
  2416. hr = SaveProperties(&SceStore, dwCookie, bstrSectionName);
  2417. }
  2418. return hr;
  2419. }
  2420. /*
  2421. Routine Description:
  2422. Name:
  2423. CScePersistMgr::Load
  2424. Functionality:
  2425. Loading instance(s) from a store. Depending on attached object (which may or may not have complete
  2426. key information), this load may be a single instanace loading if complete key is available, or
  2427. a multiple instance loading (if no complete key is available).
  2428. Virtual:
  2429. Yes. (function of IScePersistMgr)
  2430. Arguments:
  2431. bstrStorePath - the path to the store.
  2432. pHandler - COM interface pointer to notify WMI if instance(s) are loaded.
  2433. Return Value:
  2434. Success: successful code (use SUCCEEDED(hr) to test). No guarantee the return result will be S_OK.
  2435. Failure:
  2436. (1) E_UNEXPECTED no successful attachment was ever done.
  2437. (2) WBEM_E_NOT_FOUND if there is no such instance.
  2438. (2) Other error code.
  2439. Notes:
  2440. Since this is a regular COM server interface function, we will in most cases return well known COM
  2441. HRESULTs instead of WMI specific HRESULTs. However, this is no WMI specific, be prepared to see
  2442. your result results in WMI specific HRESULTs.
  2443. */
  2444. STDMETHODIMP
  2445. CScePersistMgr::Load (
  2446. IN BSTR bstrStorePath,
  2447. IN IWbemObjectSink * pHandler
  2448. )
  2449. {
  2450. HRESULT hr = S_OK;
  2451. if (m_srpObject == NULL)
  2452. {
  2453. return E_UNEXPECTED;
  2454. }
  2455. else if (FAILED(hr = m_srpObject->Validate()))
  2456. {
  2457. return hr;
  2458. }
  2459. CComBSTR bstrSectionName;
  2460. //
  2461. // we have an attached object, we must also know the section
  2462. // (actually, as it is now, it's the name of the class)
  2463. //
  2464. hr = GetSectionName(&bstrSectionName);
  2465. if (FAILED(hr))
  2466. {
  2467. return hr;
  2468. }
  2469. //
  2470. // Prepare a store (for persistence) for this store path (file)
  2471. //
  2472. CSceStore SceStore;
  2473. SceStore.SetPersistPath(bstrStorePath);
  2474. //
  2475. // Need to know what instances (their cookies) are present in the store for this class.
  2476. //
  2477. CExtClassInstCookieList clsInstCookies;
  2478. hr = clsInstCookies.Create(&SceStore, bstrSectionName, GetKeyPropertyNames(NULL, NULL));
  2479. if (FAILED(hr))
  2480. {
  2481. return hr;
  2482. }
  2483. //
  2484. // get this attached object's cookie if possible (in non-querying loading)
  2485. //
  2486. DWORD dwCookie;
  2487. CComBSTR bstrCompoundKey;
  2488. //
  2489. // it returns WBEM_S_FALSE if no compound key can be returned.
  2490. //
  2491. hr = GetCompoundKey(&bstrCompoundKey);
  2492. //
  2493. // if we can't create a complete compound cookie, then we are querying
  2494. //
  2495. if (hr == WBEM_S_FALSE)
  2496. {
  2497. //
  2498. // we will track first error during querying
  2499. //
  2500. HRESULT hrFirstError = WBEM_NO_ERROR;
  2501. DWORD dwResumeHandle = 0;
  2502. CComBSTR bstrEachCompKey;
  2503. //
  2504. // will try to load everything. Enumerate through the cookies...
  2505. //
  2506. hr = clsInstCookies.Next(&bstrEachCompKey, &dwCookie, &dwResumeHandle);
  2507. while (SUCCEEDED(hr) && hr != WBEM_S_NO_MORE_DATA)
  2508. {
  2509. //
  2510. // as long as there is more item, keep looping
  2511. //
  2512. if (SUCCEEDED(hr) && hr != WBEM_S_NO_MORE_DATA)
  2513. {
  2514. CComPtr<IWbemClassObject> srpNewObj;
  2515. //
  2516. // LoadInstance will return WBEM_S_FALSE if there is no such instance.
  2517. //
  2518. hr = LoadInstance(&SceStore, bstrSectionName, bstrEachCompKey, dwCookie, &srpNewObj);
  2519. if (SUCCEEDED(hr) && hr != WBEM_S_FALSE)
  2520. {
  2521. hr = pHandler->Indicate(1, &srpNewObj);
  2522. }
  2523. //
  2524. // we will track first error during querying
  2525. //
  2526. if (SUCCEEDED(hrFirstError) && FAILED(hr))
  2527. {
  2528. hrFirstError = hr;
  2529. }
  2530. }
  2531. //
  2532. // prepare to be re-used
  2533. //
  2534. bstrEachCompKey.Empty();
  2535. //
  2536. // next cookie
  2537. //
  2538. hr = clsInstCookies.Next(&bstrEachCompKey, &dwCookie, &dwResumeHandle);
  2539. }
  2540. //
  2541. // if error have happened, then we will pass that error back while trying our best to query
  2542. //
  2543. if (FAILED(hrFirstError))
  2544. {
  2545. hr = hrFirstError;
  2546. }
  2547. }
  2548. else if (SUCCEEDED(hr))
  2549. {
  2550. //
  2551. // unique instance load, we can get the cookie!
  2552. //
  2553. ExtClassCookieIterator it;
  2554. dwCookie = clsInstCookies.GetCompKeyCookie(bstrCompoundKey, &it);
  2555. //
  2556. // We must have a cookie since this instance is unique
  2557. //
  2558. if (dwCookie != INVALID_COOKIE)
  2559. {
  2560. CComPtr<IWbemClassObject> srpNewObj;
  2561. //
  2562. // LoadInstance will return WBEM_S_FALSE if there is no such instance.
  2563. //
  2564. hr = LoadInstance(&SceStore, bstrSectionName, bstrCompoundKey, dwCookie, &srpNewObj);
  2565. if (SUCCEEDED(hr) && hr != WBEM_S_FALSE)
  2566. {
  2567. hr = pHandler->Indicate(1, &srpNewObj);
  2568. }
  2569. else if ( hr == WBEM_S_FALSE)
  2570. {
  2571. hr = WBEM_E_NOT_FOUND;
  2572. }
  2573. }
  2574. else
  2575. {
  2576. hr = WBEM_E_NOT_FOUND;
  2577. }
  2578. }
  2579. return hr;
  2580. }
  2581. /*
  2582. Routine Description:
  2583. Name:
  2584. CScePersistMgr::LoadInstance
  2585. Functionality:
  2586. Loading a single instanace with the given cookie.
  2587. Virtual:
  2588. No.
  2589. Arguments:
  2590. pSceStore - the store.
  2591. pszSectionName - the section name.
  2592. pszCompoundKey - the compound key.
  2593. dwCookie - the cookie.
  2594. ppObj - Receives the WMI object.
  2595. Return Value:
  2596. Success:
  2597. (1) S_OK if instance is loaded.
  2598. (2) WBEM_S_FALSE if no such instance is found.
  2599. Failure:
  2600. (1) various error codes.
  2601. Notes:
  2602. (1) This is a private helper, we don't check all validity of the attached object.
  2603. (2) Since this is a regular COM server interface function, we will in most cases return well known COM
  2604. HRESULTs instead of WMI specific HRESULTs. However, this is no WMI specific, be prepared to see
  2605. your result results in WMI specific HRESULTs.
  2606. (3) This routine can be enhanced to get rid of the compound key parameter since once a cookie is found
  2607. all key property information is available via the use of CCompoundKey.
  2608. */
  2609. HRESULT
  2610. CScePersistMgr::LoadInstance (
  2611. IN CSceStore * pSceStore,
  2612. IN LPCWSTR pszSectionName,
  2613. IN LPCWSTR pszCompoundKey,
  2614. IN DWORD dwCookie,
  2615. OUT IWbemClassObject ** ppObj
  2616. )
  2617. {
  2618. if (ppObj == NULL || pszCompoundKey == NULL || *pszCompoundKey == L'\0')
  2619. {
  2620. return E_INVALIDARG;
  2621. }
  2622. CComPtr<IWbemClassObject> srpObj;
  2623. HRESULT hr = m_srpObject->GetClassObject(&srpObj);
  2624. //
  2625. // spawn a new instance, we won't pass it back until everything is loaded successfully
  2626. // so, this is a local object at this point.
  2627. //
  2628. CComPtr<IWbemClassObject> srpNewObj;
  2629. hr = srpObj->SpawnInstance(0, &srpNewObj);
  2630. DWORD dwLoadedProperties = 0;
  2631. if (SUCCEEDED(hr))
  2632. {
  2633. if (SUCCEEDED(hr))
  2634. {
  2635. //
  2636. // CScePropertyMgr helps us to access WMI object's properties
  2637. // create an instance and attach the WMI object to it.
  2638. // This will always succeed.
  2639. //
  2640. CScePropertyMgr ScePropMgr;
  2641. ScePropMgr.Attach(srpNewObj);
  2642. //
  2643. // store path is the only property not managed by the ISceClassObject
  2644. //
  2645. hr = ScePropMgr.PutProperty(pStorePath, pSceStore->GetExpandedPath());
  2646. if (FAILED(hr))
  2647. {
  2648. return hr;
  2649. }
  2650. //
  2651. // pszCompoundKey == pszNullKey means loading singleton (foreign object)
  2652. // or an abstract method call. So, pszNullKey means no need to populate
  2653. // key properties.
  2654. //
  2655. if (_wcsicmp(pszCompoundKey, pszNullKey) != 0)
  2656. {
  2657. hr = ::PopulateKeyProperties(pszCompoundKey, &ScePropMgr);
  2658. }
  2659. if (FAILED(hr))
  2660. {
  2661. return hr;
  2662. }
  2663. //
  2664. // now read the non-key properties and set each one
  2665. //
  2666. DWORD dwCount = 0;
  2667. m_srpObject->GetPropertyCount(SceProperty_NonKey, &dwCount);
  2668. for (int i = 0; i < dwCount; i++)
  2669. {
  2670. CComBSTR bstrPropName;
  2671. CComBSTR bstrKey;
  2672. //
  2673. // get i-th property name
  2674. //
  2675. hr = FormatNonKeyPropertyName(dwCookie, i, &bstrKey, &bstrPropName);
  2676. if (FAILED(hr))
  2677. {
  2678. break;
  2679. }
  2680. DWORD dwRead = 0;
  2681. //
  2682. // need to delete this memory
  2683. //
  2684. LPWSTR pszBuffer = NULL;
  2685. //
  2686. // the property may not be present in the store.
  2687. // So, ignore the result since the property may be missing in the store
  2688. //
  2689. if (SUCCEEDED(pSceStore->GetPropertyFromStore(pszSectionName, bstrKey, &pszBuffer, &dwRead)))
  2690. {
  2691. //
  2692. // translate the string to a variant and set the property
  2693. //
  2694. CComVariant var;
  2695. hr = ::VariantFromFormattedString(pszBuffer, &var);
  2696. if (SUCCEEDED(hr))
  2697. {
  2698. ScePropMgr.PutProperty(bstrPropName, &var);
  2699. }
  2700. }
  2701. delete [] pszBuffer;
  2702. }
  2703. if (SUCCEEDED(hr))
  2704. {
  2705. //
  2706. // give it to the out-bound parameter
  2707. //
  2708. *ppObj = srpNewObj.Detach();
  2709. hr = S_OK;
  2710. }
  2711. else
  2712. {
  2713. hr = WBEM_S_FALSE; // no instance loaded
  2714. }
  2715. }
  2716. }
  2717. return hr;
  2718. }
  2719. /*
  2720. Routine Description:
  2721. Name:
  2722. CScePersistMgr::Delete
  2723. Functionality:
  2724. Delete an instance from the store.
  2725. Virtual:
  2726. Yes. (function of IScePersistMgr)
  2727. Arguments:
  2728. bstrStorePath - the store.
  2729. pHandler - COM interface to notify WMI of successful operation.
  2730. Return Value:
  2731. Success:
  2732. (1) Various success codes.
  2733. Failure:
  2734. (1) E_UNEXPECTED means no successfully attached object.
  2735. (1) various other error codes.
  2736. Notes:
  2737. */
  2738. STDMETHODIMP
  2739. CScePersistMgr::Delete (
  2740. IN BSTR bstrStorePath,
  2741. IN IWbemObjectSink *pHandler
  2742. )
  2743. {
  2744. if (m_srpObject == NULL)
  2745. {
  2746. return E_UNEXPECTED;
  2747. }
  2748. if (bstrStorePath == NULL || pHandler == NULL)
  2749. {
  2750. return WBEM_E_INVALID_PARAMETER;
  2751. }
  2752. //
  2753. // we have an attached object, we must also know the section
  2754. // (actually, as it is now, it's the name of the class)
  2755. //
  2756. CComBSTR bstrSectionName;
  2757. HRESULT hr = GetSectionName(&bstrSectionName);
  2758. if (SUCCEEDED(hr))
  2759. {
  2760. CComBSTR bstrCompoundKey;
  2761. hr = GetCompoundKey(&bstrCompoundKey);
  2762. //
  2763. // Prepare a store (for persistence) for this store path (file)
  2764. //
  2765. CSceStore SceStore;
  2766. SceStore.SetPersistPath(bstrStorePath);
  2767. //
  2768. // if we can't create a complete compound cookie, then we are deleting everything of the class
  2769. //
  2770. if (hr == WBEM_S_FALSE)
  2771. {
  2772. //
  2773. // delete the whole section
  2774. //
  2775. SceStore.DeleteSectionFromStore(bstrSectionName);
  2776. }
  2777. else if (SUCCEEDED(hr))
  2778. {
  2779. //
  2780. // unique instance delete
  2781. // now create the instance list (cookies are enough) for the class
  2782. //
  2783. CExtClassInstCookieList clsInstCookies;
  2784. hr = clsInstCookies.Create(&SceStore, bstrSectionName, GetKeyPropertyNames(NULL, NULL));
  2785. if (SUCCEEDED(hr))
  2786. {
  2787. //
  2788. // see if we are really deleting the last one?
  2789. // if yes, then we can simply delete the section.
  2790. //
  2791. ExtClassCookieIterator it;
  2792. DWORD dwCookie = clsInstCookies.GetCompKeyCookie(bstrCompoundKey, &it);
  2793. if (dwCookie != INVALID_COOKIE && clsInstCookies.GetCookieCount() == 1)
  2794. {
  2795. //
  2796. // Yes, there is only one cookie and this is the one, so everything is gone
  2797. //
  2798. SceStore.DeleteSectionFromStore(bstrSectionName);
  2799. }
  2800. else
  2801. {
  2802. //
  2803. // remove the instance's key properties from the in-memory cookie list
  2804. //
  2805. dwCookie = clsInstCookies.RemoveCompKey(&SceStore, bstrSectionName, bstrCompoundKey);
  2806. //
  2807. // save the new list, this will effectively remove the instance's key properties
  2808. // from the store. Key properties are saved as part of the cookie list
  2809. //
  2810. hr = clsInstCookies.Save(&SceStore, bstrSectionName);
  2811. //
  2812. // now, delete non-key the properties
  2813. //
  2814. if (SUCCEEDED(hr))
  2815. {
  2816. hr = DeleteAllNonKeyProperties(&SceStore, dwCookie, bstrSectionName);
  2817. }
  2818. }
  2819. }
  2820. }
  2821. else
  2822. {
  2823. hr = WBEM_E_NOT_FOUND;
  2824. }
  2825. }
  2826. //
  2827. // Inform WMI that the action is complete
  2828. //
  2829. pHandler->SetStatus(WBEM_STATUS_COMPLETE, hr, NULL, NULL);
  2830. return hr;
  2831. }
  2832. /*
  2833. Routine Description:
  2834. Name:
  2835. CScePersistMgr::SaveProperties
  2836. Functionality:
  2837. Saves the non-key properties. Key properties are saved as part of the instance cookie list.
  2838. Virtual:
  2839. No.
  2840. Arguments:
  2841. pSceStore - the store.
  2842. dwCookie - the instance cookie.
  2843. pszSection - the section name.
  2844. Return Value:
  2845. Success:
  2846. (1) Various success codes.
  2847. Failure:
  2848. (1) various error codes.
  2849. Notes:
  2850. This is private helper. No checking against attached object's validity.
  2851. */
  2852. HRESULT
  2853. CScePersistMgr::SaveProperties (
  2854. IN CSceStore * pSceStore,
  2855. IN DWORD dwCookie,
  2856. IN LPCWSTR pszSection
  2857. )
  2858. {
  2859. DWORD dwCount = 0;
  2860. HRESULT hr = m_srpObject->GetPropertyCount(SceProperty_NonKey, &dwCount);
  2861. if (SUCCEEDED(hr))
  2862. {
  2863. for (DWORD dwIndex = 0; dwIndex < dwCount; dwIndex++)
  2864. {
  2865. //
  2866. // This is what is used to identify the property in the store.
  2867. // When you save a property, use this name.
  2868. //
  2869. CComBSTR bstrStorePropName;
  2870. //
  2871. // real name of the property
  2872. //
  2873. CComBSTR bstrTrueName;
  2874. //
  2875. // get the dwIndex-th non-key property names
  2876. //
  2877. hr = FormatNonKeyPropertyName(dwCookie, dwIndex, &bstrStorePropName, &bstrTrueName);
  2878. if (FAILED(hr))
  2879. {
  2880. break;
  2881. }
  2882. BSTR bstrData = NULL;
  2883. //
  2884. // get the dwIndex-th non-key property value in string format!
  2885. //
  2886. hr = FormatPropertyValue(SceProperty_NonKey, dwIndex, &bstrData);
  2887. //
  2888. // if a property is not present, we are fine with that.
  2889. //
  2890. if (SUCCEEDED(hr) && bstrData != NULL)
  2891. {
  2892. hr = pSceStore->SavePropertyToStore(pszSection, bstrStorePropName, bstrData);
  2893. ::SysFreeString(bstrData);
  2894. }
  2895. if (FAILED(hr))
  2896. {
  2897. break;
  2898. }
  2899. }
  2900. }
  2901. return hr;
  2902. }
  2903. /*
  2904. Routine Description:
  2905. Name:
  2906. CScePersistMgr::DeleteAllNonKeyProperties
  2907. Functionality:
  2908. Delete the non-key properties. Key properties are saved/delete as part of the instance cookie list.
  2909. Virtual:
  2910. No.
  2911. Arguments:
  2912. pSceStore - the store.
  2913. dwCookie - the instance cookie.
  2914. pszSection - the section name.
  2915. Return Value:
  2916. Success:
  2917. (1) Various success codes.
  2918. Failure:
  2919. (1) various error codes.
  2920. Notes:
  2921. This is private helper. No checking against attached object's validity.
  2922. */
  2923. HRESULT
  2924. CScePersistMgr::DeleteAllNonKeyProperties (
  2925. IN CSceStore * pSceStore,
  2926. IN DWORD dwCookie,
  2927. IN LPCWSTR pszSection
  2928. )
  2929. {
  2930. DWORD dwCount = 0;
  2931. HRESULT hr = m_srpObject->GetPropertyCount(SceProperty_NonKey, &dwCount);
  2932. HRESULT hrDelete = WBEM_NO_ERROR;
  2933. if (SUCCEEDED(hr))
  2934. {
  2935. for (DWORD dwIndex = 0; dwIndex < dwCount; dwIndex++)
  2936. {
  2937. //
  2938. // This is what is used to identify the property in the store.
  2939. // When you save a property, use this name.
  2940. //
  2941. CComBSTR bstrStorePropName;
  2942. CComBSTR bstrTrueName;
  2943. hr = FormatNonKeyPropertyName(dwCookie, dwIndex, &bstrStorePropName, &bstrTrueName);
  2944. if (FAILED(hr))
  2945. {
  2946. break;
  2947. }
  2948. //
  2949. // we will delete the property.
  2950. // In case of error, such deletion will continue, but the error will be reported
  2951. //
  2952. hr = pSceStore->DeletePropertyFromStore(pszSection, bstrStorePropName);
  2953. if (FAILED(hr))
  2954. {
  2955. hrDelete = hr;
  2956. }
  2957. }
  2958. }
  2959. return FAILED(hrDelete) ? hrDelete : hr;
  2960. }
  2961. /*
  2962. Routine Description:
  2963. Name:
  2964. CScePersistMgr::FormatNonKeyPropertyName
  2965. Functionality:
  2966. Given a non-key property index, get the property's real name and its instance-specific
  2967. name inside a store.
  2968. Currently, its name inside a store has the cookie's number prefixed to guarantee its
  2969. uniquess inside a section. This is a result of the .INF file format limitations.
  2970. Virtual:
  2971. No.
  2972. Arguments:
  2973. dwCookie - the instance cookie.
  2974. dwIndex - the index of the property.
  2975. pbstrStorePropName - The property's name inside the store for the instance
  2976. pbstrTrueName - The real name of the property
  2977. Return Value:
  2978. Success:
  2979. (1) Various success codes.
  2980. Failure:
  2981. (1) various error codes.
  2982. Notes:
  2983. This is private helper. No checking against attached object's validity.
  2984. */
  2985. HRESULT
  2986. CScePersistMgr::FormatNonKeyPropertyName (
  2987. IN DWORD dwCookie,
  2988. IN DWORD dwIndex,
  2989. OUT BSTR * pbstrStorePropName,
  2990. OUT BSTR * pbstrTrueName
  2991. )
  2992. {
  2993. if (pbstrStorePropName == NULL || pbstrTrueName == NULL)
  2994. {
  2995. return WBEM_E_INVALID_PARAMETER;
  2996. }
  2997. *pbstrStorePropName = NULL;
  2998. *pbstrTrueName = NULL;
  2999. //
  3000. // We are only interested in the name, not the value
  3001. //
  3002. HRESULT hr = m_srpObject->GetPropertyValue(SceProperty_NonKey, dwIndex, pbstrTrueName, NULL);
  3003. if (SUCCEEDED(hr))
  3004. {
  3005. int iNameLen = wcslen(*pbstrTrueName);
  3006. *pbstrStorePropName = ::SysAllocStringLen(NULL, MAX_INT_LENGTH + iNameLen + 1);
  3007. if (*pbstrStorePropName == NULL)
  3008. {
  3009. hr = WBEM_E_OUT_OF_MEMORY;
  3010. }
  3011. else
  3012. {
  3013. //
  3014. // prefix the real name with the cookie number.
  3015. //
  3016. wsprintf(*pbstrStorePropName, L"%d%s", dwCookie, *pbstrTrueName);
  3017. }
  3018. }
  3019. if (FAILED(hr))
  3020. {
  3021. //
  3022. // bstr might have been allocated. Free them
  3023. //
  3024. if (*pbstrTrueName != NULL)
  3025. {
  3026. ::SysFreeString(*pbstrTrueName);
  3027. *pbstrTrueName = NULL;
  3028. }
  3029. if (*pbstrStorePropName != NULL)
  3030. {
  3031. ::SysFreeString(*pbstrStorePropName);
  3032. *pbstrStorePropName = NULL;
  3033. }
  3034. }
  3035. return hr;
  3036. }
  3037. /*
  3038. Routine Description:
  3039. Name:
  3040. CScePersistMgr::FormatPropertyValue
  3041. Functionality:
  3042. Given the type (key or non-key) of and its index (of the property),
  3043. get the property's value in string format.
  3044. This works for both key and non-key properties.
  3045. Virtual:
  3046. No.
  3047. Arguments:
  3048. type - what type of property (key or non-key).
  3049. dwIndex - the index of the property.
  3050. pbstrValue - receives the value in string format
  3051. Return Value:
  3052. Success:
  3053. (1) Various success codes.
  3054. Failure:
  3055. (1) various error codes.
  3056. Notes:
  3057. This is private helper. No checking against attached object's validity.
  3058. */
  3059. HRESULT
  3060. CScePersistMgr::FormatPropertyValue (
  3061. IN SceObjectPropertyType type,
  3062. IN DWORD dwIndex,
  3063. OUT BSTR * pbstrValue
  3064. )
  3065. {
  3066. CComBSTR bstrName;
  3067. CComVariant varValue;
  3068. HRESULT hr = m_srpObject->GetPropertyValue(type, dwIndex, &bstrName, &varValue);
  3069. *pbstrValue = NULL;
  3070. if (SUCCEEDED(hr) && (varValue.vt != VT_EMPTY && varValue.vt != VT_NULL))
  3071. {
  3072. hr = ::FormatVariant(&varValue, pbstrValue);
  3073. }
  3074. return hr;
  3075. }
  3076. /*
  3077. Routine Description:
  3078. Name:
  3079. CScePersistMgr::GetCompoundKey
  3080. Functionality:
  3081. Given the type (key or non-key) of and its index (of the property),
  3082. get the property's value in string format.
  3083. This works for both key and non-key properties.
  3084. Virtual:
  3085. No.
  3086. Arguments:
  3087. pbstrKey - receives compound key in string format. See header file for format explanation.
  3088. Return Value:
  3089. Success:
  3090. (1) WBEM_S_FALSE if information doesn't give complete key properties.
  3091. (2) WBEM_NO_ERROR if the compond key is successfully generated.
  3092. Failure:
  3093. (1) various error codes.
  3094. Notes:
  3095. This is private helper. No checking against attached object's validity.
  3096. */
  3097. HRESULT
  3098. CScePersistMgr::GetCompoundKey (
  3099. OUT BSTR* pbstrKey
  3100. )
  3101. {
  3102. if (pbstrKey == NULL)
  3103. {
  3104. return WBEM_E_INVALID_PARAMETER;
  3105. }
  3106. *pbstrKey = NULL;
  3107. DWORD dwCount = 0;
  3108. HRESULT hr = m_srpObject->GetPropertyCount(SceProperty_Key, &dwCount);
  3109. if (SUCCEEDED(hr) && dwCount == 0)
  3110. {
  3111. //
  3112. // no key, must be singleton/static, thus no compound key
  3113. //
  3114. *pbstrKey = ::SysAllocString(pszNullKey);
  3115. return WBEM_S_FALSE;
  3116. }
  3117. if (SUCCEEDED(hr))
  3118. {
  3119. //
  3120. // these are the individual key property's format string
  3121. //
  3122. CComBSTR *pbstrKeyProperties = new CComBSTR[dwCount];
  3123. if (pbstrKeyProperties == NULL)
  3124. {
  3125. return WBEM_E_OUT_OF_MEMORY;
  3126. }
  3127. DWORD dwTotalLen = 0;
  3128. //
  3129. // for each key property, we will format the (prop, value) pair
  3130. // into prop<vt:value> format
  3131. //
  3132. for (DWORD dwIndex = 0; dwIndex < dwCount; dwIndex++)
  3133. {
  3134. CComVariant var;
  3135. //
  3136. // put the property name to pbstrKeyProperties[dwIndex] first.
  3137. //
  3138. hr = m_srpObject->GetPropertyValue(SceProperty_Key, dwIndex, &pbstrKeyProperties[dwIndex], &var);
  3139. if (FAILED(hr) || var.vt == VT_NULL || var.vt == VT_EMPTY)
  3140. {
  3141. //
  3142. // will quit because we don't have enough information,
  3143. // but just that we can't find the key property value.
  3144. // We'd like to be more specific about the error. However, we have observed that
  3145. // WMI will return inconsistent code for not finding the property. Sometimes it
  3146. // simply returns success but without a value in the variant. But other times, it
  3147. // returns errors. We have to treat it as if the property is not present in the object.
  3148. //
  3149. hr = WBEM_S_FALSE;
  3150. break;
  3151. }
  3152. //
  3153. // put the variant's value in string format (like <VT_I4 : 123456>)
  3154. //
  3155. CComBSTR bstrData;
  3156. hr = ::FormatVariant(&var, &bstrData);
  3157. if (SUCCEEDED(hr))
  3158. {
  3159. //
  3160. // append the value to pbstrKeyProperties[dwIndex] so that
  3161. // pbstrKeyProperties[dwIndex] all have this format: PropName<VT_TYPE : value>
  3162. //
  3163. pbstrKeyProperties[dwIndex] += bstrData;
  3164. }
  3165. else
  3166. {
  3167. break;
  3168. }
  3169. //
  3170. // so that we can re-use it
  3171. //
  3172. bstrData.Empty();
  3173. //
  3174. // keep track of total length
  3175. //
  3176. dwTotalLen += wcslen(pbstrKeyProperties[dwIndex]);
  3177. }
  3178. //
  3179. // hr == WBEM_S_FALSE indicates no compound key
  3180. //
  3181. if (SUCCEEDED(hr) && hr != WBEM_S_FALSE)
  3182. {
  3183. //
  3184. // now, we are ready to generate the final buffer for the caller
  3185. // 1 for the '\0' terminator
  3186. //
  3187. *pbstrKey = ::SysAllocStringLen(NULL, dwTotalLen + 1);
  3188. if (*pbstrKey != NULL)
  3189. {
  3190. //
  3191. // pszCur is the current point to write
  3192. //
  3193. LPWSTR pszCur = *pbstrKey;
  3194. DWORD dwLen;
  3195. //
  3196. // pack each pbstrKeyProperties[dwIndex] into the final bstr
  3197. //
  3198. for (dwIndex = 0; dwIndex < dwCount; dwIndex++)
  3199. {
  3200. dwLen = wcslen(pbstrKeyProperties[dwIndex]);
  3201. //
  3202. // Since each pbstrKeyProperties[dwIndex] is a CComBSTR,
  3203. // do some casting to remove any ambiguity.
  3204. //
  3205. ::memcpy(pszCur, (const void*)(LPCWSTR)(pbstrKeyProperties[dwIndex]), dwLen * sizeof(WCHAR));
  3206. //
  3207. // move the current write point
  3208. //
  3209. pszCur += dwLen;
  3210. }
  3211. (*pbstrKey)[dwTotalLen] = L'\0';
  3212. }
  3213. else
  3214. {
  3215. hr = WBEM_E_OUT_OF_MEMORY;
  3216. }
  3217. }
  3218. //
  3219. // we are done with the individual parts
  3220. //
  3221. delete [] pbstrKeyProperties;
  3222. }
  3223. //
  3224. // truly successfully generated the compound key
  3225. //
  3226. if (SUCCEEDED(hr) && hr != WBEM_S_FALSE)
  3227. {
  3228. hr = WBEM_NO_ERROR;
  3229. }
  3230. return hr;
  3231. }
  3232. /*
  3233. Routine Description:
  3234. Name:
  3235. GetKeyPropertyNames
  3236. Functionality:
  3237. private helper. Will get this class's key property names vector
  3238. Virtual:
  3239. No.
  3240. Arguments:
  3241. pNamespace - The provider namespace.
  3242. pCtx - The context pointer that we are given and pass around for WMI API's.
  3243. Return Value:
  3244. Success: Non-NULL.
  3245. Failure: NULL.
  3246. Notes:
  3247. */
  3248. std::vector<LPWSTR>*
  3249. CScePersistMgr::GetKeyPropertyNames (
  3250. IN IWbemServices * pNamespace,
  3251. IN IWbemContext * pCtx
  3252. )
  3253. {
  3254. CComBSTR bstrClassName;
  3255. HRESULT hr = GetClassName(&bstrClassName);
  3256. if (FAILED(hr))
  3257. {
  3258. return NULL;
  3259. }
  3260. const CForeignClassInfo* pFCInfo = NULL;
  3261. if (SUCCEEDED(hr))
  3262. {
  3263. pFCInfo = g_ExtClasses.GetForeignClassInfo(pNamespace, pCtx, bstrClassName);
  3264. }
  3265. if (pFCInfo == NULL)
  3266. {
  3267. return NULL;
  3268. }
  3269. else
  3270. {
  3271. return pFCInfo->m_pVecKeyPropNames;
  3272. }
  3273. }
  3274. //
  3275. // Implementing those global helper parsing related functions.
  3276. //
  3277. /*
  3278. Routine Description:
  3279. Name:
  3280. FormatVariant
  3281. Functionality:
  3282. Given a variant, we will get our format of string representing the variant value.
  3283. For example, if pVar is of VT_I4 type and value 12345, this function will return:
  3284. < VT_I4 : 12345 >;
  3285. We also support arrays. For example, a safearray of bstrs that has "This is "
  3286. value at its first element and "Microsoft SCE" at its second value will receive:
  3287. < VT_ARRAY(VT_BSTR) : "This is " , "Microsoft SCE" >;
  3288. Virtual:
  3289. N/A.
  3290. Arguments:
  3291. pVar - The variant.
  3292. pbstrData - The string (in our format) receives the formatted string.
  3293. Return Value:
  3294. Success: WBEM_NO_ERROR.
  3295. Failure: Various errors may occurs.
  3296. Most obvious is
  3297. WBEM_E_INVALID_SYNTAX,
  3298. WBEM_E_OUT_OF_MEMORY,
  3299. WBEM_E_NOT_SUPPORTED
  3300. Notes:
  3301. */
  3302. HRESULT
  3303. FormatVariant (
  3304. IN VARIANT * pVar,
  3305. OUT BSTR * pbstrData
  3306. )
  3307. {
  3308. if (pVar == NULL || pbstrData == NULL)
  3309. {
  3310. return WBEM_E_INVALID_PARAMETER;
  3311. }
  3312. HRESULT hr = WBEM_NO_ERROR;
  3313. *pbstrData = NULL;
  3314. //
  3315. // if it is not a safearray
  3316. //
  3317. if ( (pVar->vt & VT_ARRAY) != VT_ARRAY)
  3318. {
  3319. CComBSTR bstrValue;
  3320. hr = ::GetStringPresentation(pVar, &bstrValue);
  3321. LPCWSTR pszType = gVtToStringMap.GetTypeString(pVar->vt);
  3322. if (SUCCEEDED(hr) && pszType)
  3323. {
  3324. //
  3325. // formatted string has both type and value information
  3326. //
  3327. ULONG uLen = wcslen(bstrValue);
  3328. ULONG uTypeLen = wcslen(pszType);
  3329. ULONG uTotalLen = uLen + uTypeLen + 4;
  3330. //
  3331. // don't be surprised that we do the formatting this way, it turns out that
  3332. // wsprintf doesn't work for strings longer than 1K
  3333. //
  3334. *pbstrData = ::SysAllocStringLen(NULL, uTotalLen);
  3335. if (*pbstrData != NULL)
  3336. {
  3337. //
  3338. // this is the current point to write formatted string
  3339. //
  3340. LPWSTR pszCurDataPtr = *pbstrData;
  3341. //
  3342. // put the < character and move one index
  3343. //
  3344. pszCurDataPtr[0] = wchTypeValLeft;
  3345. ++pszCurDataPtr;
  3346. //
  3347. // write the type string, like VT_BSTR, and move over that many characters
  3348. //
  3349. memcpy(pszCurDataPtr, pszType, uTypeLen * sizeof(WCHAR));
  3350. pszCurDataPtr += uTypeLen;
  3351. //
  3352. // put the type and value separater, and move one index
  3353. //
  3354. pszCurDataPtr[0] = wchTypeValSep;
  3355. ++pszCurDataPtr;
  3356. //
  3357. // put the value and value separater, and move over that many characters
  3358. //
  3359. memcpy(pszCurDataPtr, bstrValue, uLen * sizeof(WCHAR));
  3360. pszCurDataPtr += uLen;
  3361. //
  3362. // put the < character and move one index
  3363. //
  3364. pszCurDataPtr[0] = wchTypeValRight;
  3365. pszCurDataPtr[1] = L'\0';
  3366. }
  3367. else
  3368. {
  3369. hr = WBEM_E_OUT_OF_MEMORY;
  3370. }
  3371. }
  3372. else if (SUCCEEDED(hr))
  3373. {
  3374. hr = WBEM_E_NOT_SUPPORTED;
  3375. }
  3376. }
  3377. else
  3378. {
  3379. hr = ::FormatArray(pVar, pbstrData);
  3380. }
  3381. return hr;
  3382. }
  3383. /*
  3384. Routine Description:
  3385. Name:
  3386. GetObjectPath
  3387. Functionality:
  3388. Given a store path and an instance's compound key, this will generate the instance's path.
  3389. This is to reduce WMI traffic. WMI uses paths to execute method. But we don't have path until
  3390. the object is avaiable. As a result, we need to read the object out (which may contain many
  3391. properties), and then get the path and feed the path to WMI to execute a method. When WMI receives
  3392. that request, it again ask us for the object (using the path we gave in the above sequence)
  3393. and we have to load the instance again.
  3394. This is obviously too much traffic. So, to reduce the traffic, we will create the path ourselves.
  3395. For each class, we have a cookie list. For each instance, we have a cookie in the cookie list.
  3396. For each cookie, we know the compound key very easily (key property counts are always small).
  3397. This function creates a path based on the compound key.
  3398. Virtual:
  3399. N/A.
  3400. Arguments:
  3401. pSpawn - COM interface pointer that has all the class definition. We need this
  3402. to for the path creation.
  3403. pszStorePath - The store's path
  3404. pszCompoundKey - The instance's compound key
  3405. pbstrPath - receives the path.
  3406. Return Value:
  3407. Success:
  3408. (1) various success codes.
  3409. Failure:
  3410. (1) various error codes.
  3411. Notes:
  3412. As usual, caller is responsible for freeing the bstr.
  3413. */
  3414. HRESULT
  3415. GetObjectPath (
  3416. IN IWbemClassObject * pSpawn,
  3417. IN LPCWSTR pszStorePath,
  3418. IN LPCWSTR pszCompoundKey,
  3419. OUT BSTR * pbstrPath
  3420. )
  3421. {
  3422. if (pSpawn == NULL ||
  3423. pszCompoundKey == NULL ||
  3424. *pszCompoundKey == L'\0' ||
  3425. pbstrPath == NULL )
  3426. {
  3427. return WBEM_E_INVALID_PARAMETER;
  3428. }
  3429. *pbstrPath = NULL;
  3430. //
  3431. // this instance is not going to live beyond the scope of the function
  3432. //
  3433. CComPtr<IWbemClassObject> srpTempObj;
  3434. HRESULT hr = pSpawn->SpawnInstance(0, &srpTempObj);
  3435. DWORD dwLoadedProperties = 0;
  3436. //
  3437. // We will populate the key properties into this temp object and ask it for the path
  3438. //
  3439. if (SUCCEEDED(hr))
  3440. {
  3441. if (SUCCEEDED(hr))
  3442. {
  3443. CScePropertyMgr ScePropMgr;
  3444. ScePropMgr.Attach(srpTempObj);
  3445. //
  3446. // this is the only property not managed by the ISceClassObject
  3447. //
  3448. hr = ScePropMgr.PutProperty(pStorePath, pszStorePath);
  3449. if (FAILED(hr))
  3450. {
  3451. return hr;
  3452. }
  3453. if (_wcsicmp(pszCompoundKey, pszNullKey) != 0)
  3454. {
  3455. hr = PopulateKeyProperties(pszCompoundKey, &ScePropMgr);
  3456. }
  3457. }
  3458. }
  3459. if (SUCCEEDED(hr))
  3460. {
  3461. CComVariant varPath;
  3462. //
  3463. // a fully populated (as far as key properties are concerned) will have a path
  3464. //
  3465. hr = srpTempObj->Get(L"__RelPath", 0, &varPath, NULL, NULL);
  3466. if (SUCCEEDED(hr) && varPath.vt == VT_BSTR)
  3467. {
  3468. //
  3469. // this is it.
  3470. //
  3471. *pbstrPath = varPath.bstrVal;
  3472. //
  3473. // since the bstr is now owned by the out parameter, we'd better stop the auto-destruction
  3474. // by CComVariant
  3475. //
  3476. varPath.bstrVal = NULL;
  3477. varPath.vt = VT_EMPTY;
  3478. }
  3479. }
  3480. return hr;
  3481. }
  3482. /*
  3483. Routine Description:
  3484. Name:
  3485. VariantFromFormattedString
  3486. Functionality:
  3487. Given a formatted string representing a variant value, transform it to a variant value.
  3488. For example,
  3489. VariantFromFormattedString(L"<VT_I4 : 12345>", &var);
  3490. will assign VT_I4 value 12345 to var.
  3491. We also support arrays. For example,
  3492. VariantFromFormattedString(L"<VT_ARRAY(VT_BSTR) : "This is " , "Microsoft SCE" >", &var);
  3493. will assign VT_ARRAY | VT_BSTR to var and it contains a safearray of bstrs that has "This is "
  3494. value at its first element and "Microsoft SCE" at its second value.
  3495. Virtual:
  3496. N/A.
  3497. Arguments:
  3498. pszString - The string (in our format) representing a value.
  3499. pVar - receives the variant value.
  3500. Return Value:
  3501. Success: WBEM_NO_ERROR.
  3502. Failure: Various errors may occurs.
  3503. Most obvious is
  3504. WBEM_E_INVALID_SYNTAX,
  3505. WBEM_E_OUT_OF_MEMORY,
  3506. WBEM_E_NOT_SUPPORTED
  3507. Notes:
  3508. */
  3509. HRESULT
  3510. VariantFromFormattedString (
  3511. IN LPCWSTR pszString,
  3512. OUT VARIANT* pVar
  3513. )
  3514. {
  3515. // USES_CONVERSION;
  3516. if (pszString == NULL || pVar == NULL)
  3517. {
  3518. return WBEM_E_INVALID_PARAMETER;
  3519. }
  3520. ::VariantInit(pVar);
  3521. //
  3522. // the current point of parsing
  3523. //
  3524. LPCWSTR pCur = pszString;
  3525. //
  3526. // scan the string for <xxx:
  3527. // the last parameter true indicates that we want the see to move to end
  3528. // if the wanted char was not found.
  3529. //
  3530. bool bEscaped = false;
  3531. pCur = ::EscSeekToChar(pCur, wchTypeValLeft, &bEscaped, true);
  3532. if (*pCur == L'\0')
  3533. {
  3534. //
  3535. // no value is encoded
  3536. //
  3537. return WBEM_NO_ERROR;
  3538. }
  3539. //
  3540. // pCur points to '<'. skip the <
  3541. //
  3542. ++pCur;
  3543. //
  3544. // seek till ':'
  3545. //
  3546. LPCWSTR pNext = ::EscSeekToChar(pCur, wchTypeValSep, &bEscaped, true);
  3547. //
  3548. // must contain something before ':'
  3549. //
  3550. if (*pNext != wchTypeValSep || pCur == pNext)
  3551. {
  3552. return WBEM_E_INVALID_SYNTAX;
  3553. }
  3554. //
  3555. // length of the found token
  3556. //
  3557. int iTokenLen = pNext - pCur;
  3558. LPWSTR pszType = new WCHAR[iTokenLen + 1]; // need to release the memory
  3559. if (pszType == NULL)
  3560. {
  3561. return WBEM_E_OUT_OF_MEMORY;
  3562. }
  3563. //
  3564. // copy the token, but trim the white space at both ends
  3565. //
  3566. ::TrimCopy(pszType, pCur, iTokenLen);
  3567. VARTYPE varSubType;
  3568. VARTYPE varVT = gStringToVtMap.GetType(pszType, &varSubType);
  3569. //
  3570. // done with the type string
  3571. //
  3572. delete [] pszType;
  3573. if (varVT == VT_EMPTY)
  3574. {
  3575. return WBEM_E_NOT_SUPPORTED;
  3576. }
  3577. //
  3578. // must have more data
  3579. //
  3580. pCur = ++pNext; // pCur point to char after ':'
  3581. if (*pCur == L'\0')
  3582. {
  3583. return WBEM_E_INVALID_SYNTAX;
  3584. }
  3585. pNext = ::EscSeekToChar(pCur, wchTypeValRight, &bEscaped, true); // move to end if not found
  3586. //
  3587. // must see '>'
  3588. //
  3589. if (*pNext != wchTypeValRight)
  3590. {
  3591. return WBEM_E_INVALID_SYNTAX;
  3592. }
  3593. //
  3594. // length of the found token
  3595. //
  3596. iTokenLen = pNext - pCur;
  3597. LPWSTR pszValue = new WCHAR[iTokenLen + 1]; // need to release the memory
  3598. if (pszValue == NULL)
  3599. {
  3600. return WBEM_E_OUT_OF_MEMORY;
  3601. }
  3602. //
  3603. // copy the token, but trim the white space at both ends
  3604. //
  3605. ::TrimCopy(pszValue, pCur, iTokenLen);
  3606. HRESULT hr = WBEM_NO_ERROR;
  3607. //
  3608. // arrays not more complicated to format
  3609. //
  3610. if ((varVT & VT_ARRAY) != VT_ARRAY)
  3611. {
  3612. hr = ::VariantFromStringValue(pszValue, varVT, pVar);
  3613. }
  3614. else
  3615. {
  3616. hr = ::ArrayFromFormatString(pszValue, varSubType, pVar);
  3617. }
  3618. delete [] pszValue;
  3619. return hr;
  3620. }
  3621. /*
  3622. Routine Description:
  3623. Name:
  3624. VariantFromStringValue
  3625. Functionality:
  3626. Given a formatted string representing a variant value, transform it to a variant value.
  3627. For example,
  3628. VariantFromStringValue(L"12345", VT_I4, &var);
  3629. will assign VT_I4 value 12345 to var.
  3630. We do not support array at this function. That is done ArrayFromFormatString.
  3631. Virtual:
  3632. N/A.
  3633. Arguments:
  3634. szValue - The string (in our format) representing a value.
  3635. vt - VARTYPE
  3636. pVar - receives the variant value.
  3637. Return Value:
  3638. Success: WBEM_NO_ERROR.
  3639. Failure: Various errors may occurs.
  3640. Most obvious is
  3641. WBEM_E_INVALID_PARAMETER,
  3642. WBEM_E_INVALID_SYNTAX,
  3643. WBEM_E_OUT_OF_MEMORY,
  3644. WBEM_E_NOT_SUPPORTED
  3645. Notes:
  3646. */
  3647. HRESULT
  3648. VariantFromStringValue (
  3649. IN LPCWSTR szValue,
  3650. IN VARTYPE vt,
  3651. IN VARIANT * pVar
  3652. )
  3653. {
  3654. //
  3655. // so that we can use those W2CA like macros
  3656. //
  3657. USES_CONVERSION;
  3658. if (szValue == NULL || *szValue == L'\0' || pVar == NULL)
  3659. {
  3660. return WBEM_E_INVALID_PARAMETER;
  3661. }
  3662. ::VariantInit(pVar);
  3663. pVar->vt = vt;
  3664. HRESULT hr = WBEM_NO_ERROR;
  3665. switch (vt)
  3666. {
  3667. case VT_BSTR:
  3668. hr = ::DeEscapeStringData(szValue, &(pVar->bstrVal), true);
  3669. break;
  3670. case VT_BOOL:
  3671. if (*szValue == L'0' || _wcsicmp(szValue, L"FALSE") == 0)
  3672. {
  3673. pVar->boolVal = VARIANT_FALSE;
  3674. }
  3675. else
  3676. {
  3677. pVar->boolVal = VARIANT_TRUE;
  3678. }
  3679. break;
  3680. case VT_I2:
  3681. pVar->iVal = (short)(_wtol(szValue));
  3682. break;
  3683. case VT_UI1:
  3684. pVar->bVal = (BYTE)(_wtol(szValue));
  3685. break;
  3686. case VT_UI2:
  3687. pVar->uiVal = (USHORT)(_wtol(szValue));
  3688. break;
  3689. case VT_UI4:
  3690. pVar->ulVal = (ULONG)(_wtol(szValue));
  3691. break;
  3692. case VT_I4:
  3693. pVar->lVal = (long)(_wtol(szValue));
  3694. break;
  3695. case VT_DATE:
  3696. case VT_R4:
  3697. case VT_R8:
  3698. {
  3699. double fValue = atof(W2CA(szValue));
  3700. if (vt == VT_DATE)
  3701. {
  3702. pVar->date = fValue;
  3703. }
  3704. else if (vt == VT_R4)
  3705. {
  3706. pVar->fltVal = (float)fValue;
  3707. }
  3708. else
  3709. {
  3710. pVar->dblVal = fValue;
  3711. }
  3712. }
  3713. break;
  3714. case VT_CY:
  3715. hr = ::CurrencyFromFormatString(szValue, pVar);
  3716. break;
  3717. default:
  3718. hr = WBEM_E_NOT_SUPPORTED;
  3719. break;
  3720. }
  3721. if (FAILED(hr))
  3722. {
  3723. ::VariantInit(pVar);
  3724. }
  3725. return hr;
  3726. }
  3727. /*
  3728. Routine Description:
  3729. Name:
  3730. CurrencyFromFormatString
  3731. Functionality:
  3732. Given a formatted string representing a currency value, translate into a variant.
  3733. Virtual:
  3734. N/A.
  3735. Arguments:
  3736. lpszFmtStr - The string (in our format) representing currency value.
  3737. pVar - receives the variant value.
  3738. Return Value:
  3739. Success: WBEM_NO_ERROR.
  3740. Failure: Various errors may occurs.
  3741. Most obvious is
  3742. WBEM_E_INVALID_SYNTAX,
  3743. WBEM_E_INVALID_PARAMETER
  3744. Notes:
  3745. */
  3746. HRESULT
  3747. CurrencyFromFormatString (
  3748. IN LPCWSTR lpszFmtStr,
  3749. OUT VARIANT * pVar
  3750. )
  3751. {
  3752. if (lpszFmtStr == NULL || pVar == NULL)
  3753. {
  3754. return WBEM_E_INVALID_PARAMETER;
  3755. }
  3756. ::VariantInit(pVar);
  3757. pVar->vt = VT_CY;
  3758. LPCWSTR lpszDot = lpszFmtStr;
  3759. while (*lpszDot != L'\0' && *lpszDot != wchCySeparator)
  3760. {
  3761. ++lpszDot;
  3762. }
  3763. if (*lpszDot != wchCySeparator)
  3764. {
  3765. return WBEM_E_INVALID_SYNTAX;
  3766. }
  3767. else
  3768. {
  3769. pVar->cyVal.Lo = (short)(_wtol(lpszDot + 1));
  3770. //
  3771. // _wtol won't read past the dot
  3772. //
  3773. pVar->cyVal.Hi = (short)(_wtol(lpszFmtStr));
  3774. }
  3775. return WBEM_NO_ERROR;
  3776. }
  3777. /*
  3778. Routine Description:
  3779. Name:
  3780. ArrayFromFormatString
  3781. Functionality:
  3782. Given a formatted string representing array value, translate into a variant.
  3783. Virtual:
  3784. N/A.
  3785. Arguments:
  3786. lpszFmtStr - The string (in our format) representing array value.
  3787. vt - sub type (the array's element type)
  3788. pVar - receives the variant value.
  3789. Return Value:
  3790. Success: WBEM_NO_ERROR.
  3791. Failure: Various errors may occurs.
  3792. Most obvious is
  3793. WBEM_E_INVALID_SYNTAX,
  3794. WBEM_E_INVALID_PARAMETER
  3795. Notes:
  3796. */
  3797. HRESULT
  3798. ArrayFromFormatString (
  3799. IN LPCWSTR lpszFmtStr,
  3800. IN VARTYPE vt,
  3801. OUT VARIANT * pVar
  3802. )
  3803. {
  3804. if (lpszFmtStr == NULL || pVar == NULL)
  3805. {
  3806. return WBEM_E_INVALID_PARAMETER;
  3807. }
  3808. ::VariantInit(pVar);
  3809. //
  3810. // need to find out how many are there in the array, we will just count the delimiter wchValueSep == ','
  3811. //
  3812. LPCWSTR pszCur = lpszFmtStr;
  3813. //
  3814. // get the count
  3815. //
  3816. DWORD dwCount = 1;
  3817. bool bEscaped;
  3818. while (pszCur = EscSeekToChar(pszCur, wchValueSep, &bEscaped, false))
  3819. {
  3820. ++dwCount;
  3821. ++pszCur; // skip the separator
  3822. }
  3823. //
  3824. // we know this is the type
  3825. //
  3826. pVar->vt = VT_ARRAY | vt;
  3827. //
  3828. // create a safearray
  3829. //
  3830. SAFEARRAYBOUND rgsabound[1];
  3831. rgsabound[0].lLbound = 0;
  3832. rgsabound[0].cElements = dwCount;
  3833. pVar->parray = ::SafeArrayCreate(vt, 1, rgsabound);
  3834. HRESULT hr = WBEM_NO_ERROR;
  3835. if (pVar->parray == NULL)
  3836. {
  3837. hr = WBEM_E_OUT_OF_MEMORY;
  3838. }
  3839. else
  3840. {
  3841. long lIndecies[1];
  3842. LPCWSTR pszNext = pszCur = lpszFmtStr;
  3843. long lLength = 0;
  3844. //
  3845. // pszValue will be used to hold each individual value. This buffer
  3846. // is generous enough. Need to free the memory.
  3847. //
  3848. LPWSTR pszValue = new WCHAR[wcslen(lpszFmtStr) + 1];
  3849. if (pszValue == NULL)
  3850. {
  3851. hr = WBEM_E_OUT_OF_MEMORY;
  3852. }
  3853. else
  3854. {
  3855. //
  3856. // all values are separated by the character wchValueSep
  3857. // We will loop through and get each value out and put them
  3858. // into the safearray
  3859. //
  3860. for (DWORD dwIndex = 0; dwIndex < dwCount; dwIndex++)
  3861. {
  3862. pszNext = ::EscSeekToChar(pszCur, wchValueSep, &bEscaped, true);
  3863. if (pszNext == pszCur)
  3864. {
  3865. break;
  3866. }
  3867. lLength = pszNext - pszCur;
  3868. lIndecies[0] = dwIndex;
  3869. ::TrimCopy(pszValue, pszCur, lLength);
  3870. VARIANT var;
  3871. hr = ::VariantFromStringValue(pszValue, vt, &var);
  3872. if (FAILED(hr))
  3873. {
  3874. break;
  3875. }
  3876. if (vt == VT_BSTR)
  3877. {
  3878. hr = ::SafeArrayPutElement(pVar->parray, lIndecies, var.bstrVal);
  3879. }
  3880. else
  3881. {
  3882. hr = ::SafeArrayPutElement(pVar->parray, lIndecies, ::GetVoidPtrOfVariant(var.vt, &var));
  3883. }
  3884. ::VariantClear(&var);
  3885. if (FAILED(hr))
  3886. {
  3887. break;
  3888. }
  3889. pszCur = pszNext;
  3890. //
  3891. // we won't quit until we see the end of the buffer.
  3892. //
  3893. if (*pszCur != L'\0')
  3894. {
  3895. ++pszCur;
  3896. }
  3897. else
  3898. {
  3899. break;
  3900. }
  3901. }
  3902. delete [] pszValue;
  3903. }
  3904. }
  3905. if (FAILED(hr))
  3906. {
  3907. ::VariantClear(pVar);
  3908. }
  3909. return hr;
  3910. }
  3911. /*
  3912. Routine Description:
  3913. Name:
  3914. FormatArray
  3915. Functionality:
  3916. Given a variant, get the formatted (our format) string representation.
  3917. For example, given a variant of array (say, 3 elements) of VT_I4 of value 1, 2, 3, this function
  3918. will give < VT_ARRAY(VT_I4) : 1, 2, 3, >
  3919. For example, given a variant of array (say, 3 elements) VT_BSTR of value
  3920. "Microsoft", "Security" "Configuration", this function
  3921. will give < VT_ARRAY(VT_BSTR) : "Microsoft" , "Security", "Configuration" >
  3922. Virtual:
  3923. N/A.
  3924. Arguments:
  3925. pVar - The varaint to be formatted. Must be a safearray
  3926. pbstrData - Receive the formatted string.
  3927. Return Value:
  3928. Success: WBEM_NO_ERROR.
  3929. Failure: Various errors may occurs.
  3930. Most obvious is
  3931. WBEM_E_INVALID_SYNTAX,
  3932. WBEM_E_INVALID_PARAMETER
  3933. Notes:
  3934. */
  3935. HRESULT
  3936. FormatArray (
  3937. IN VARIANT * pVar,
  3938. OUT BSTR * pbstrData
  3939. )
  3940. {
  3941. if (pVar == NULL || pbstrData == NULL || (pVar->vt & VT_ARRAY) != VT_ARRAY)
  3942. {
  3943. return WBEM_E_INVALID_PARAMETER;
  3944. }
  3945. *pbstrData = NULL;
  3946. VARTYPE vtSub = ::GetSubType(pVar->vt);
  3947. long lLowerBound, lUpperBound;
  3948. HRESULT hr = ::SafeArrayGetLBound(pVar->parray, 1, &lLowerBound);
  3949. if (FAILED(hr))
  3950. {
  3951. return hr;
  3952. }
  3953. hr = ::SafeArrayGetUBound(pVar->parray, 1, &lUpperBound);
  3954. if (FAILED(hr))
  3955. {
  3956. return hr;
  3957. }
  3958. long lIndexes[1];
  3959. //
  3960. // get lUpperBound - lLowerBound + 1 bstrs and set all to NULL
  3961. //
  3962. BSTR * pbstrArray = new BSTR[lUpperBound - lLowerBound + 1];
  3963. if (pbstrArray == NULL)
  3964. {
  3965. return WBEM_E_OUT_OF_MEMORY;
  3966. }
  3967. ::memset(pbstrArray, 0, sizeof(BSTR) * (lUpperBound - lLowerBound + 1));
  3968. //
  3969. // this is the nightmare to deal with CComBSTR's appending, its += operator
  3970. // doesn't work for loops!
  3971. //
  3972. long lTotalLen = 0;
  3973. LPWSTR pszNextToWrite = NULL;
  3974. for (long i = lLowerBound; i <= lUpperBound; i++)
  3975. {
  3976. CComBSTR bstrValue;
  3977. CComVariant var;
  3978. var.vt = vtSub;
  3979. //
  3980. // i-th element of the array
  3981. //
  3982. lIndexes[0] = i;
  3983. void* pv = ::GetVoidPtrOfVariant(vtSub, &var);
  3984. hr = ::SafeArrayGetElement(pVar->parray, lIndexes, pv);
  3985. if (FAILED(hr))
  3986. {
  3987. break;
  3988. }
  3989. hr = ::GetStringPresentation(&var, &bstrValue);
  3990. if (FAILED(hr))
  3991. {
  3992. break;
  3993. }
  3994. int iValueLen = wcslen(bstrValue);
  3995. if (i == 0)
  3996. {
  3997. //
  3998. // This is the start of the format, we need to get the VARTYPE string.
  3999. // first, put the type string.
  4000. //
  4001. LPCWSTR pszType = gVtToStringMap.GetTypeString(VT_ARRAY, vtSub);
  4002. if (pszType == NULL)
  4003. {
  4004. hr = WBEM_E_NOT_SUPPORTED;
  4005. break;
  4006. }
  4007. int iTypeLen = wcslen(pszType);
  4008. pbstrArray[i] = ::SysAllocStringLen(NULL, 1 + iTypeLen + 1 + iValueLen + 2);
  4009. if (pbstrArray[i] == (LPCWSTR)NULL)
  4010. {
  4011. hr = WBEM_E_OUT_OF_MEMORY;
  4012. break;
  4013. }
  4014. pszNextToWrite = pbstrArray[i];
  4015. //
  4016. // put the separator, move over one wchar position
  4017. //
  4018. pszNextToWrite[0] = wchTypeValLeft;
  4019. ++pszNextToWrite;
  4020. ::memcpy(pszNextToWrite, pszType, iTypeLen * sizeof(WCHAR));
  4021. //
  4022. // have copied over that many WCHAR, move that many positions.
  4023. //
  4024. pszNextToWrite += iTypeLen;
  4025. //
  4026. // put the separator, move over one wchar position
  4027. //
  4028. pszNextToWrite[0] = wchTypeValSep;
  4029. ++pszNextToWrite;
  4030. ::memcpy(pszNextToWrite, (void*)((LPCWSTR)bstrValue), iValueLen * sizeof(WCHAR));
  4031. //
  4032. // have copied over that many WCHAR, move that many positions.
  4033. //
  4034. pszNextToWrite += iValueLen;
  4035. }
  4036. else
  4037. {
  4038. //
  4039. // not the first value any more
  4040. //
  4041. pbstrArray[i] = ::SysAllocStringLen(NULL, 1 + iValueLen + 2);
  4042. if (pbstrArray[i] == (LPCWSTR)NULL)
  4043. {
  4044. hr = WBEM_E_OUT_OF_MEMORY;
  4045. break;
  4046. }
  4047. pszNextToWrite = pbstrArray[i];
  4048. //
  4049. // put the separator, move over one wchar position
  4050. //
  4051. pszNextToWrite[0] = wchValueSep;
  4052. ++pszNextToWrite;
  4053. ::memcpy(pszNextToWrite, (void*)((LPCWSTR)bstrValue), iValueLen * sizeof(WCHAR));
  4054. //
  4055. // have copied over that many WCHAR, move that many positions.
  4056. //
  4057. pszNextToWrite += iValueLen;
  4058. }
  4059. bstrValue.Empty();
  4060. //
  4061. // enclosing >
  4062. //
  4063. if (i == pVar->parray->rgsabound[0].cElements - 1)
  4064. {
  4065. pszNextToWrite[0] = wchTypeValRight;
  4066. ++pszNextToWrite;
  4067. }
  4068. pszNextToWrite[0] = L'\0';
  4069. lTotalLen += wcslen(pbstrArray[i]);
  4070. }
  4071. //
  4072. // now if everything is fine, pack them into one single output parameter
  4073. //
  4074. if (SUCCEEDED(hr))
  4075. {
  4076. //
  4077. // this is what we will passback
  4078. //
  4079. *pbstrData = ::SysAllocStringLen(NULL, lTotalLen + 1);
  4080. if (*pbstrData == NULL)
  4081. {
  4082. hr = WBEM_E_OUT_OF_MEMORY;
  4083. }
  4084. else
  4085. {
  4086. pszNextToWrite = *pbstrData;
  4087. long lLen = 0;
  4088. for (i = lLowerBound; i <= lUpperBound; i++)
  4089. {
  4090. lLen = wcslen(pbstrArray[i]);
  4091. //
  4092. // have copied over that many WCHAR, move that many positions.
  4093. //
  4094. ::memcpy(pszNextToWrite, (void*)((LPCWSTR)pbstrArray[i]), lLen * sizeof(WCHAR));
  4095. pszNextToWrite += lLen;
  4096. }
  4097. pszNextToWrite[0] = L'\0';
  4098. }
  4099. }
  4100. //
  4101. // release the bstrs
  4102. //
  4103. for (long i = lLowerBound; i <= lUpperBound; i++)
  4104. {
  4105. if (pbstrArray[i] != NULL)
  4106. {
  4107. ::SysFreeString(pbstrArray[i]);
  4108. }
  4109. }
  4110. delete [] pbstrArray;
  4111. return hr;
  4112. }
  4113. /*
  4114. Routine Description:
  4115. Name:
  4116. GetStringPresentation
  4117. Functionality:
  4118. Given a variant, get the formatted (our format) string representation.
  4119. For example, given a variant of type VT_I4 of value 12345, this function
  4120. will give < VT_I4 : 12345 >
  4121. For example, given a variant of type VT_BSTR of value "Microsoft's SCE", this function
  4122. will give < VT_BSTR : "Microsoft's SCE" >
  4123. Virtual:
  4124. N/A.
  4125. Arguments:
  4126. pVar - The varaint to be formatted. Must not be VT_ARRAY's variant. That is done by
  4127. FormatArray function.
  4128. pbstrData - Receive the formatted string.
  4129. Return Value:
  4130. Success: WBEM_NO_ERROR.
  4131. Failure: Various errors may occurs.
  4132. Most obvious is
  4133. WBEM_E_INVALID_SYNTAX,
  4134. WBEM_E_INVALID_PARAMETER
  4135. Notes:
  4136. */
  4137. HRESULT
  4138. GetStringPresentation (
  4139. IN VARIANT * pVar,
  4140. OUT BSTR * pbstrData
  4141. )
  4142. {
  4143. USES_CONVERSION;
  4144. if (pVar == NULL || pbstrData == NULL)
  4145. {
  4146. return WBEM_E_INVALID_PARAMETER;
  4147. }
  4148. int iFormat = 0;
  4149. DWORD dwValue;
  4150. double dblValue = 0.0F;
  4151. *pbstrData = NULL;
  4152. HRESULT hr = WBEM_NO_ERROR;
  4153. switch (pVar->vt)
  4154. {
  4155. case VT_BSTR:
  4156. hr = ::EscapeStringData(pVar->bstrVal, pbstrData, true); // adding quote
  4157. break;
  4158. case VT_BOOL:
  4159. dwValue = (pVar->boolVal == VARIANT_TRUE) ? 1 : 0;
  4160. iFormat = iFormatIntegral;
  4161. break;
  4162. case VT_I2:
  4163. dwValue = pVar->iVal;
  4164. iFormat = iFormatIntegral;
  4165. break;
  4166. case VT_UI1:
  4167. dwValue = pVar->bVal;
  4168. iFormat = iFormatIntegral;
  4169. break;
  4170. case VT_UI2:
  4171. dwValue = pVar->uiVal;
  4172. iFormat = iFormatIntegral;
  4173. break;
  4174. case VT_UI4:
  4175. dwValue = pVar->ulVal;
  4176. iFormat = iFormatIntegral;
  4177. break;
  4178. case VT_I4:
  4179. dwValue = pVar->lVal;
  4180. iFormat = iFormatIntegral;
  4181. break;
  4182. //case VT_I8:
  4183. // dwValue = pVar->hVal;
  4184. // iFormat = iFormatInt8;
  4185. // break;
  4186. //case VT_UI8:
  4187. // dwValue = pVar->uhVal;
  4188. // iFormat = iFormatInt8;
  4189. // break;
  4190. case VT_DATE:
  4191. dblValue = pVar->date;
  4192. iFormat = iFormatFloat;
  4193. break;
  4194. case VT_R4:
  4195. dblValue = pVar->fltVal;
  4196. iFormat = iFormatFloat;
  4197. break;
  4198. case VT_R8:
  4199. dblValue = pVar->dblVal;
  4200. iFormat = iFormatFloat;
  4201. break;
  4202. case VT_CY:
  4203. iFormat = iFormatCurrenty;
  4204. break;
  4205. default:
  4206. hr = WBEM_E_NOT_SUPPORTED;
  4207. break;
  4208. }
  4209. //
  4210. // The the data type is a integral type
  4211. //
  4212. if (iFormat == iFormatIntegral)
  4213. {
  4214. *pbstrData = ::SysAllocStringLen(NULL, MAX_INT_LENGTH);
  4215. if (*pbstrData != NULL)
  4216. {
  4217. wsprintf(*pbstrData, L"%d", dwValue);
  4218. }
  4219. else
  4220. {
  4221. hr = WBEM_E_OUT_OF_MEMORY;
  4222. }
  4223. }
  4224. else if (iFormat == iFormatFloat)
  4225. {
  4226. //
  4227. // there is no wsprintf for float data types!
  4228. //
  4229. char chData[MAX_DOUBLE_LENGTH];
  4230. ::sprintf(chData, "%f", dblValue);
  4231. *pbstrData = ::SysAllocString(A2W(chData));
  4232. if (*pbstrData == NULL)
  4233. {
  4234. hr = WBEM_E_OUT_OF_MEMORY;
  4235. }
  4236. }
  4237. else if (iFormat == iFormatCurrenty)
  4238. {
  4239. //
  4240. // the data type is currency!
  4241. //
  4242. *pbstrData = ::SysAllocStringLen(NULL, MAX_DOUBLE_LENGTH);
  4243. if (*pbstrData != NULL)
  4244. {
  4245. wsprintf(*pbstrData, L"%d%c%d", pVar->cyVal.Hi, wchCySeparator, pVar->cyVal.Lo);
  4246. }
  4247. else
  4248. {
  4249. hr = WBEM_E_OUT_OF_MEMORY;
  4250. }
  4251. }
  4252. return hr;
  4253. }
  4254. /*
  4255. Routine Description:
  4256. Name:
  4257. GetVoidPtrOfVariant
  4258. Functionality:
  4259. Helper. Will return the address of the data member of the variant for non array data type.
  4260. Virtual:
  4261. N/A.
  4262. Arguments:
  4263. vt - The type we want. Can't be VT_ARRAY, which is done separately
  4264. pVar - The variant. This may be empty!
  4265. Return Value:
  4266. Success: Non-NULL void*.
  4267. Failure: NULL. Either this type is not supportd or the variant is NULL.
  4268. Notes:
  4269. */
  4270. void*
  4271. GetVoidPtrOfVariant (
  4272. VARTYPE vt,
  4273. VARIANT* pVar
  4274. )
  4275. {
  4276. if (pVar == NULL)
  4277. {
  4278. return NULL;
  4279. }
  4280. switch (vt)
  4281. {
  4282. case VT_BSTR:
  4283. return &(pVar->bstrVal);
  4284. case VT_BOOL:
  4285. return &(pVar->boolVal);
  4286. case VT_I2:
  4287. return &(pVar->iVal);
  4288. case VT_UI1:
  4289. return &(pVar->bVal);
  4290. case VT_UI2:
  4291. return &(pVar->uiVal);
  4292. case VT_UI4:
  4293. return &(pVar->ulVal);
  4294. case VT_I4:
  4295. return &(pVar->lVal);
  4296. //case VT_I8:
  4297. // return &(pVar->hVal);
  4298. //case VT_UI8:
  4299. // return &(pVar->uhVal);
  4300. case VT_DATE:
  4301. return &(pVar->date);
  4302. case VT_R8:
  4303. return &(pVar->dblVal);
  4304. case VT_R4:
  4305. return &(pVar->fltVal);
  4306. case VT_CY:
  4307. return &(pVar->cyVal);
  4308. default:
  4309. return NULL;
  4310. }
  4311. }
  4312. /*
  4313. Routine Description:
  4314. Name:
  4315. ParseCompoundKeyString
  4316. Functionality:
  4317. Will parse the compound key string to get one (name, value) pair and advance the pointer
  4318. to the next position to continue the same parsing. This is designed to be called repeatedly
  4319. in a loop.
  4320. Virtual:
  4321. N/A.
  4322. Arguments:
  4323. pszCurStart - Current position to start the parsing.
  4324. ppszName - Receives the name. Optional. If caller is not interested in the name,
  4325. it can simply pass in NULL.
  4326. pVar - Receives the variant value. Optional. If caller is not interested in the value,
  4327. it can simply pass in NULL.
  4328. ppNext - Receives the pointer for next parsing step, must not be null.
  4329. Return Value:
  4330. Success: WBEM_S_FALSE if no parsing needs to be done.
  4331. WBEM_NO_ERROR if results are returned.
  4332. Failure: various error code.
  4333. Notes:
  4334. Caller is responsible for releasing the out parameters if function is successful.
  4335. */
  4336. HRESULT
  4337. ParseCompoundKeyString (
  4338. IN LPCWSTR pszCurStart,
  4339. OUT LPWSTR* ppszName OPTIONAL,
  4340. OUT VARIANT* pVar OPTIONAL,
  4341. OUT LPCWSTR* ppNext
  4342. )
  4343. {
  4344. if (ppNext == NULL)
  4345. {
  4346. return WBEM_E_INVALID_PARAMETER;
  4347. }
  4348. if (ppszName != NULL)
  4349. {
  4350. *ppszName = NULL;
  4351. }
  4352. if (pVar != NULL)
  4353. {
  4354. ::VariantInit(pVar);
  4355. }
  4356. *ppNext = NULL;
  4357. if (pszCurStart == NULL || *pszCurStart == L'\0')
  4358. {
  4359. return WBEM_S_FALSE;
  4360. }
  4361. //
  4362. // we don't use this bEsc.
  4363. //
  4364. bool bEsc;
  4365. //
  4366. // this is our current position to start parsing
  4367. //
  4368. LPCWSTR pCur = pszCurStart;
  4369. //
  4370. // get the name, which is delimited by wchTypeValLeft ('<')
  4371. //
  4372. LPCWSTR pNext = ::EscSeekToChar(pCur, wchTypeValLeft, &bEsc, true);
  4373. if (*pNext != wchTypeValLeft)
  4374. {
  4375. return WBEM_S_FALSE;
  4376. }
  4377. HRESULT hr = WBEM_S_FALSE;
  4378. //
  4379. // it wants the name
  4380. //
  4381. if (ppszName != NULL)
  4382. {
  4383. //
  4384. // caller is responsible for releasing it.
  4385. //
  4386. *ppszName = new WCHAR[pNext - pCur + 1];
  4387. if (*ppszName == NULL)
  4388. {
  4389. return WBEM_E_OUT_OF_MEMORY;
  4390. }
  4391. //
  4392. // *pNext == '<', thus from pCur to pNext is the name of the key property
  4393. //
  4394. ::TrimCopy(*ppszName, pCur, pNext - pCur);
  4395. }
  4396. //
  4397. // ready for value
  4398. //
  4399. pCur = pNext; // pCur is pointing at '<'
  4400. //
  4401. // move pNext to '>'
  4402. //
  4403. pNext = ::EscSeekToChar(pCur, wchTypeValRight, &bEsc, true);
  4404. //
  4405. // if not see the wchTypeValRight, it's syntax error
  4406. //
  4407. if (*pNext != wchTypeValRight)
  4408. {
  4409. //
  4410. // caller won't do the releasing in this case
  4411. //
  4412. if (ppszName)
  4413. {
  4414. delete [] *ppszName;
  4415. *ppszName = NULL;
  4416. }
  4417. return WBEM_E_INVALID_SYNTAX;
  4418. }
  4419. ++pNext; // skip the '>'
  4420. if (pVar != NULL)
  4421. {
  4422. //
  4423. // from pCur to pNext is the encoded value <xxx:yyyyyyy>. Copy this to szValue
  4424. //
  4425. LPWSTR pszValue = new WCHAR[pNext - pCur + 1];
  4426. if (pszValue != NULL)
  4427. {
  4428. ::TrimCopy(pszValue, pCur, pNext - pCur);
  4429. hr = ::VariantFromFormattedString(pszValue, pVar);
  4430. delete [] pszValue;
  4431. }
  4432. else
  4433. {
  4434. hr = WBEM_E_OUT_OF_MEMORY;
  4435. }
  4436. }
  4437. if (SUCCEEDED(hr))
  4438. {
  4439. *ppNext = pNext;
  4440. hr = WBEM_NO_ERROR;
  4441. }
  4442. else
  4443. {
  4444. delete [] *ppszName;
  4445. *ppszName = NULL;
  4446. }
  4447. return hr;
  4448. }
  4449. /*
  4450. Routine Description:
  4451. Name:
  4452. PopulateKeyProperties
  4453. Functionality:
  4454. Will parse the compound key string and feed the property values to the property manager,
  4455. which has been attached to the appropriate object.
  4456. Virtual:
  4457. N/A.
  4458. Arguments:
  4459. pszCompoundKey - The compound key string.
  4460. pScePropMgr - The property manager where the parsed (key) properties will be put. It must
  4461. be prepared correctly for the object to receive the properties.
  4462. Return Value:
  4463. Success: WBEM_S_FALSE if no thing was done.
  4464. WBEM_NO_ERROR if results are returned.
  4465. Failure: various error code.
  4466. Notes:
  4467. Partial properties might have been set to the object if the parsing fails at a later stage.
  4468. We don't try to undo those partially filled properties.
  4469. */
  4470. HRESULT
  4471. PopulateKeyProperties (
  4472. IN LPCWSTR pszCompoundKey,
  4473. IN CScePropertyMgr * pScePropMgr
  4474. )
  4475. {
  4476. if (pszCompoundKey == NULL || *pszCompoundKey == L'\0')
  4477. {
  4478. //
  4479. // nothing to populate
  4480. //
  4481. return WBEM_S_FALSE;
  4482. }
  4483. LPWSTR pszName = NULL;
  4484. VARIANT var;
  4485. ::VariantInit(&var);
  4486. LPCWSTR pszCur = pszCompoundKey;
  4487. LPCWSTR pszNext;
  4488. HRESULT hr = ::ParseCompoundKeyString(pszCur, &pszName, &var, &pszNext);
  4489. bool bHasSetProperties = false;
  4490. while (SUCCEEDED(hr) && hr != WBEM_S_FALSE)
  4491. {
  4492. hr = pScePropMgr->PutProperty(pszName, &var);
  4493. if (SUCCEEDED(hr))
  4494. {
  4495. bHasSetProperties = true;
  4496. }
  4497. delete [] pszName;
  4498. ::VariantClear(&var);
  4499. //
  4500. // start our next round
  4501. //
  4502. pszCur = pszNext;
  4503. hr = ::ParseCompoundKeyString(pszCur, &pszName, &var, &pszNext);
  4504. }
  4505. if (SUCCEEDED(hr) && bHasSetProperties)
  4506. {
  4507. hr = WBEM_NO_ERROR;
  4508. }
  4509. return hr;
  4510. }