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.

1082 lines
21 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 2000
  6. //
  7. // File: wbemmisc.cpp
  8. //
  9. // Abstract: Misc routines useful for interfacing with WBEM
  10. //
  11. //--------------------------------------------------------------------------
  12. #include <objbase.h>
  13. #include <windows.h>
  14. #include <wbemidl.h>
  15. #include <wbemtime.h>
  16. #include <stdio.h>
  17. #include <string.h>
  18. #include <wchar.h>
  19. #include "debug.h"
  20. #include "wbemmisc.h"
  21. HRESULT GetMethodInParamInstance(
  22. IN IWbemServices *pServices,
  23. IN PWCHAR ClassName,
  24. IN BSTR MethodName,
  25. OUT IWbemClassObject **ppInParamInstance
  26. )
  27. /*+++
  28. Routine Description:
  29. This routine will return an instance object for a methods in
  30. parameter. WBEM requires that we go through this dance to get an
  31. instance object.
  32. Arguments:
  33. pServices
  34. ClassName is the class containing the method
  35. MethodName is the name of the method
  36. *ppInParamInstance returns the instance object to fill with in
  37. parameters
  38. Return Value:
  39. HRESULT
  40. ---*/
  41. {
  42. HRESULT hr;
  43. IWbemClassObject *pClass;
  44. IWbemClassObject *pInParamClass;
  45. WmipAssert(pServices != NULL);
  46. WmipAssert(ClassName != NULL);
  47. WmipAssert(MethodName != NULL);
  48. WmipAssert(ppInParamInstance != NULL);
  49. hr = pServices->GetObject(ClassName,
  50. 0,
  51. NULL,
  52. &pClass,
  53. NULL);
  54. if (hr == WBEM_S_NO_ERROR)
  55. {
  56. hr = pClass->GetMethod(MethodName,
  57. 0,
  58. &pInParamClass,
  59. NULL);
  60. if (hr == WBEM_S_NO_ERROR)
  61. {
  62. hr = pInParamClass->SpawnInstance(0,
  63. ppInParamInstance);
  64. pInParamClass->Release();
  65. }
  66. pClass->Release();
  67. }
  68. return(hr);
  69. }
  70. HRESULT WmiGetQualifier(
  71. IN IWbemQualifierSet *pIWbemQualifierSet,
  72. IN PWCHAR QualifierName,
  73. IN VARTYPE Type,
  74. OUT /* FREE */ VARIANT *Value
  75. )
  76. /*+++
  77. Routine Description:
  78. This routine will return the value for a specific qualifier
  79. Arguments:
  80. pIWbemQualifierSet is the qualifier set object
  81. QualifierName is the name of the qualifier
  82. Type is the type of qualifier expected
  83. *Value returns with the value of the qualifier. Caller must call
  84. VariantClear
  85. Return Value:
  86. HRESULT
  87. ---*/
  88. {
  89. BSTR s;
  90. HRESULT hr;
  91. WmipAssert(pIWbemQualifierSet != NULL);
  92. WmipAssert(QualifierName != NULL);
  93. WmipAssert(Value != NULL);
  94. s = SysAllocString(QualifierName);
  95. if (s != NULL)
  96. {
  97. hr = pIWbemQualifierSet->Get(s,
  98. 0,
  99. Value,
  100. NULL);
  101. if ((Value->vt & ~CIM_FLAG_ARRAY) != Type)
  102. {
  103. hr = WBEM_E_FAILED;
  104. VariantClear(Value);
  105. }
  106. SysFreeString(s);
  107. } else {
  108. hr = WBEM_E_OUT_OF_MEMORY;
  109. }
  110. return(hr);
  111. }
  112. HRESULT WmiGetQualifierListByName(
  113. IN IWbemServices *pServices,
  114. IN PWCHAR ClassName,
  115. IN PWCHAR PropertyName,
  116. IN ULONG QualifierCount,
  117. IN PWCHAR *QualifierNames,
  118. IN VARTYPE *Types,
  119. OUT VARIANT /* FREE */ *Values
  120. )
  121. /*+++
  122. Routine Description:
  123. This routine will return the values for a list of qualifiers. If
  124. all qualifiers cannot be returned then none are.
  125. Arguments:
  126. pServices is the IWbemServices pointer
  127. ClassName is the name of the class with qualifiers
  128. PropertyName is the name of the property with qualfiers. If NULL
  129. then class qualifiers are returned
  130. QualifierCount is the count of qualifers to get
  131. QualifierNames is an array contaiing names of qualifiers to get
  132. Types is an array of expected value types for the qualifiers
  133. Values is an array of variants that return with the qualifer values
  134. Return Value:
  135. HRESULT
  136. ---*/
  137. {
  138. HRESULT hr;
  139. IWbemClassObject *pClass;
  140. IWbemQualifierSet *pQualifiers;
  141. ULONG i, j;
  142. WmipAssert(pServices != NULL);
  143. WmipAssert(ClassName != NULL);
  144. WmipAssert(QualifierNames != NULL);
  145. WmipAssert(Types != NULL);
  146. WmipAssert(Values != NULL);
  147. //
  148. // Create the class so we can look at the properties
  149. //
  150. hr = pServices->GetObject(ClassName,
  151. WBEM_FLAG_USE_AMENDED_QUALIFIERS,
  152. NULL,
  153. &pClass,
  154. NULL);
  155. if (hr == WBEM_S_NO_ERROR)
  156. {
  157. if (PropertyName == NULL)
  158. {
  159. hr = pClass->GetQualifierSet(&pQualifiers);
  160. } else {
  161. hr = pClass->GetPropertyQualifierSet(PropertyName,
  162. &pQualifiers);
  163. }
  164. if (hr == WBEM_S_NO_ERROR)
  165. {
  166. for (i = 0; (i < QualifierCount) && (hr == WBEM_S_NO_ERROR); i++)
  167. {
  168. hr = WmiGetQualifier(pQualifiers,
  169. QualifierNames[i],
  170. Types[i],
  171. &Values[i]);
  172. }
  173. if (hr != WBEM_S_NO_ERROR)
  174. {
  175. for (j = 0; j < i; j++)
  176. {
  177. VariantClear(&Values[j]);
  178. }
  179. }
  180. pQualifiers->Release();
  181. }
  182. pClass->Release();
  183. }
  184. return(hr);
  185. }
  186. HRESULT WmiGetProperty(
  187. IN IWbemClassObject *pIWbemClassObject,
  188. IN PWCHAR PropertyName,
  189. IN CIMTYPE ExpectedCimType,
  190. OUT VARIANT /* FREE */ *Value
  191. )
  192. /*+++
  193. Routine Description:
  194. This routine will return the value for a specific property
  195. Arguments:
  196. pIWbemQualifierSet is the qualifier set object
  197. PropertyName is the name of the property
  198. Type is the type of property expected
  199. *Value returns with the value of the property
  200. Return Value:
  201. HRESULT
  202. ---*/
  203. {
  204. HRESULT hr;
  205. CIMTYPE CimType;
  206. WmipAssert(pIWbemClassObject != NULL);
  207. WmipAssert(PropertyName != NULL);
  208. WmipAssert(Value != NULL);
  209. hr = pIWbemClassObject->Get(PropertyName,
  210. 0,
  211. Value,
  212. &CimType,
  213. NULL);
  214. //
  215. // Treat a NULL value for a property as an error
  216. //
  217. if (Value->vt == VT_NULL)
  218. {
  219. hr = WBEM_E_ILLEGAL_NULL;
  220. WmipDebugPrint(("CDMPROV: Property %ws is NULL\n",
  221. PropertyName));
  222. }
  223. //
  224. // Treat CIM_REFERENCE and CIM_STRING as interchangable
  225. //
  226. if ((ExpectedCimType == CIM_REFERENCE) &&
  227. (CimType == CIM_STRING))
  228. {
  229. ExpectedCimType = CIM_STRING;
  230. }
  231. if ((ExpectedCimType == CIM_STRING) &&
  232. (CimType == CIM_REFERENCE))
  233. {
  234. ExpectedCimType = CIM_REFERENCE;
  235. }
  236. if ((hr == WBEM_S_NO_ERROR) && (ExpectedCimType != CimType))
  237. {
  238. WmipDebugPrint(("CDMPROV: Property %ws was expected as %d but was got as %d\n",
  239. PropertyName,
  240. ExpectedCimType,
  241. CimType));
  242. WmipAssert(FALSE);
  243. hr = WBEM_E_FAILED;
  244. VariantClear(Value);
  245. }
  246. return(hr);
  247. }
  248. HRESULT WmiGetPropertyList(
  249. IN IWbemClassObject *pIWbemClassObject,
  250. IN ULONG PropertyCount,
  251. IN PWCHAR *PropertyNames,
  252. IN CIMTYPE *ExpectedCimType,
  253. OUT VARIANT /* FREE */ *Value
  254. )
  255. /*+++
  256. Routine Description:
  257. This routine will return the value for a specific property
  258. Arguments:
  259. pIWbemQualifierSet is the qualifier set object
  260. PropertyNames is the name of the property
  261. Type is the type of property expected
  262. *Value returns with the value of the property
  263. Return Value:
  264. HRESULT
  265. ---*/
  266. {
  267. ULONG i,j;
  268. HRESULT hr;
  269. WmipAssert(pIWbemClassObject != NULL);
  270. WmipAssert(PropertyNames != NULL);
  271. WmipAssert(ExpectedCimType != NULL);
  272. WmipAssert(Value != NULL);
  273. for (i = 0, hr = WBEM_S_NO_ERROR;
  274. (i < PropertyCount) && (hr == WBEM_S_NO_ERROR);
  275. i++)
  276. {
  277. hr = WmiGetProperty(pIWbemClassObject,
  278. PropertyNames[i],
  279. ExpectedCimType[i],
  280. &Value[i]);
  281. }
  282. if (hr != WBEM_S_NO_ERROR)
  283. {
  284. for (j = 0; j < i; j++)
  285. {
  286. VariantClear(&Value[i]);
  287. }
  288. }
  289. return(hr);
  290. }
  291. HRESULT WmiGetPropertyByName(
  292. IN IWbemServices *pServices,
  293. IN PWCHAR ClassName,
  294. IN PWCHAR PropertyName,
  295. IN CIMTYPE ExpectedCimType,
  296. OUT VARIANT /* FREE */ *Value
  297. )
  298. /*+++
  299. Routine Description:
  300. This routine will return the value for a specific property within a
  301. class
  302. Arguments:
  303. pServices is the IWbemServices for the namespace containing your
  304. class
  305. ClassName is the name of the class whose property you are
  306. interested in
  307. PropertyName is the name of the property
  308. Type is the type of property expected
  309. *Value returns with the value of the property
  310. Return Value:
  311. HRESULT
  312. ---*/
  313. {
  314. HRESULT hr;
  315. IWbemClassObject *pClass;
  316. WmipAssert(pServices != NULL);
  317. WmipAssert(ClassName != NULL);
  318. WmipAssert(PropertyName != NULL);
  319. WmipAssert(Value != NULL);
  320. //
  321. // Create the class so we can look at the properties
  322. //
  323. hr = pServices->GetObject(ClassName, 0, NULL, &pClass, NULL);
  324. if (hr == WBEM_S_NO_ERROR)
  325. {
  326. hr = WmiGetProperty(pClass,
  327. PropertyName,
  328. ExpectedCimType,
  329. Value);
  330. pClass->Release();
  331. }
  332. return(hr);
  333. }
  334. HRESULT WmiSetProperty(
  335. IN IWbemClassObject *pIWbemClassObject,
  336. IN PWCHAR PropertyName,
  337. IN VARIANT *Value
  338. )
  339. /*+++
  340. Routine Description:
  341. This routine will set the value of a property to something
  342. Arguments:
  343. pIWbemClassObject is the object whose property is being set
  344. PropertyName is the name of the property being set
  345. Value is the value that the property is being set to
  346. Return Value:
  347. HRESULT
  348. ---*/
  349. {
  350. HRESULT hr;
  351. WmipAssert(pIWbemClassObject != NULL);
  352. WmipAssert(PropertyName != NULL);
  353. WmipAssert(Value != NULL);
  354. hr = pIWbemClassObject->Put(PropertyName,
  355. 0,
  356. Value,
  357. 0);
  358. if (hr == WBEM_E_TYPE_MISMATCH)
  359. {
  360. WmipDebugPrint(("CDMPROV: Put %ws has wrong type %d\n",
  361. PropertyName, Value->vt));
  362. WmipAssert(FALSE);
  363. }
  364. return(hr);
  365. }
  366. HRESULT WmiSetPropertyList(
  367. IN IWbemClassObject *pIWbemClassObject,
  368. IN ULONG PropertyCount,
  369. IN PWCHAR *PropertyNames,
  370. IN VARIANT *Values
  371. )
  372. /*+++
  373. Routine Description:
  374. This routine will set the values of multiple properties to something
  375. Arguments:
  376. pIWbemClassObject is the object whose property is being set
  377. PropertyCount is the number of properties to set
  378. PropertyNames is the names of the property being set
  379. Values is the value that the property is being set to
  380. Return Value:
  381. HRESULT
  382. ---*/
  383. {
  384. ULONG i;
  385. HRESULT hr = WBEM_S_NO_ERROR;
  386. WmipAssert(pIWbemClassObject != NULL);
  387. WmipAssert(PropertyNames != NULL);
  388. WmipAssert(Values != NULL);
  389. for (i = 0; (i < PropertyCount) && (hr == WBEM_S_NO_ERROR); i++)
  390. {
  391. hr = WmiSetProperty(pIWbemClassObject,
  392. PropertyNames[i],
  393. &Values[i]);
  394. }
  395. return(hr);
  396. }
  397. // @@BEGIN_DDKSPLIT
  398. #ifndef HEAP_DEBUG
  399. // @@END_DDKSPLIT
  400. PVOID WmipAlloc(
  401. IN ULONG Size
  402. )
  403. /*+++
  404. Routine Description:
  405. Internal memory allocator
  406. Arguments:
  407. Size is the number of bytes to allocate
  408. Return Value:
  409. pointer to alloced memory or NULL
  410. ---*/
  411. {
  412. return(LocalAlloc(LPTR, Size));
  413. }
  414. void WmipFree(
  415. IN PVOID Ptr
  416. )
  417. /*+++
  418. Routine Description:
  419. Internal memory deallocator
  420. Arguments:
  421. Pointer to freed memory
  422. Return Value:
  423. void
  424. ---*/
  425. {
  426. WmipAssert(Ptr != NULL);
  427. LocalFree(Ptr);
  428. }
  429. // @@BEGIN_DDKSPLIT
  430. #endif
  431. // @@END_DDKSPLIT
  432. PWCHAR AddSlashesToStringW(
  433. OUT PWCHAR SlashedNamespace,
  434. IN PWCHAR Namespace
  435. )
  436. /*+++
  437. Routine Description:
  438. This routine will convert ever \ in the string into \\. It needs to
  439. do this since WBEM will collapse \\ into \ sometimes.
  440. Arguments:
  441. SlashedNamespace returns with string double slashed
  442. Namespace is the input string
  443. Return Value:
  444. pointer to SlashedNamespace
  445. ---*/
  446. {
  447. PWCHAR Return = SlashedNamespace;
  448. WmipAssert(SlashedNamespace != NULL);
  449. WmipAssert(Namespace != NULL);
  450. //
  451. // MOF likes the namespace paths to be C-style, that is to have a
  452. // '\\' instad of a '\'. So whereever we see a '\', we insert a
  453. // second one
  454. //
  455. while (*Namespace != 0)
  456. {
  457. if (*Namespace == L'\\')
  458. {
  459. *SlashedNamespace++ = L'\\';
  460. }
  461. *SlashedNamespace++ = *Namespace++;
  462. }
  463. *SlashedNamespace = 0;
  464. return(Return);
  465. }
  466. PWCHAR AddSlashesToStringExW(
  467. OUT PWCHAR SlashedNamespace,
  468. IN PWCHAR Namespace
  469. )
  470. /*+++
  471. Routine Description:
  472. This routine will convert ever \ in the string into \\ and " into
  473. \". It needs to do this since WBEM will collapse \\ into \ sometimes.
  474. Arguments:
  475. SlashedNamespace returns with string double slashed
  476. Namespace is the input string
  477. Return Value:
  478. pointer to SlashedNamespace
  479. ---*/
  480. {
  481. PWCHAR Return = SlashedNamespace;
  482. WmipAssert(SlashedNamespace != NULL);
  483. WmipAssert(Namespace != NULL);
  484. //
  485. // MOF likes the namespace paths to be C-style, that is to have a
  486. // '\\' instad of a '\'. So whereever we see a '\', we insert a
  487. // second one. We also need to add a \ before any ".
  488. //
  489. while (*Namespace != 0)
  490. {
  491. if ((*Namespace == L'\\') || (*Namespace == L'"'))
  492. {
  493. *SlashedNamespace++ = L'\\';
  494. }
  495. *SlashedNamespace++ = *Namespace++;
  496. }
  497. *SlashedNamespace = 0;
  498. return(Return);
  499. }
  500. HRESULT WmiConnectToWbem(
  501. IN PWCHAR Namespace,
  502. OUT IWbemServices **ppIWbemServices
  503. )
  504. /*+++
  505. Routine Description:
  506. This routine will establishes a connection to a WBEM namespace on
  507. the local machine.
  508. Arguments:
  509. Namespace is the namespace to which to connect
  510. *ppIWbemServices returns with a IWbemServices * for the namespace
  511. Return Value:
  512. HRESULT
  513. ---*/
  514. {
  515. IWbemLocator *pIWbemLocator;
  516. DWORD hr;
  517. BSTR s;
  518. WmipAssert(Namespace != NULL);
  519. WmipAssert(ppIWbemServices != NULL);
  520. hr = CoCreateInstance(CLSID_WbemLocator,
  521. NULL,
  522. CLSCTX_INPROC_SERVER,
  523. IID_IWbemLocator,
  524. (LPVOID *) &pIWbemLocator);
  525. if (hr == S_OK)
  526. {
  527. s = SysAllocString(Namespace);
  528. if (s != NULL)
  529. {
  530. *ppIWbemServices = NULL;
  531. hr = pIWbemLocator->ConnectServer(s,
  532. NULL, // Userid
  533. NULL, // PW
  534. NULL, // Locale
  535. 0, // flags
  536. NULL, // Authority
  537. NULL, // Context
  538. ppIWbemServices
  539. );
  540. SysFreeString(s);
  541. } else {
  542. *ppIWbemServices = NULL;
  543. hr = WBEM_E_OUT_OF_MEMORY;
  544. }
  545. pIWbemLocator->Release();
  546. }
  547. return(hr);
  548. }
  549. HRESULT CreateInst(
  550. IN IWbemServices * pNamespace,
  551. OUT /* FREE */ IWbemClassObject ** pNewInst,
  552. IN WCHAR * pwcClassName,
  553. IN IWbemContext *pCtx
  554. )
  555. /*+++
  556. Routine Description:
  557. This routine will create a new instance for the specified class
  558. Arguments:
  559. pNamespace is the IWbemServices * to the namespace in which the
  560. class lives
  561. *pNewinst returns with the new instance of the class
  562. pwcClassName has the name of the class whose instance is created
  563. pCtx is the context to use in creating the instance
  564. Return Value:
  565. HRESULT
  566. ---*/
  567. {
  568. HRESULT hr;
  569. IWbemClassObject * pClass;
  570. hr = pNamespace->GetObject(pwcClassName, 0, pCtx, &pClass, NULL);
  571. if (hr != S_OK)
  572. {
  573. return WBEM_E_FAILED;
  574. }
  575. hr = pClass->SpawnInstance(0, pNewInst);
  576. pClass->Release();
  577. WmipDebugPrint(("CDMProv:: Created %ws as %p\n",
  578. pwcClassName, *pNewInst));
  579. return(hr);
  580. }
  581. /* FREE */ BSTR GetCurrentDateTime(
  582. void
  583. )
  584. {
  585. SYSTEMTIME SystemTime;
  586. WBEMTime WbemTime;
  587. GetSystemTime(&SystemTime);
  588. WbemTime = SystemTime;
  589. return(WbemTime.GetBSTR());
  590. }
  591. HRESULT WmiGetArraySize(
  592. IN SAFEARRAY *Array,
  593. OUT LONG *LBound,
  594. OUT LONG *UBound,
  595. OUT LONG *NumberElements
  596. )
  597. /*+++
  598. Routine Description:
  599. This routine will information about the size and bounds of a single
  600. dimensional safe array.
  601. Arguments:
  602. Array is the safe array
  603. *LBound returns with the lower bound of the array
  604. *UBound returns with the upper bound of the array
  605. *NumberElements returns with the number of elements in the array
  606. Return Value:
  607. TRUE if successful else FALSE
  608. ---*/
  609. {
  610. HRESULT hr;
  611. WmipAssert(Array != NULL);
  612. WmipAssert(LBound != NULL);
  613. WmipAssert(UBound != NULL);
  614. WmipAssert(NumberElements != NULL);
  615. //
  616. // Only single dim arrays are supported
  617. //
  618. WmipAssert(SafeArrayGetDim(Array) == 1);
  619. hr = SafeArrayGetLBound(Array, 1, LBound);
  620. if (hr == WBEM_S_NO_ERROR)
  621. {
  622. hr = SafeArrayGetUBound(Array, 1, UBound);
  623. *NumberElements = (*UBound - *LBound) + 1;
  624. }
  625. return(hr);
  626. }
  627. BOOLEAN IsUlongAndStringEqual(
  628. IN ULONG Number,
  629. IN PWCHAR String
  630. )
  631. /*+++
  632. Routine Description:
  633. This routine will convert the passed string to an integer and
  634. compare it to the passed integer value
  635. Arguments:
  636. Number
  637. String
  638. Return Value:
  639. TRUE if equal else FALSE
  640. ---*/
  641. {
  642. ULONG SNumber;
  643. SNumber = _wtoi(String);
  644. return ( (Number == SNumber) ? TRUE : FALSE );
  645. }
  646. HRESULT LookupValueMap(
  647. IN IWbemServices *pServices,
  648. IN PWCHAR ClassName,
  649. IN PWCHAR PropertyName,
  650. IN ULONG Value,
  651. OUT /* FREE */ BSTR *MappedValue
  652. )
  653. /*+++
  654. Routine Description:
  655. This routine will lookup the string value corresponding to an
  656. integer valuemap
  657. Arguments:
  658. pServices is the pointer to the namespace in which the class is
  659. locaed
  660. ClassName is the name of the class
  661. PropertyName is the name of the property
  662. Value is the value of the property and is used to look up the
  663. string that corresponsds to it
  664. *MappedValue returns a string that contains the string which the
  665. value maps to
  666. Return Value:
  667. HRESULT
  668. ---*/
  669. {
  670. PWCHAR Names[2];
  671. VARIANT QualifierValues[2];
  672. VARTYPE Types[2];
  673. HRESULT hr;
  674. BSTR s;
  675. LONG ValuesLBound, ValuesUBound, ValuesElements;
  676. LONG ValueMapLBound, ValueMapUBound, ValueMapElements;
  677. LONG i, Index;
  678. WmipAssert(pServices != NULL);
  679. WmipAssert(ClassName != NULL);
  680. WmipAssert(PropertyName != NULL);
  681. WmipAssert(MappedValue != NULL);
  682. //
  683. // Get the Values and ValueMap qualifiers so we can do the mapping
  684. //
  685. Names[0] = L"Values";
  686. Types[0] = VT_BSTR;
  687. Names[1] = L"ValueMap";
  688. Types[1] = VT_BSTR;
  689. hr = WmiGetQualifierListByName(pServices,
  690. ClassName,
  691. PropertyName,
  692. 2,
  693. Names,
  694. Types,
  695. QualifierValues);
  696. if (hr == WBEM_S_NO_ERROR)
  697. {
  698. //
  699. // Now do a sanity check to make sure the values and valuemaps
  700. // have the same number of elements
  701. //
  702. if (QualifierValues[0].vt == QualifierValues[1].vt)
  703. {
  704. //
  705. // Values and ValueMap both agree that they are both
  706. // scalars or both arrays and are both strings
  707. //
  708. if (QualifierValues[0].vt & VT_ARRAY)
  709. {
  710. //
  711. // We have an array of thing to check for mapping.
  712. // First lets make sure that the arrays have identical
  713. // dimensions
  714. //
  715. hr = WmiGetArraySize(QualifierValues[0].parray,
  716. &ValuesLBound,
  717. &ValuesUBound,
  718. &ValuesElements);
  719. if (hr == WBEM_S_NO_ERROR)
  720. {
  721. hr = WmiGetArraySize(QualifierValues[1].parray,
  722. &ValueMapLBound,
  723. &ValueMapUBound,
  724. &ValueMapElements);
  725. if (hr == WBEM_S_NO_ERROR)
  726. {
  727. if ((ValuesLBound == ValueMapLBound) &&
  728. (ValuesUBound == ValueMapUBound) &&
  729. (ValuesElements == ValueMapElements))
  730. {
  731. for (i = 0; i < ValueMapElements; i++)
  732. {
  733. Index = i + ValueMapLBound;
  734. hr = SafeArrayGetElement(QualifierValues[1].parray,
  735. &Index,
  736. &s);
  737. if (hr == WBEM_S_NO_ERROR)
  738. {
  739. if (IsUlongAndStringEqual(Value,
  740. s))
  741. {
  742. hr = SafeArrayGetElement(QualifierValues[0].parray,
  743. &Index,
  744. MappedValue);
  745. //
  746. // Make sure loop will
  747. // terminate
  748. i = ValueMapElements;
  749. }
  750. SysFreeString(s);
  751. }
  752. }
  753. } else {
  754. hr = WBEM_E_NOT_FOUND;
  755. }
  756. }
  757. }
  758. } else {
  759. //
  760. // We have scalars so this should make a fairly simple
  761. // mapping
  762. //
  763. if (IsUlongAndStringEqual(Value,
  764. QualifierValues[1].bstrVal))
  765. {
  766. *MappedValue = SysAllocString(QualifierValues[0].bstrVal);
  767. if (*MappedValue == NULL)
  768. {
  769. hr = WBEM_E_OUT_OF_MEMORY;
  770. }
  771. } else {
  772. hr = WBEM_E_NOT_FOUND;
  773. }
  774. }
  775. } else {
  776. hr = WBEM_E_NOT_FOUND;
  777. }
  778. VariantClear(&QualifierValues[0]);
  779. VariantClear(&QualifierValues[1]);
  780. }
  781. return(hr);
  782. }
  783. void FreeTheBSTRArray(
  784. BSTR *Array,
  785. ULONG Size
  786. )
  787. /*+++
  788. Routine Description:
  789. This routine will free the contents of an array of BSTR and then
  790. the array itself
  791. Arguments:
  792. Array is the array to be freed
  793. Size is the number of elements in the array
  794. Return Value:
  795. HRESULT
  796. ---*/
  797. {
  798. ULONG i;
  799. if (Array != NULL)
  800. {
  801. for (i = 0; i < Size; i++)
  802. {
  803. if (Array[i] != NULL)
  804. {
  805. SysFreeString(Array[i]);
  806. }
  807. }
  808. WmipFree(Array);
  809. }
  810. }