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.

3773 lines
90 KiB

  1. //***************************************************************************
  2. //
  3. // Copyright (c) 1998-1999 Microsoft Corporation
  4. //
  5. // UTIL.CPP
  6. //
  7. // alanbos 13-Feb-98 Created.
  8. //
  9. // Some useful functions
  10. //
  11. //***************************************************************************
  12. #include "precomp.h"
  13. #include "assert.h"
  14. #include "initguid.h"
  15. #include "dispex.h"
  16. #include <math.h>
  17. extern CWbemErrorCache *g_pErrorCache;
  18. extern CRITICAL_SECTION g_csErrorCache;
  19. typedef struct {
  20. VARTYPE vtOkForQual;
  21. VARTYPE vtTest;
  22. } Conversion;
  23. Conversion QualConvertList[] = {
  24. {VT_I4, VT_I4},
  25. {VT_I4, VT_UI1},
  26. {VT_I4, VT_I2},
  27. {VT_R8, VT_R4},
  28. {VT_R8, VT_R8},
  29. {VT_BOOL, VT_BOOL},
  30. {VT_I4, VT_ERROR},
  31. {VT_BSTR, VT_CY},
  32. {VT_BSTR, VT_DATE},
  33. {VT_BSTR, VT_BSTR}};
  34. //***************************************************************************
  35. //
  36. // GetAcceptableQualType(VARTYPE vt)
  37. //
  38. // DESCRIPTION:
  39. //
  40. // Only certain types are acceptable for qualifiers. This routine takes a
  41. // vartype and returns an acceptable conversion type. Note that if the type is
  42. // already acceptable, then it is returned.
  43. //
  44. //***************************************************************************
  45. VARTYPE GetAcceptableQualType(VARTYPE vt)
  46. {
  47. int iCnt;
  48. VARTYPE vtArrayBit = vt & VT_ARRAY;
  49. VARTYPE vtSimple = vt & ~(VT_ARRAY | VT_BYREF);
  50. int iSize = sizeof(QualConvertList) / sizeof(Conversion);
  51. for(iCnt = 0; iCnt < iSize; iCnt++)
  52. if(vtSimple == QualConvertList[iCnt].vtTest)
  53. return QualConvertList[iCnt].vtOkForQual | vtArrayBit;
  54. return VT_ILLEGAL;
  55. }
  56. //***************************************************************************
  57. //
  58. // SCODE MapFromCIMOMObject
  59. //
  60. // Description:
  61. //
  62. // This function filters out embedded objects that have been passed in
  63. // from CIMOM, ensuring they are returned to the automation environment
  64. // as VT_DISPATCH types.
  65. //
  66. // Return Value:
  67. // HRESULT NOERROR if successful, otherwise E_NOINTERFACE
  68. // if we cannot support the requested interface.
  69. //***************************************************************************
  70. HRESULT MapFromCIMOMObject(CSWbemServices *pService,
  71. VARIANT *pVal,
  72. ISWbemInternalObject *pSWbemObject,
  73. BSTR propertyName,
  74. long index)
  75. {
  76. HRESULT hr = S_OK;
  77. if(pVal->vt == VT_UNKNOWN)
  78. {
  79. /*
  80. * This may be an embedded object. If it is replace by it's
  81. * scriptable equivalent. If not leave it be.
  82. */
  83. if (pVal->punkVal)
  84. {
  85. CComQIPtr<IWbemClassObject> pIWbemClassObject (pVal->punkVal);
  86. if (pIWbemClassObject)
  87. {
  88. // Yowzer - it's one of ours
  89. CSWbemObject *pNew = new CSWbemObject (pService, pIWbemClassObject);
  90. if (pNew)
  91. {
  92. CComQIPtr<IDispatch> pIDispatch (reinterpret_cast<IUnknown*>(pNew));
  93. if (pIDispatch)
  94. {
  95. // Conversion succeeded - replace the punkVal by a pdispVal
  96. pVal->punkVal->Release ();
  97. pVal->punkVal = NULL;
  98. // Transfer the AddRef'd pointer from the QI call above to the Variant
  99. pVal->pdispVal = pIDispatch.Detach ();
  100. pVal->vt = VT_DISPATCH;
  101. if (pSWbemObject)
  102. {
  103. // Our newly create CSWbemObject is an embedded object
  104. // we need to set its site
  105. pNew->SetSite (pSWbemObject, propertyName, index);
  106. }
  107. }
  108. else
  109. {
  110. // This should NEVER happen, but just in case
  111. delete pNew;
  112. hr = WBEM_E_FAILED;
  113. }
  114. }
  115. else
  116. hr = WBEM_E_OUT_OF_MEMORY;
  117. }
  118. }
  119. }
  120. else if(pVal->vt == (VT_UNKNOWN | VT_ARRAY))
  121. {
  122. // got an array of objects. Replace the object pointers with a wrapper
  123. // pointer
  124. SAFEARRAYBOUND aBounds[1];
  125. long lLBound, lUBound;
  126. SafeArrayGetLBound(pVal->parray, 1, &lLBound);
  127. SafeArrayGetUBound(pVal->parray, 1, &lUBound);
  128. aBounds[0].cElements = lUBound - lLBound + 1;
  129. aBounds[0].lLbound = lLBound;
  130. // Update the individual data pieces
  131. // ================================
  132. bool ok = true;
  133. for(long lIndex = lLBound; ok && (lIndex <= lUBound); lIndex++)
  134. {
  135. // Load the initial data element into a VARIANT
  136. // ============================================
  137. CComPtr<IUnknown> pUnk;
  138. if (FAILED(SafeArrayGetElement(pVal->parray, &lIndex, &pUnk)) || !pUnk)
  139. {
  140. ok = false;
  141. hr = WBEM_E_FAILED;
  142. }
  143. else
  144. {
  145. CComQIPtr<IWbemClassObject> pIWbemClassObject (pUnk);
  146. if (pIWbemClassObject)
  147. {
  148. CSWbemObject *pNew = new CSWbemObject (pService, pIWbemClassObject);
  149. if (pNew)
  150. {
  151. CComQIPtr<IDispatch> pIDispatch (reinterpret_cast<IUnknown*>(pNew));
  152. if (pIDispatch)
  153. {
  154. if (FAILED(SafeArrayPutElement(pVal->parray, &lIndex, pIDispatch)))
  155. {
  156. hr = WBEM_E_FAILED;
  157. ok = false;
  158. }
  159. else
  160. {
  161. pVal->vt = VT_ARRAY | VT_DISPATCH;
  162. if (pSWbemObject)
  163. {
  164. // This element is an embedded object. We must set it's site.
  165. pNew->SetSite (pSWbemObject, propertyName, lIndex);
  166. }
  167. }
  168. }
  169. else
  170. {
  171. // This should NEVER happen, but just in case
  172. delete pNew;
  173. hr = WBEM_E_FAILED;
  174. }
  175. }
  176. else
  177. {
  178. hr = WBEM_E_OUT_OF_MEMORY;
  179. ok = false;
  180. }
  181. }
  182. }
  183. }
  184. }
  185. return hr;
  186. }
  187. //***************************************************************************
  188. //
  189. // HRESULT MapToCIMOMObject
  190. //
  191. // Description:
  192. //
  193. // This function filters out embedded objects that have been passed in
  194. // as VT_DISPATCH (possibly combined with VT_BYREF or VT_ARRAY). The
  195. // object is recast inside a VT_UNKNOWN so it can be accepted by CIMOM.
  196. //
  197. // Parameters:
  198. //
  199. // pVal The input variant to check
  200. //
  201. // Return Value:
  202. // HRESULT S_OK if successful
  203. //***************************************************************************
  204. HRESULT MapToCIMOMObject(
  205. VARIANT *pVal
  206. )
  207. {
  208. HRESULT hRes = S_OK;
  209. if(pVal->vt == VT_DISPATCH || (pVal->vt == (VT_DISPATCH | VT_BYREF)))
  210. {
  211. /*
  212. * We may have an embedded object. Replace the object pointer with
  213. * a wrapper pointer.
  214. */
  215. IDispatch *pDisp = NULL;
  216. if (V_ISBYREF(pVal) && (pVal->ppdispVal))
  217. pDisp = *(pVal->ppdispVal);
  218. else if (VT_DISPATCH == V_VT(pVal))
  219. pDisp = pVal->pdispVal;
  220. if (pDisp)
  221. {
  222. // If successful this will AddRef the returned interface
  223. IWbemClassObject *pObj = CSWbemObject::GetIWbemClassObject (pDisp);
  224. if (pObj)
  225. {
  226. // Release the dispatch pointer as we are about to remove it from the
  227. // VARIANT, but only if it wasn't a VT_BYREF (because byrefs don't
  228. // get AddRef'd by VariantCopy or Released by VariantClear).
  229. if (!V_ISBYREF(pVal))
  230. pDisp->Release ();
  231. pVal->punkVal = pObj;
  232. pVal->vt = VT_UNKNOWN;
  233. }
  234. else
  235. {
  236. /*
  237. * Rather than just cast IDispatch* to IUnknown*, we do a QI
  238. * with a release just in case the object has per-interface
  239. * ref counting.
  240. */
  241. if (SUCCEEDED (hRes = pDisp->QueryInterface (IID_IUnknown, (PPVOID) &(pVal->punkVal))))
  242. {
  243. pDisp->Release ();
  244. pVal->vt = VT_UNKNOWN;
  245. }
  246. }
  247. }
  248. }
  249. else if(pVal->vt == (VT_DISPATCH | VT_ARRAY))
  250. {
  251. // got an array of embedded objects. Replace the object pointers with a wrapper
  252. // pointer
  253. SAFEARRAYBOUND aBounds[1];
  254. long lLBound, lUBound;
  255. SafeArrayGetLBound(pVal->parray, 1, &lLBound);
  256. SafeArrayGetUBound(pVal->parray, 1, &lUBound);
  257. aBounds[0].cElements = lUBound - lLBound + 1;
  258. aBounds[0].lLbound = lLBound;
  259. // Update the individual data pieces
  260. // ================================
  261. long lIndex;
  262. for (lIndex = lLBound; lIndex <= lUBound; lIndex++)
  263. {
  264. // Load the initial data element into a VARIANT
  265. // ============================================
  266. IDispatch * pDisp = NULL;
  267. if (FAILED (hRes = SafeArrayGetElement(pVal->parray, &lIndex, &pDisp)))
  268. break;
  269. if (pDisp)
  270. {
  271. // If successful this will AddRef the returned interface
  272. IWbemClassObject *pObj = CSWbemObject::GetIWbemClassObject (pDisp);
  273. if (pObj)
  274. {
  275. pDisp->Release (); // Balances the SafeArrayGetElement call
  276. // Put it into the new array
  277. // =========================
  278. hRes = SafeArrayPutElement(pVal->parray, &lIndex, pObj);
  279. pObj->Release (); // balances CSWbemObject::GetIWbemClassObject call
  280. if (FAILED (hRes))
  281. break;
  282. else
  283. pVal->vt = VT_UNKNOWN | VT_ARRAY;
  284. }
  285. else
  286. {
  287. /*
  288. * Rather than just cast IDispatch* to IUnknown*, we do a QI
  289. * with a release just in case the object has per-interface
  290. * ref counting.
  291. */
  292. IUnknown *pUnk = NULL;
  293. if (SUCCEEDED (hRes = pDisp->QueryInterface (IID_IUnknown, (PPVOID) &pUnk)))
  294. {
  295. pDisp->Release (); // Balances the SafeArrayGetElement call
  296. hRes = SafeArrayPutElement(pVal->parray, &lIndex, pUnk);
  297. pUnk->Release (); // Balances the QI call
  298. if (FAILED (hRes))
  299. break;
  300. else
  301. pVal->vt = VT_UNKNOWN | VT_ARRAY;
  302. }
  303. else
  304. {
  305. pDisp->Release (); // Balances the SafeArrayGetElement call
  306. break;
  307. }
  308. }
  309. }
  310. else
  311. break;
  312. }
  313. if (lUBound < lIndex)
  314. {
  315. hRes = WBEM_S_NO_ERROR;
  316. pVal->vt = VT_UNKNOWN | VT_ARRAY;
  317. }
  318. }
  319. return hRes;
  320. }
  321. //***************************************************************************
  322. //
  323. // HRESULT SetSite
  324. //
  325. // Description:
  326. //
  327. // This function examines a VARIANT that has been successfully set as the
  328. // value of a property to determine whether it contains any embedded objects.
  329. // Any such objects are modified to ensure their site represents the property
  330. // in question.
  331. //
  332. // Parameters:
  333. //
  334. // pVal The input variant to check
  335. // pSObject Owning object of the property
  336. // propertyName Take a wild guess
  337. //
  338. // Return Value:
  339. // HRESULT S_OK if successful
  340. //***************************************************************************
  341. void SetSite (VARIANT *pVal, ISWbemInternalObject *pSObject, BSTR propertyName,
  342. long index)
  343. {
  344. HRESULT hRes = S_OK;
  345. if (pVal)
  346. {
  347. if(pVal->vt == VT_DISPATCH || (pVal->vt == (VT_DISPATCH | VT_BYREF)))
  348. {
  349. // Could be an embedded object
  350. IDispatch *pDisp = NULL;
  351. if (VT_DISPATCH == V_VT(pVal))
  352. pDisp = pVal->pdispVal;
  353. else if (NULL != pVal->ppdispVal)
  354. pDisp = *(pVal->ppdispVal);
  355. if (pDisp)
  356. CSWbemObject::SetSite (pDisp, pSObject, propertyName, index);
  357. }
  358. else if(pVal->vt == (VT_DISPATCH | VT_ARRAY))
  359. {
  360. // Could be an array of embedded objects.
  361. SAFEARRAYBOUND aBounds[1];
  362. long lLBound, lUBound;
  363. SafeArrayGetLBound(pVal->parray, 1, &lLBound);
  364. SafeArrayGetUBound(pVal->parray, 1, &lUBound);
  365. aBounds[0].cElements = lUBound - lLBound + 1;
  366. aBounds[0].lLbound = lLBound;
  367. // Update the individual data pieces
  368. // ================================
  369. long lIndex;
  370. for (lIndex = lLBound; lIndex <= lUBound; lIndex++)
  371. {
  372. // Load the initial data element into a VARIANT
  373. // ============================================
  374. IDispatch * pDisp = NULL;
  375. if (FAILED (hRes = SafeArrayGetElement(pVal->parray, &lIndex, &pDisp)))
  376. break;
  377. if (pDisp)
  378. {
  379. CSWbemObject::SetSite (pDisp, pSObject, propertyName, lIndex);
  380. pDisp->Release (); // To balance AddRef from SafeArrayGetElement
  381. }
  382. else
  383. break;
  384. }
  385. }
  386. }
  387. }
  388. //***************************************************************************
  389. //
  390. // HRESULT ConvertArray
  391. //
  392. // Description:
  393. //
  394. // This function is applied to VARIANT arrays in order to check for certain
  395. // restrictions imposed by CIMOM (e.g. they must be homogeneous) or perform
  396. // conversions (certain VARIANT types have to be mapped to acceptable CIMOM
  397. // types).
  398. //
  399. // Return Value:
  400. // HRESULT S_OK if successful
  401. //***************************************************************************
  402. HRESULT ConvertArray(VARIANT * pDest, VARIANT * pSrc, BOOL bQualTypesOnly,
  403. VARTYPE requiredVarType)
  404. {
  405. VARTYPE vtPut;
  406. // Now is not (yet) the time to perform SWbemObject->IWbemClassObject conversion
  407. if (VT_UNKNOWN == requiredVarType)
  408. requiredVarType = VT_DISPATCH;
  409. // Treat these imposters just the same...
  410. if (VT_EMPTY == requiredVarType)
  411. requiredVarType = VT_NULL;
  412. if(pSrc == NULL || pDest == NULL)
  413. return WBEM_E_FAILED;
  414. if (!(V_VT(pSrc) & VT_ARRAY) || !(V_VT(pSrc) & VT_VARIANT))
  415. return WBEM_E_FAILED;
  416. // Extract the source SAFEARRAY (how depends on whether VT_BYREF is set)
  417. SAFEARRAY *parray = NULL;
  418. if (VT_BYREF & V_VT(pSrc))
  419. {
  420. if (pSrc->pparray)
  421. parray = *(pSrc->pparray);
  422. }
  423. else
  424. parray = pSrc->parray;
  425. if (!parray)
  426. return WBEM_E_FAILED;
  427. // Determine the size of the source array. Also make sure that the array
  428. // only has one dimension
  429. unsigned int uDim = SafeArrayGetDim(parray);
  430. if(uDim != 1)
  431. return WBEM_E_FAILED; // Bad array, or too many dimensions
  432. long ix[2] = {0,0};
  433. long lLower, lUpper;
  434. SCODE sc = SafeArrayGetLBound(parray,1,&lLower);
  435. if(sc != S_OK)
  436. return sc;
  437. sc = SafeArrayGetUBound(parray,1,&lUpper);
  438. if(sc != S_OK)
  439. return sc;
  440. int iNumElements = lUpper - lLower +1;
  441. if(iNumElements == 0)
  442. {
  443. // Degenerate case of an empty array - simply create an empty
  444. // copy with a VT_VARIANT type for properties
  445. if (!bQualTypesOnly)
  446. vtPut = VT_VARIANT;
  447. else
  448. {
  449. // For qualifiers, we can hope that we've been given a candidate
  450. // type from an existing value; otherwise we'll just have to make one up.
  451. vtPut = (VT_NULL != requiredVarType) ? requiredVarType : VT_I4;
  452. }
  453. }
  454. else
  455. {
  456. // Use an explicit type if it was supplied
  457. if (VT_NULL != requiredVarType)
  458. {
  459. vtPut = requiredVarType;
  460. }
  461. else
  462. {
  463. // Try an infer one from the array supplied
  464. // Make sure all the elements of the source array are of the same type.
  465. for(ix[0] = lLower; ix[0] <= lUpper && sc == S_OK; ix[0]++)
  466. {
  467. VARIANT var;
  468. VariantInit(&var);
  469. sc = SafeArrayGetElement(parray,ix,&var);
  470. if(sc != S_OK)
  471. return sc;
  472. VARTYPE vt = var.vt;
  473. VariantClear(&var);
  474. if(ix[0] == lLower)
  475. vtPut = vt;
  476. else if (vtPut != vt)
  477. {
  478. // The vartype is different from that previously encountered.
  479. // In general this is an error, but it is possible that we may
  480. // wish to "upcast" to a common vartype in certain circumstances,
  481. // as the automation controller may return heterogenous arrays.
  482. // The only cases in which this applies are:
  483. //
  484. // 1. VT_UI1, VT_I2, VT_I4 should be upcast to the widest
  485. // occurring type in the array.
  486. //
  487. // 2. VT_R4, VT_R8 should be upcast to the widest occuring type
  488. // in the array
  489. //
  490. // All other cases are treated as an error.
  491. bool error = true;
  492. switch (vtPut)
  493. {
  494. case VT_UI1:
  495. if ((VT_I2 == vt) || (VT_I4 == vt))
  496. {
  497. error = false;
  498. vtPut = vt;
  499. }
  500. break;
  501. case VT_I2:
  502. if (VT_UI1 == vt)
  503. {
  504. error = false;
  505. }
  506. else if (VT_I4 == vt)
  507. {
  508. error = false;
  509. vtPut = vt;
  510. }
  511. break;
  512. case VT_I4:
  513. if ((VT_I2 == vt) || (VT_UI1 == vt))
  514. error = false;
  515. break;
  516. case VT_R4:
  517. if (VT_R8 == vt)
  518. {
  519. error = false;
  520. vtPut = vt;
  521. }
  522. break;
  523. case VT_R8:
  524. if (VT_R4 == vt)
  525. error = false;
  526. break;
  527. }
  528. if (error)
  529. return WBEM_E_INVALID_PARAMETER;
  530. }
  531. }
  532. // Having made our best guess, we may need to refine it
  533. // if we are being restricted to qualifier types only
  534. if(bQualTypesOnly)
  535. vtPut = GetAcceptableQualType(vtPut);
  536. }
  537. }
  538. // Create a destination array of equal size
  539. SAFEARRAYBOUND rgsabound[1];
  540. rgsabound[0].lLbound = 0;
  541. rgsabound[0].cElements = iNumElements;
  542. SAFEARRAY * pDestArray = SafeArrayCreate(vtPut,1,rgsabound);
  543. for(ix[0] = lLower; ix[0] <= lUpper && sc == S_OK; ix[0]++)
  544. {
  545. VARIANT var;
  546. VariantInit(&var);
  547. sc = SafeArrayGetElement(parray,ix,&var);
  548. if(sc != S_OK)
  549. {
  550. SafeArrayDestroy (pDestArray);
  551. return sc;
  552. }
  553. if(var.vt != vtPut)
  554. {
  555. // do the conversion to the acceptable type and put that
  556. VARIANT vTemp;
  557. VariantInit(&vTemp);
  558. LCID lcid = GetSystemDefaultLCID();
  559. sc = VariantChangeTypeEx(&vTemp, &var, lcid, 0, vtPut);
  560. if(sc != S_OK)
  561. {
  562. SafeArrayDestroy (pDestArray);
  563. return sc;
  564. }
  565. if(vtPut == VT_BSTR || vtPut == VT_UNKNOWN || vtPut == VT_DISPATCH)
  566. sc = SafeArrayPutElement(pDestArray,ix,(void *)vTemp.bstrVal);
  567. else
  568. sc = SafeArrayPutElement(pDestArray,ix,(void *)&vTemp.lVal);
  569. VariantClear(&vTemp);
  570. }
  571. else
  572. {
  573. if(vtPut == VT_BSTR || vtPut == VT_UNKNOWN || vtPut == VT_DISPATCH)
  574. sc = SafeArrayPutElement(pDestArray,ix,(void *)var.bstrVal);
  575. else
  576. sc = SafeArrayPutElement(pDestArray,ix,(void *)&var.lVal);
  577. }
  578. VariantClear(&var);
  579. }
  580. pDest->vt = (VT_ARRAY | vtPut);
  581. pDest->parray = pDestArray;
  582. return S_OK;
  583. }
  584. //***************************************************************************
  585. //
  586. // HRESULT ConvertArrayRev
  587. //
  588. // Description:
  589. //
  590. // This function is applied to outbound VARIANT arrays in order to transform
  591. // VARIANT arrays so that each member is a VT_VARIANT rather than a simple
  592. // type (VT_BSTR). This is done so that certain automation environments
  593. // (such as VBScript) can correctly interpret array values.
  594. //
  595. // Return Value:
  596. // HRESULT S_OK if successful
  597. //***************************************************************************
  598. HRESULT ConvertArrayRev(VARIANT *pDest, VARIANT *pSrc)
  599. {
  600. if(pSrc == NULL || pDest == NULL || (0 == (pSrc->vt & VT_ARRAY)))
  601. return WBEM_E_FAILED;
  602. // Determine the size of the source array. Also make sure that the array
  603. // only has one dimension
  604. unsigned int uDim = SafeArrayGetDim(pSrc->parray);
  605. if(uDim != 1)
  606. return WBEM_E_FAILED; // Bad array, or too many dimensions
  607. long ix[2] = {0,0};
  608. long lLower, lUpper;
  609. SCODE sc = SafeArrayGetLBound(pSrc->parray,1,&lLower);
  610. if(sc != S_OK)
  611. return sc;
  612. sc = SafeArrayGetUBound(pSrc->parray,1,&lUpper);
  613. if(sc != S_OK)
  614. return sc;
  615. int iNumElements = lUpper - lLower +1;
  616. VARTYPE vtSimple = pSrc->vt & ~VT_ARRAY;
  617. // Create a destination array of equal size
  618. SAFEARRAYBOUND rgsabound[1];
  619. rgsabound[0].lLbound = 0;
  620. rgsabound[0].cElements = iNumElements;
  621. SAFEARRAY *pDestArray = SafeArrayCreate(VT_VARIANT,1,rgsabound);
  622. for(ix[0] = lLower; ix[0] <= lUpper && sc == S_OK; ix[0]++)
  623. {
  624. VARIANT var;
  625. VariantInit(&var);
  626. var.vt = vtSimple;
  627. switch (var.vt)
  628. {
  629. case VT_BSTR:
  630. {
  631. BSTR bstrVal = NULL;
  632. if (S_OK == (sc = SafeArrayGetElement (pSrc->parray, ix, &bstrVal)))
  633. {
  634. var.bstrVal = SysAllocString (bstrVal);
  635. SysFreeString (bstrVal);
  636. }
  637. }
  638. break;
  639. case VT_DISPATCH:
  640. {
  641. IDispatch *pDispatch = NULL;
  642. if (S_OK == (sc = SafeArrayGetElement (pSrc->parray, ix, &pDispatch)))
  643. var.pdispVal = pDispatch;
  644. }
  645. break;
  646. case VT_UNKNOWN:
  647. {
  648. IUnknown *pUnknown = NULL;
  649. if (S_OK == (sc = SafeArrayGetElement (pSrc->parray, ix, &pUnknown)))
  650. var.punkVal = pUnknown;
  651. }
  652. break;
  653. default:
  654. {
  655. // Assume simple integer value
  656. sc = SafeArrayGetElement (pSrc->parray, ix, &(var.lVal));
  657. }
  658. break;
  659. }
  660. if(sc != S_OK)
  661. return sc;
  662. sc = SafeArrayPutElement (pDestArray, ix, &var);
  663. VariantClear(&var);
  664. }
  665. pDest->vt = (VT_ARRAY | VT_VARIANT);
  666. pDest->parray = pDestArray;
  667. return S_OK;
  668. }
  669. //***************************************************************************
  670. //
  671. // HRESULT ConvertBSTRArray
  672. //
  673. // Description:
  674. //
  675. // This function is applied to outbound SAFEARRAY's of BSTRs in order to
  676. // transform then into SAFEARRAY's of VARIANTs (each of type VT_BSTR). This
  677. // is required by scripting environments (such as VBScript0 which do not
  678. // support SAFEARRAY of non-VARIANT types.
  679. //
  680. // Return Value:
  681. // HRESULT S_OK if successful
  682. //***************************************************************************
  683. HRESULT ConvertBSTRArray(SAFEARRAY **ppDest, SAFEARRAY *pSrc)
  684. {
  685. if(pSrc == NULL || ppDest == NULL)
  686. return WBEM_E_FAILED;
  687. // Determine the size of the source array. Also make sure that the array
  688. // only has one dimension
  689. unsigned int uDim = SafeArrayGetDim(pSrc);
  690. if(uDim != 1)
  691. return WBEM_E_FAILED; // Bad array, or too many dimensions
  692. long ix[2] = {0,0};
  693. long lLower, lUpper;
  694. SCODE sc = SafeArrayGetLBound(pSrc,1,&lLower);
  695. if(sc != S_OK)
  696. return sc;
  697. sc = SafeArrayGetUBound(pSrc,1,&lUpper);
  698. if(sc != S_OK)
  699. return sc;
  700. int iNumElements = lUpper - lLower +1;
  701. if(iNumElements == 0)
  702. return WBEM_E_FAILED;
  703. // Create a destination array of equal size
  704. SAFEARRAYBOUND rgsabound[1];
  705. rgsabound[0].lLbound = 0;
  706. rgsabound[0].cElements = iNumElements;
  707. *ppDest = SafeArrayCreate(VT_VARIANT,1,rgsabound);
  708. for(ix[0] = lLower; ix[0] <= lUpper && sc == S_OK; ix[0]++)
  709. {
  710. VARIANT var;
  711. VariantInit(&var);
  712. var.vt = VT_BSTR;
  713. BSTR bstrVal = NULL;
  714. if (S_OK == (sc = SafeArrayGetElement (pSrc, ix, &bstrVal)))
  715. {
  716. var.bstrVal = SysAllocString (bstrVal);
  717. SysFreeString (bstrVal);
  718. }
  719. if(sc != S_OK)
  720. return sc;
  721. sc = SafeArrayPutElement (*ppDest, ix, &var);
  722. VariantClear(&var);
  723. }
  724. return S_OK;
  725. }
  726. //***************************************************************************
  727. //
  728. // HRESULT QualifierVariantChangeType
  729. //
  730. // DESCRIPTION:
  731. //
  732. // Just like VariantChangeType, but deals with arrays as well.
  733. //
  734. // PARAMETERS:
  735. //
  736. // VARIANT pvDest Destination variant
  737. // VARIANT pvSrc Source variant (can be the same as pvDest)
  738. // VARTYPE vtNew The type to coerce to.
  739. //
  740. //***************************************************************************
  741. HRESULT QualifierVariantChangeType (VARIANT* pvDest, VARIANT* pvSrc,
  742. VARTYPE vtNew)
  743. {
  744. HRESULT hres = DISP_E_TYPEMISMATCH;
  745. if(V_VT(pvSrc) == VT_NULL)
  746. {
  747. return VariantCopy(pvDest, pvSrc);
  748. }
  749. if (vtNew & VT_ARRAY)
  750. {
  751. // It's an array, we have to do our own conversion
  752. // ===============================================
  753. if((V_VT(pvSrc) & VT_ARRAY) == 0)
  754. return DISP_E_TYPEMISMATCH;
  755. // Create a new array
  756. SAFEARRAY* psaSrc = V_ARRAY(pvSrc);
  757. SAFEARRAYBOUND aBounds[1];
  758. long lLBound;
  759. SafeArrayGetLBound(psaSrc, 1, &lLBound);
  760. long lUBound;
  761. SafeArrayGetUBound(psaSrc, 1, &lUBound);
  762. aBounds[0].cElements = lUBound - lLBound + 1;
  763. aBounds[0].lLbound = lLBound;
  764. SAFEARRAY* psaDest = SafeArrayCreate(vtNew & ~VT_ARRAY, 1, aBounds);
  765. long lIndex;
  766. for (lIndex = lLBound; lIndex <= lUBound; lIndex++)
  767. {
  768. // Load the initial data element into a VARIANT
  769. // ============================================
  770. VARIANT vSrcEl;
  771. VariantInit (&vSrcEl);
  772. V_VT(&vSrcEl) = V_VT(pvSrc) & ~VT_ARRAY;
  773. SafeArrayGetElement(psaSrc, &lIndex, &V_UI1(&vSrcEl));
  774. // Cast it to the new type
  775. // =======================
  776. if (SUCCEEDED (hres = VariantChangeType(&vSrcEl, &vSrcEl, 0, vtNew & ~VT_ARRAY)))
  777. {
  778. // Put it into the new array
  779. // =========================
  780. if(V_VT(&vSrcEl) == VT_BSTR)
  781. hres = SafeArrayPutElement(psaDest, &lIndex, V_BSTR(&vSrcEl));
  782. else
  783. hres = SafeArrayPutElement(psaDest, &lIndex, &V_UI1(&vSrcEl));
  784. }
  785. VariantClear (&vSrcEl);
  786. if (FAILED(hres))
  787. break;
  788. }
  789. if (lUBound < lIndex)
  790. {
  791. hres = WBEM_S_NO_ERROR;
  792. if(pvDest == pvSrc)
  793. VariantClear(pvSrc);
  794. V_VT(pvDest) = vtNew;
  795. V_ARRAY(pvDest) = psaDest;
  796. }
  797. else
  798. SafeArrayDestroy (psaDest);
  799. }
  800. else
  801. hres = VariantChangeType(pvDest, pvSrc, VARIANT_NOVALUEPROP, vtNew);
  802. return hres;
  803. }
  804. //***************************************************************************
  805. //
  806. // void SetWbemError
  807. //
  808. // DESCRIPTION:
  809. //
  810. // For remoted WBEM COM interfaces, extra error information may be returned
  811. // on the thread as an IWbemClassObject. This routine extracts that object
  812. // (if found) amd stores it in thread local-storage as an ISWbemObject. The
  813. // object can be accessed later using the SWbemLastError coclass.
  814. //
  815. // PARAMETERS:
  816. //
  817. // pService The backpointer to the CSWbemServices (used in case
  818. // we do property/method access on the error object)
  819. //
  820. //***************************************************************************
  821. void SetWbemError (CSWbemServices *pService)
  822. {
  823. EnterCriticalSection (&g_csErrorCache);
  824. if (g_pErrorCache)
  825. g_pErrorCache->SetCurrentThreadError (pService);
  826. LeaveCriticalSection (&g_csErrorCache);
  827. }
  828. //***************************************************************************
  829. //
  830. // void ResetLastErrors
  831. //
  832. // DESCRIPTION:
  833. //
  834. // For remoted WBEM COM interfaces, extra error information may be returned
  835. // on the thread as an IWbemClassObject. This routine clears that error. It
  836. // also clears the ErrorInfo on the thread. This should be called at the
  837. // start of any of the API functions
  838. //
  839. // PARAMETERS:
  840. //
  841. //***************************************************************************
  842. void ResetLastErrors ()
  843. {
  844. SetErrorInfo(0, NULL);
  845. EnterCriticalSection (&g_csErrorCache);
  846. if (g_pErrorCache)
  847. g_pErrorCache->ResetCurrentThreadError ();
  848. LeaveCriticalSection (&g_csErrorCache);
  849. }
  850. //***************************************************************************
  851. //
  852. // HRESULT SetException
  853. //
  854. // Description:
  855. //
  856. // This function fills in an EXECPINFO structure using the supplied HRESULT
  857. // and object name. The former is mapped to the Err.Description property,
  858. // and the latter to the Err.Source property.
  859. //
  860. // Parameters:
  861. //
  862. // pExcepInfo pointer to EXCEPINFO to initialize (must not be NULL)
  863. // hr HRESULT to map to string
  864. // bsObjectName Name of source object that generated the error
  865. //
  866. // Return Value:
  867. // HRESULT S_OK if successful
  868. //***************************************************************************
  869. void SetException (EXCEPINFO *pExcepInfo, HRESULT hr, BSTR bsObjectName)
  870. {
  871. if (pExcepInfo->bstrDescription)
  872. SysFreeString (pExcepInfo->bstrDescription);
  873. pExcepInfo->bstrDescription = MapHresultToWmiDescription (hr);
  874. if (pExcepInfo->bstrSource)
  875. SysFreeString (pExcepInfo->bstrSource);
  876. pExcepInfo->bstrSource = SysAllocString (bsObjectName);
  877. pExcepInfo->scode = hr;
  878. }
  879. //***************************************************************************
  880. //
  881. // HRESULT MapHresultToWmiDescription
  882. //
  883. // Description:
  884. //
  885. // Thin wrapper around the IWbemStatusCodeText implementation. Transforms
  886. // an HRESULT (which may or may not be a WMI-specific error code) into a
  887. // localized user-friendly description.
  888. //
  889. // Parameters:
  890. //
  891. // hr HRESULT to map to string
  892. //
  893. // Return Value:
  894. // BSTR containing the description (or NULL).
  895. //***************************************************************************
  896. BSTR MapHresultToWmiDescription (HRESULT hr)
  897. {
  898. BSTR bsMessageText = NULL;
  899. // Used as our error code translator
  900. IWbemStatusCodeText *pErrorCodeTranslator = NULL;
  901. HRESULT result = CoCreateInstance (CLSID_WbemStatusCodeText, 0, CLSCTX_INPROC_SERVER,
  902. IID_IWbemStatusCodeText, (LPVOID *) &pErrorCodeTranslator);
  903. if (SUCCEEDED (result))
  904. {
  905. HRESULT hrCode = hr;
  906. // Some WBEM success codes become Scripting error codes.
  907. if (wbemErrTimedout == hr)
  908. hrCode = WBEM_S_TIMEDOUT;
  909. else if (wbemErrResetToDefault == hr)
  910. hrCode = WBEM_S_RESET_TO_DEFAULT;
  911. HRESULT sc = pErrorCodeTranslator->GetErrorCodeText(
  912. hrCode, (LCID) 0, WBEMSTATUS_FORMAT_NO_NEWLINE, &bsMessageText);
  913. pErrorCodeTranslator->Release ();
  914. }
  915. return bsMessageText;
  916. }
  917. //***************************************************************************
  918. //
  919. // HRESULT ConvertDispatchToArray
  920. //
  921. // DESCRIPTION:
  922. //
  923. // Attempt to convert from an IDispatch value to a CIM array value (property
  924. // qualifier or context).
  925. //
  926. // PARAMETERS:
  927. //
  928. // pDest Output value
  929. // pSrc Input value
  930. // lCimType CIM Property type (underlying the array) - defaults to
  931. // CIM_ILLEGAL for Qualifier & Context value mappings.
  932. // bIsQual true iff we are mapping for a qualifier
  933. //
  934. // RETURN VALUES:
  935. //
  936. // WBEM_S_NO_ERROR success
  937. // WBEM_E_FAILED otherwise
  938. //
  939. //***************************************************************************
  940. HRESULT ConvertDispatchToArray (
  941. VARIANT *pvDest,
  942. VARIANT *pvSrc,
  943. CIMTYPE lCimType,
  944. BOOL bIsQual,
  945. VARTYPE requiredQualifierType
  946. )
  947. {
  948. HRESULT hr = WBEM_E_FAILED; // Default error
  949. IDispatch * pDispatch = NULL;
  950. /*
  951. * Extract the IDispatch pointer. NB we assume the VT of pSrc is
  952. * VT_DISPATCH (possibly combined with VT_BYREF) for this function to
  953. * have been called.
  954. */
  955. if (VT_DISPATCH == V_VT(pvSrc))
  956. pDispatch = pvSrc->pdispVal;
  957. else if (pvSrc->ppdispVal)
  958. pDispatch = *(pvSrc->ppdispVal);
  959. if (NULL == pDispatch)
  960. return hr;
  961. // The expected var type of the property
  962. VARTYPE expectedVarType = VT_ERROR;
  963. if (CIM_ILLEGAL != lCimType)
  964. expectedVarType = CimTypeToVtType (lCimType);
  965. CComQIPtr<IDispatchEx> pIDispatchEx (pDispatch);
  966. /*
  967. * We use the IDispatchEx interface to iterate through the properties
  968. * of the interface.
  969. */
  970. if (pIDispatchEx)
  971. {
  972. /*
  973. * Looks promising, but just check if this isn't one of our objects
  974. */
  975. CComQIPtr<ISWbemObject> pISWbemObject (pDispatch);
  976. if (!pISWbemObject)
  977. {
  978. /*
  979. * Start by determining how many properties there are so we can create
  980. * a suitable array.
  981. */
  982. long propertyCount = 0;
  983. DISPID dispId = DISPID_STARTENUM;
  984. DISPPARAMS dispParams;
  985. dispParams.rgvarg = NULL;
  986. dispParams.rgdispidNamedArgs = NULL;
  987. dispParams.cArgs = 0;
  988. dispParams.cNamedArgs = 0;
  989. while (S_OK == pIDispatchEx->GetNextDispID (fdexEnumAll, dispId, &dispId))
  990. {
  991. if ((0 == propertyCount) && (VT_ERROR == expectedVarType))
  992. {
  993. /*
  994. * If we are setting an array value for a context/qualifier, the
  995. * Vartype will not yet be determined - we will use the best
  996. * we can from the first array value.
  997. */
  998. VARIANT vPropVal;
  999. VariantInit (&vPropVal);
  1000. if (SUCCEEDED (pIDispatchEx->InvokeEx (dispId, 0,
  1001. DISPATCH_PROPERTYGET, &dispParams, &vPropVal, NULL, NULL)))
  1002. {
  1003. if (bIsQual)
  1004. expectedVarType = GetAcceptableQualType(V_VT(&vPropVal));
  1005. else if (VT_DISPATCH == V_VT(&vPropVal))
  1006. expectedVarType = VT_UNKNOWN;
  1007. else
  1008. expectedVarType = V_VT(&vPropVal);
  1009. }
  1010. VariantClear (&vPropVal);
  1011. }
  1012. propertyCount++;
  1013. }
  1014. // Create the safearray - note that it may be empty
  1015. SAFEARRAYBOUND rgsaBound;
  1016. rgsaBound.cElements = propertyCount;
  1017. rgsaBound.lLbound = 0;
  1018. SAFEARRAY *pArray = SafeArrayCreate (expectedVarType, 1, &rgsaBound);
  1019. if (0 < propertyCount)
  1020. {
  1021. // Enumerate the DISPIDs on this interface
  1022. dispId = DISPID_STARTENUM;
  1023. long nextExpectedIndex = 0;
  1024. HRESULT enumHr;
  1025. wchar_t *stopString = NULL;
  1026. /*
  1027. * For JScript arrays, the property names are the specified indices of the
  1028. * the array; these can be integer indices or they can be strings. We make
  1029. * the following requirements of the array indices:
  1030. *
  1031. * (1) All of the indices are non-negative integers
  1032. * (2) The indices start at 0 and are contiguous.
  1033. */
  1034. while (S_OK == (enumHr = pIDispatchEx->GetNextDispID (fdexEnumAll, dispId, &dispId)))
  1035. {
  1036. BSTR memberName = NULL;
  1037. if (SUCCEEDED(pIDispatchEx->GetMemberName (dispId, &memberName)))
  1038. {
  1039. // Check that property name is numeric
  1040. long index = wcstol (memberName, &stopString, 10);
  1041. if ((0 != wcslen (stopString)))
  1042. {
  1043. // Failure - cannot convert to integer
  1044. SysFreeString (memberName);
  1045. memberName = NULL;
  1046. break;
  1047. }
  1048. SysFreeString (memberName);
  1049. memberName = NULL;
  1050. if (index != nextExpectedIndex)
  1051. {
  1052. // Failure - non-contiguous array
  1053. break;
  1054. }
  1055. nextExpectedIndex++;
  1056. // Extract the property
  1057. VARIANT vPropVal;
  1058. VariantInit (&vPropVal);
  1059. HRESULT hrInvoke;
  1060. if (SUCCEEDED (hrInvoke = pIDispatchEx->InvokeEx (dispId, 0,
  1061. DISPATCH_PROPERTYGET, &dispParams, &vPropVal, NULL, NULL)))
  1062. {
  1063. HRESULT hr2 = WBEM_E_FAILED;
  1064. // Take care of embedded objects
  1065. if ((S_OK == MapToCIMOMObject (&vPropVal)) &&
  1066. (S_OK == VariantChangeType (&vPropVal, &vPropVal, 0, expectedVarType)))
  1067. {
  1068. switch (expectedVarType)
  1069. {
  1070. case VT_BSTR:
  1071. hr2 = SafeArrayPutElement (pArray, &index, (void*)vPropVal.bstrVal);
  1072. break;
  1073. case VT_UNKNOWN:
  1074. if (!bIsQual)
  1075. hr2 = SafeArrayPutElement (pArray, &index, (void*)vPropVal.punkVal);
  1076. break;
  1077. default:
  1078. hr2 = SafeArrayPutElement (pArray, &index, (void*)&vPropVal.lVal);
  1079. break;
  1080. }
  1081. }
  1082. VariantClear (&vPropVal);
  1083. if (FAILED(hr2))
  1084. break;
  1085. }
  1086. else
  1087. {
  1088. // Failure - couldn't invoke method
  1089. break;
  1090. }
  1091. } // GetMemberName SUCCEEDED
  1092. } // while loop
  1093. if (S_FALSE == enumHr)
  1094. {
  1095. // Now construct the new property value using our array
  1096. VariantInit (pvDest);
  1097. pvDest->vt = VT_ARRAY | expectedVarType;
  1098. pvDest->parray = pArray;
  1099. hr = S_OK;
  1100. }
  1101. else
  1102. {
  1103. // Something went wrong
  1104. SafeArrayDestroy (pArray);
  1105. }
  1106. }
  1107. else
  1108. {
  1109. // Degenerate case of an empty array - simply create an empty
  1110. // copy with a VT_VARIANT type for properties
  1111. if (!bIsQual)
  1112. expectedVarType = VT_VARIANT;
  1113. else
  1114. {
  1115. // For qualifiers, we can hope that we've been given a candidate
  1116. // type from an existing value; otherwise we'll just have to make one up.
  1117. expectedVarType = (VT_NULL != requiredQualifierType) ? requiredQualifierType :
  1118. VT_I4;
  1119. }
  1120. VariantInit (pvDest);
  1121. pvDest->vt = VT_ARRAY | expectedVarType;
  1122. pvDest->parray = pArray;
  1123. hr = S_OK;
  1124. }
  1125. }
  1126. }
  1127. return hr;
  1128. }
  1129. //***************************************************************************
  1130. //
  1131. // void MapNulls
  1132. //
  1133. // Description:
  1134. //
  1135. // The passing of a "null" value from script (where "null" in VB/VBS and JS
  1136. // is the keyword null, and is an undefined variable in Perl) may be interpreted
  1137. // by this API as equivalent to a default value for certain method calls.
  1138. //
  1139. // This function is used to map VT_NULL dispatch parameters to the VB standard
  1140. // realization of "missing" parameters, i.e. a VT_ERROR value whose scode is
  1141. // DISP_E_PARAMNOTFOUND.
  1142. //
  1143. // Parameters:
  1144. //
  1145. // pdispparams the input dispatch parameters
  1146. //
  1147. //***************************************************************************
  1148. void MapNulls (DISPPARAMS FAR* pdispparams)
  1149. {
  1150. if (pdispparams)
  1151. {
  1152. for (unsigned int i = 0; i < pdispparams->cArgs; i++)
  1153. {
  1154. VARIANTARG &v = pdispparams->rgvarg [i];
  1155. if (VT_NULL == V_VT(&v))
  1156. {
  1157. v.vt = VT_ERROR;
  1158. v.scode = DISP_E_PARAMNOTFOUND;
  1159. }
  1160. else if (((VT_VARIANT|VT_BYREF) == V_VT(&v)) &&
  1161. (VT_NULL == V_VT(v.pvarVal)))
  1162. {
  1163. v.vt = VT_ERROR;
  1164. v.scode = DISP_E_PARAMNOTFOUND;
  1165. }
  1166. }
  1167. }
  1168. }
  1169. //***************************************************************************
  1170. //
  1171. // BSTR FormatAssociatorsQuery
  1172. //
  1173. // Description:
  1174. //
  1175. // Takes the parameters to an AssociatorsOf call and constructs a WQL
  1176. // query string from them.
  1177. //
  1178. // Returns: The constructed WQL query; this must be freed using
  1179. // SysFreeString by the caller.
  1180. //
  1181. // pdispparams the input dispatch parameters
  1182. //
  1183. //***************************************************************************
  1184. BSTR FormatAssociatorsQuery
  1185. (
  1186. BSTR strObjectPath,
  1187. BSTR strAssocClass,
  1188. BSTR strResultClass,
  1189. BSTR strResultRole,
  1190. BSTR strRole,
  1191. VARIANT_BOOL bClassesOnly,
  1192. VARIANT_BOOL bSchemaOnly,
  1193. BSTR strRequiredAssocQualifier,
  1194. BSTR strRequiredQualifier
  1195. )
  1196. {
  1197. BSTR bsQuery = NULL;
  1198. // Get the length of the string:
  1199. // associators of {SourceObject} where
  1200. // AssocClass = AssocClassName
  1201. // ClassDefsOnly
  1202. // SchemaOnly
  1203. // RequiredAssocQualifier = QualifierName
  1204. // RequiredQualifier = QualifierName
  1205. // ResultClass = ClassName
  1206. // ResultRole = PropertyName
  1207. // Role = PropertyName
  1208. long queryLength = 1; // Terminating NULL
  1209. queryLength += wcslen (WBEMS_QUERY_ASSOCOF) +
  1210. wcslen (WBEMS_QUERY_OPENBRACE) +
  1211. wcslen (WBEMS_QUERY_CLOSEBRACE) +
  1212. wcslen (strObjectPath);
  1213. bool needWhere = false;
  1214. if ((strAssocClass && (0 < wcslen (strAssocClass))) ||
  1215. (strResultClass && (0 < wcslen (strResultClass))) ||
  1216. (strResultRole && (0 < wcslen (strResultRole))) ||
  1217. (strRole && (0 < wcslen (strRole))) ||
  1218. (VARIANT_FALSE != bClassesOnly) ||
  1219. (VARIANT_FALSE != bSchemaOnly) ||
  1220. (strRequiredAssocQualifier && (0 < wcslen (strRequiredAssocQualifier))) ||
  1221. (strRequiredQualifier && (0 < wcslen (strRequiredQualifier))))
  1222. {
  1223. needWhere = true;
  1224. queryLength += wcslen (WBEMS_QUERY_WHERE);
  1225. }
  1226. if (strAssocClass && (0 < wcslen (strAssocClass)))
  1227. queryLength += wcslen (WBEMS_QUERY_ASSOCCLASS) +
  1228. wcslen (WBEMS_QUERY_EQUALS) +
  1229. wcslen (strAssocClass);
  1230. if (strResultClass && (0 < wcslen (strResultClass)))
  1231. queryLength += wcslen (WBEMS_QUERY_RESCLASS) +
  1232. wcslen (WBEMS_QUERY_EQUALS) +
  1233. wcslen (strResultClass);
  1234. if (strResultRole && (0 < wcslen (strResultRole)))
  1235. queryLength += wcslen (WBEMS_QUERY_RESROLE) +
  1236. wcslen (WBEMS_QUERY_EQUALS) +
  1237. wcslen (strResultRole);
  1238. if (strRole && (0 < wcslen (strRole)))
  1239. queryLength += wcslen (WBEMS_QUERY_ROLE) +
  1240. wcslen (WBEMS_QUERY_EQUALS) +
  1241. wcslen (strRole);
  1242. if (VARIANT_FALSE != bClassesOnly)
  1243. queryLength += wcslen (WBEMS_QUERY_CLASSDEFS);
  1244. if (VARIANT_FALSE != bSchemaOnly)
  1245. queryLength += wcslen (WBEMS_QUERY_SCHEMAONLY);
  1246. if (strRequiredAssocQualifier && (0 < wcslen (strRequiredAssocQualifier)))
  1247. queryLength += wcslen (WBEMS_QUERY_REQASSOCQ) +
  1248. wcslen (WBEMS_QUERY_EQUALS) +
  1249. wcslen (strRequiredAssocQualifier);
  1250. if (strRequiredQualifier && (0 < wcslen (strRequiredQualifier)))
  1251. queryLength += wcslen (WBEMS_QUERY_REQQUAL) +
  1252. wcslen (WBEMS_QUERY_EQUALS) +
  1253. wcslen (strRequiredQualifier);
  1254. // Allocate the string and fill it in
  1255. bsQuery = SysAllocStringLen (WBEMS_QUERY_ASSOCOF, queryLength);
  1256. wcscat (bsQuery, WBEMS_QUERY_OPENBRACE);
  1257. wcscat (bsQuery, strObjectPath);
  1258. wcscat (bsQuery, WBEMS_QUERY_CLOSEBRACE);
  1259. if (needWhere)
  1260. {
  1261. wcscat (bsQuery, WBEMS_QUERY_WHERE);
  1262. if (strAssocClass && (0 < wcslen (strAssocClass)))
  1263. {
  1264. wcscat (bsQuery, WBEMS_QUERY_ASSOCCLASS);
  1265. wcscat (bsQuery, WBEMS_QUERY_EQUALS);
  1266. wcscat (bsQuery, strAssocClass);
  1267. }
  1268. if (strResultClass && (0 < wcslen (strResultClass)))
  1269. {
  1270. wcscat (bsQuery, WBEMS_QUERY_RESCLASS);
  1271. wcscat (bsQuery, WBEMS_QUERY_EQUALS);
  1272. wcscat (bsQuery, strResultClass);
  1273. }
  1274. if (strResultRole && (0 < wcslen (strResultRole)))
  1275. {
  1276. wcscat (bsQuery, WBEMS_QUERY_RESROLE);
  1277. wcscat (bsQuery, WBEMS_QUERY_EQUALS);
  1278. wcscat (bsQuery, strResultRole);
  1279. }
  1280. if (strRole && (0 < wcslen (strRole)))
  1281. {
  1282. wcscat (bsQuery, WBEMS_QUERY_ROLE);
  1283. wcscat (bsQuery, WBEMS_QUERY_EQUALS);
  1284. wcscat (bsQuery, strRole);
  1285. }
  1286. if (VARIANT_FALSE != bClassesOnly)
  1287. wcscat (bsQuery, WBEMS_QUERY_CLASSDEFS);
  1288. if (VARIANT_FALSE != bSchemaOnly)
  1289. wcscat (bsQuery, WBEMS_QUERY_SCHEMAONLY);
  1290. if (strRequiredAssocQualifier && (0 < wcslen (strRequiredAssocQualifier)))
  1291. {
  1292. wcscat (bsQuery, WBEMS_QUERY_REQASSOCQ);
  1293. wcscat (bsQuery, WBEMS_QUERY_EQUALS);
  1294. wcscat (bsQuery, strRequiredAssocQualifier);
  1295. }
  1296. if (strRequiredQualifier && (0 < wcslen (strRequiredQualifier)))
  1297. {
  1298. wcscat (bsQuery, WBEMS_QUERY_REQQUAL);
  1299. wcscat (bsQuery, WBEMS_QUERY_EQUALS);
  1300. wcscat (bsQuery, strRequiredQualifier);
  1301. }
  1302. }
  1303. return bsQuery;
  1304. }
  1305. //***************************************************************************
  1306. //
  1307. // BSTR FormatReferencesQuery
  1308. //
  1309. // Description:
  1310. //
  1311. // Takes the parameters to an ReferencesOf call and constructs a WQL
  1312. // query string from them.
  1313. //
  1314. // Returns: The constructed WQL query; this must be freed using
  1315. // SysFreeString by the caller.
  1316. //
  1317. // pdispparams the input dispatch parameters
  1318. //
  1319. //***************************************************************************
  1320. BSTR FormatReferencesQuery
  1321. (
  1322. BSTR strObjectPath,
  1323. BSTR strResultClass,
  1324. BSTR strRole,
  1325. VARIANT_BOOL bClassesOnly,
  1326. VARIANT_BOOL bSchemaOnly,
  1327. BSTR strRequiredQualifier
  1328. )
  1329. {
  1330. BSTR bsQuery = NULL;
  1331. // Get the length of the string:
  1332. // references of {SourceObject} where
  1333. // ClassDefsOnly
  1334. // SchemaOnly
  1335. // RequiredQualifier = QualifierName
  1336. // ResultClass = ClassName
  1337. // Role = PropertyName
  1338. long queryLength = 1; // Terminating NULL
  1339. queryLength += wcslen (WBEMS_QUERY_REFOF) +
  1340. wcslen (WBEMS_QUERY_OPENBRACE) +
  1341. wcslen (WBEMS_QUERY_CLOSEBRACE) +
  1342. wcslen (strObjectPath);
  1343. bool needWhere = false;
  1344. if ((strResultClass && (0 < wcslen (strResultClass))) ||
  1345. (strRole && (0 < wcslen (strRole))) ||
  1346. (VARIANT_FALSE != bClassesOnly) ||
  1347. (VARIANT_FALSE != bSchemaOnly) ||
  1348. (strRequiredQualifier && (0 < wcslen (strRequiredQualifier))))
  1349. {
  1350. needWhere = true;
  1351. queryLength += wcslen (WBEMS_QUERY_WHERE);
  1352. }
  1353. if (strResultClass && (0 < wcslen (strResultClass)))
  1354. queryLength += wcslen (WBEMS_QUERY_RESCLASS) +
  1355. wcslen (WBEMS_QUERY_EQUALS) +
  1356. wcslen (strResultClass);
  1357. if (strRole && (0 < wcslen (strRole)))
  1358. queryLength += wcslen (WBEMS_QUERY_ROLE) +
  1359. wcslen (WBEMS_QUERY_EQUALS) +
  1360. wcslen (strRole);
  1361. if (VARIANT_FALSE != bClassesOnly)
  1362. queryLength += wcslen (WBEMS_QUERY_CLASSDEFS);
  1363. if (VARIANT_FALSE != bSchemaOnly)
  1364. queryLength += wcslen (WBEMS_QUERY_SCHEMAONLY);
  1365. if (strRequiredQualifier && (0 < wcslen (strRequiredQualifier)))
  1366. queryLength += wcslen (WBEMS_QUERY_REQQUAL) +
  1367. wcslen (WBEMS_QUERY_EQUALS) +
  1368. wcslen (strRequiredQualifier);
  1369. // Allocate the string and fill it in
  1370. bsQuery = SysAllocStringLen (WBEMS_QUERY_REFOF, queryLength);
  1371. wcscat (bsQuery, WBEMS_QUERY_OPENBRACE);
  1372. wcscat (bsQuery, strObjectPath);
  1373. wcscat (bsQuery, WBEMS_QUERY_CLOSEBRACE);
  1374. if (needWhere)
  1375. {
  1376. wcscat (bsQuery, WBEMS_QUERY_WHERE);
  1377. if (strResultClass && (0 < wcslen (strResultClass)))
  1378. {
  1379. wcscat (bsQuery, WBEMS_QUERY_RESCLASS);
  1380. wcscat (bsQuery, WBEMS_QUERY_EQUALS);
  1381. wcscat (bsQuery, strResultClass);
  1382. }
  1383. if (strRole && (0 < wcslen (strRole)))
  1384. {
  1385. wcscat (bsQuery, WBEMS_QUERY_ROLE);
  1386. wcscat (bsQuery, WBEMS_QUERY_EQUALS);
  1387. wcscat (bsQuery, strRole);
  1388. }
  1389. if (VARIANT_FALSE != bClassesOnly)
  1390. wcscat (bsQuery, WBEMS_QUERY_CLASSDEFS);
  1391. if (VARIANT_FALSE != bSchemaOnly)
  1392. wcscat (bsQuery, WBEMS_QUERY_SCHEMAONLY);
  1393. if (strRequiredQualifier && (0 < wcslen (strRequiredQualifier)))
  1394. {
  1395. wcscat (bsQuery, WBEMS_QUERY_REQQUAL);
  1396. wcscat (bsQuery, WBEMS_QUERY_EQUALS);
  1397. wcscat (bsQuery, strRequiredQualifier);
  1398. }
  1399. }
  1400. return bsQuery;
  1401. }
  1402. //***************************************************************************
  1403. //
  1404. // BSTR FormatMultiQuery
  1405. //
  1406. // Description:
  1407. //
  1408. // Takes an array of class names and formats a multi query
  1409. //
  1410. // Returns: The constructed WQL query; this must be freed using
  1411. // SysFreeString by the caller.
  1412. //
  1413. // classArray SAFEARRAY of class names
  1414. // iNumElements length of array
  1415. //
  1416. //***************************************************************************
  1417. BSTR FormatMultiQuery (
  1418. SAFEARRAY & classArray,
  1419. long iNumElements
  1420. )
  1421. {
  1422. BSTR bsQuery = NULL;
  1423. long queryLength = 1; // Terminating NULL
  1424. queryLength += (iNumElements * wcslen (WBEMS_QUERY_SELECT)) +
  1425. ((iNumElements - 1) * wcslen (WBEMS_QUERY_GO));
  1426. // Work out the string lengths
  1427. HRESULT hr = S_OK;
  1428. for (long i = 0; i < iNumElements && hr == S_OK; i++)
  1429. {
  1430. BSTR bsName = NULL;
  1431. if (SUCCEEDED(hr = SafeArrayGetElement(&classArray, &i, &bsName)))
  1432. {
  1433. queryLength += wcslen (bsName);
  1434. SysFreeString (bsName);
  1435. }
  1436. }
  1437. if (SUCCEEDED(hr))
  1438. {
  1439. // Allocate the string and fill it in
  1440. bsQuery = SysAllocStringLen (WBEMS_QUERY_SELECT, queryLength);
  1441. for (long i = 0; i < iNumElements && hr == S_OK; i++)
  1442. {
  1443. BSTR bsName = NULL;
  1444. if (SUCCEEDED(hr = SafeArrayGetElement(&classArray, &i, &bsName)))
  1445. {
  1446. if (i > 0)
  1447. wcscat (bsQuery, WBEMS_QUERY_SELECT);
  1448. wcscat (bsQuery, bsName);
  1449. SysFreeString (bsName);
  1450. if (i < iNumElements - 1)
  1451. wcscat (bsQuery, WBEMS_QUERY_GO);
  1452. }
  1453. }
  1454. }
  1455. return bsQuery;
  1456. }
  1457. //***************************************************************************
  1458. //
  1459. // EnsureGlobalsInitialized
  1460. //
  1461. // DESCRIPTION:
  1462. //
  1463. // Checks whether the g_pErrorCache global pointer is correctly initialized
  1464. // and, if not, assigns it appropriately.
  1465. //
  1466. //***************************************************************************
  1467. void EnsureGlobalsInitialized ()
  1468. {
  1469. // Initialize security
  1470. CSWbemSecurity::Initialize ();
  1471. EnterCriticalSection (&g_csErrorCache);
  1472. // Initlialize the error cache if proof be need be
  1473. if ( ! g_pErrorCache )
  1474. g_pErrorCache = new CWbemErrorCache ();
  1475. LeaveCriticalSection (&g_csErrorCache);
  1476. }
  1477. #ifdef _RDEBUG
  1478. #undef _RPrint
  1479. void _RRPrint(int line, const char *file, const char *func,
  1480. const char *str, long code, const char *str2)
  1481. {
  1482. FILE *fp = fopen("c:/out.txt", "a");
  1483. fprintf (fp, "%s %s(%d): %s - %s %ld(0x%lx)\n", file, func, line, str, str2, code, code);
  1484. fclose(fp);
  1485. }
  1486. #endif
  1487. //***************************************************************************
  1488. //
  1489. // CanCoerceString
  1490. //
  1491. // DESCRIPTION:
  1492. //
  1493. // Attempts to determine whether the supplied BSTR value can be cast
  1494. // more tightly to the given CIM type.
  1495. //
  1496. // PARAMETERS:
  1497. // pVal the variant in question
  1498. // cimType the casting CIM type
  1499. //
  1500. // RETURN VALUES:
  1501. // TRUE iff the cast is OK.
  1502. //
  1503. //***************************************************************************
  1504. bool CanCoerceString (
  1505. const BSTR & bsValue,
  1506. WbemCimtypeEnum cimType
  1507. )
  1508. {
  1509. bool result = false;
  1510. switch (cimType)
  1511. {
  1512. case wbemCimtypeReference:
  1513. {
  1514. CSWbemObjectPath objPath;
  1515. result = SUCCEEDED (objPath.put_Path (bsValue));
  1516. }
  1517. break;
  1518. case wbemCimtypeDatetime:
  1519. {
  1520. CSWbemDateTime dateTime;
  1521. result = SUCCEEDED (dateTime.put_Value (bsValue));
  1522. }
  1523. break;
  1524. case wbemCimtypeSint64:
  1525. {
  1526. __int64 ri64;
  1527. result = ReadI64(bsValue, ri64);
  1528. }
  1529. break;
  1530. case wbemCimtypeUint64:
  1531. {
  1532. unsigned __int64 ri64;
  1533. result = ReadUI64(bsValue, ri64);
  1534. }
  1535. break;
  1536. case wbemCimtypeString:
  1537. result = true;
  1538. break;
  1539. }
  1540. return result;
  1541. }
  1542. //***************************************************************************
  1543. //
  1544. // MapVariantTypeToCimType
  1545. //
  1546. // DESCRIPTION:
  1547. //
  1548. // Attempts to come up with a decent CIM type for the supplied VARIANT value.
  1549. //
  1550. // PARAMETERS:
  1551. // pVal the variant in question
  1552. // iCimType preferred cimtype (if appropriate)
  1553. //
  1554. // RETURN VALUES:
  1555. // A best match CIM type
  1556. //
  1557. //***************************************************************************
  1558. WbemCimtypeEnum MapVariantTypeToCimType (
  1559. VARIANT *pVal,
  1560. CIMTYPE iCimType)
  1561. {
  1562. WbemCimtypeEnum cimType = wbemCimtypeSint32;
  1563. if (pVal)
  1564. {
  1565. VARIANT vTemp;
  1566. VariantInit (&vTemp);
  1567. if ((VT_EMPTY == V_VT(pVal)) || (VT_NULL == V_VT(pVal)))
  1568. cimType = (CIM_ILLEGAL == iCimType) ?
  1569. wbemCimtypeSint32 : (WbemCimtypeEnum) iCimType;
  1570. else if (((VT_ARRAY | VT_VARIANT) == V_VT(pVal)) ||
  1571. ((VT_ARRAY | VT_VARIANT | VT_BYREF) == V_VT(pVal)))
  1572. {
  1573. // Need to dig out the array type
  1574. if ((S_OK == ConvertArray(&vTemp, pVal)) &&
  1575. (S_OK == MapToCIMOMObject(&vTemp)))
  1576. {
  1577. // Check for empty array
  1578. long lLower, lUpper;
  1579. if ((SUCCEEDED(SafeArrayGetLBound(vTemp.parray,1,&lLower))) &&
  1580. (SUCCEEDED(SafeArrayGetUBound(vTemp.parray,1,&lUpper))))
  1581. {
  1582. if (0 == lUpper - lLower + 1)
  1583. {
  1584. // For an empty array, we use wbemCimtypeSint32 unless
  1585. // we have been supplied a valid override
  1586. cimType = (CIM_ILLEGAL == iCimType) ?
  1587. wbemCimtypeSint32 : (WbemCimtypeEnum) iCimType;
  1588. }
  1589. else
  1590. {
  1591. // Pick something that matches our value and override
  1592. // as best we can
  1593. cimType = GetCIMType (vTemp, iCimType, true, lLower, lUpper);
  1594. }
  1595. }
  1596. }
  1597. }
  1598. else
  1599. {
  1600. // Look for an IDispatch that needs to be mapped to an array
  1601. if (((VT_DISPATCH == V_VT(pVal)) || ((VT_DISPATCH|VT_BYREF) == V_VT(pVal))))
  1602. {
  1603. if (S_OK == ConvertDispatchToArray (&vTemp, pVal, cimType & ~CIM_FLAG_ARRAY))
  1604. {
  1605. // Check for empty array
  1606. long lLower, lUpper;
  1607. if ((SUCCEEDED(SafeArrayGetLBound(vTemp.parray,1,&lLower))) &&
  1608. (SUCCEEDED(SafeArrayGetUBound(vTemp.parray,1,&lUpper))))
  1609. {
  1610. if (0 == lUpper - lLower + 1)
  1611. cimType = (CIM_ILLEGAL == iCimType) ?
  1612. wbemCimtypeSint32 : (WbemCimtypeEnum) iCimType;
  1613. else
  1614. cimType = GetCIMType (vTemp, iCimType, true, lLower, lUpper);
  1615. }
  1616. }
  1617. else
  1618. {
  1619. // Could be a plain old interface pointer for CIM_IUNKNOWN
  1620. if (SUCCEEDED(VariantCopy (&vTemp, pVal)))
  1621. {
  1622. if (S_OK == MapToCIMOMObject(&vTemp))
  1623. cimType = GetCIMType (vTemp, iCimType);
  1624. }
  1625. }
  1626. }
  1627. else
  1628. {
  1629. // The vanilla case
  1630. if (SUCCEEDED(VariantCopy (&vTemp, pVal)))
  1631. {
  1632. if (S_OK == MapToCIMOMObject(&vTemp))
  1633. cimType = GetCIMType (vTemp, iCimType);
  1634. }
  1635. }
  1636. }
  1637. VariantClear (&vTemp);
  1638. }
  1639. return cimType;
  1640. }
  1641. //***************************************************************************
  1642. //
  1643. // GetCIMType
  1644. //
  1645. // DESCRIPTION:
  1646. //
  1647. // Attempts to come up with a decent CIM type for the supplied VARIANT,
  1648. // with (optionally) a legal CIMType "serving suggestion" to help resolve
  1649. // ambiguities.
  1650. //
  1651. // Note that this function doesn't deal with empty arrays; that has
  1652. // already been taken care of by the caller. It also can assume that the
  1653. // array is (VARTYPE) homogeneous, for the same reason.
  1654. //
  1655. // PARAMETERS:
  1656. // pVal the variant in question
  1657. // iCimType preferred cimtype (if appropriate, else wbemCimtypeIllegal)
  1658. //
  1659. // RETURN VALUES:
  1660. // A best match CIM type
  1661. //
  1662. //***************************************************************************
  1663. WbemCimtypeEnum GetCIMType (
  1664. VARIANT & var,
  1665. CIMTYPE iCimType,
  1666. bool bIsArray,
  1667. long lLBound,
  1668. long lUBound
  1669. )
  1670. {
  1671. WbemCimtypeEnum cimType = wbemCimtypeSint32;
  1672. switch (V_VT(&var) & ~VT_ARRAY)
  1673. {
  1674. /*
  1675. * Note that prior to this function being called
  1676. * we will have transformed VT_DISPATCH's to
  1677. * VT_UNKNOWN's.
  1678. */
  1679. case VT_UNKNOWN:
  1680. {
  1681. /*
  1682. * Could be an embedded object or just a regular
  1683. * IUnknown.
  1684. */
  1685. if (bIsArray)
  1686. {
  1687. long ix = 0;
  1688. bool bCanBeServingSuggestion = true;
  1689. for(ix = lLBound; ix <= lUBound && bCanBeServingSuggestion; ix++)
  1690. {
  1691. CComPtr<IUnknown> pIUnknown;
  1692. if (SUCCEEDED(SafeArrayGetElement(var.parray,&ix,&pIUnknown)))
  1693. {
  1694. CComQIPtr<IWbemClassObject> pIWbemClassObject (pIUnknown);
  1695. if (!pIWbemClassObject)
  1696. bCanBeServingSuggestion = false;
  1697. }
  1698. else
  1699. bCanBeServingSuggestion = false;
  1700. }
  1701. if (bCanBeServingSuggestion)
  1702. cimType = wbemCimtypeObject;
  1703. }
  1704. else
  1705. {
  1706. CComQIPtr<IWbemClassObject> pIWbemClassObject (var.punkVal);
  1707. if (pIWbemClassObject)
  1708. cimType = wbemCimtypeObject;
  1709. }
  1710. }
  1711. break;
  1712. case VT_EMPTY:
  1713. case VT_ERROR:
  1714. case VT_NULL:
  1715. if (CIM_ILLEGAL == iCimType)
  1716. cimType = wbemCimtypeSint32; // Pick something
  1717. else
  1718. cimType = (WbemCimtypeEnum) iCimType; // Anything goes
  1719. break;
  1720. case VT_VARIANT:
  1721. case VT_DISPATCH:
  1722. // Can't handle these with CIM types
  1723. break;
  1724. case VT_I2:
  1725. {
  1726. cimType = wbemCimtypeSint16; // default
  1727. switch (iCimType)
  1728. {
  1729. case wbemCimtypeSint32:
  1730. case wbemCimtypeUint32:
  1731. case wbemCimtypeSint64:
  1732. case wbemCimtypeUint64:
  1733. case wbemCimtypeSint16:
  1734. case wbemCimtypeUint16:
  1735. case wbemCimtypeChar16:
  1736. cimType = (WbemCimtypeEnum) iCimType;
  1737. break;
  1738. // May be able to use a smaller type but
  1739. // only if the value "fits"
  1740. case wbemCimtypeSint8:
  1741. if (bIsArray)
  1742. {
  1743. long ix = 0;
  1744. bool bCanBeServingSuggestion = true;
  1745. for(ix = lLBound; ix <= lUBound && bCanBeServingSuggestion; ix++)
  1746. {
  1747. short iVal = 0;
  1748. if (SUCCEEDED(SafeArrayGetElement(var.parray,&ix,&iVal)))
  1749. {
  1750. if ((iVal > 0x7F) || (-iVal > 0x80))
  1751. bCanBeServingSuggestion = false;
  1752. }
  1753. else
  1754. bCanBeServingSuggestion = false;
  1755. }
  1756. if (bCanBeServingSuggestion)
  1757. cimType = (WbemCimtypeEnum) iCimType;
  1758. }
  1759. else
  1760. {
  1761. if ((var.iVal <= 0x7F) && (-var.iVal <= 0x80))
  1762. cimType = (WbemCimtypeEnum) iCimType;
  1763. }
  1764. break;
  1765. case wbemCimtypeUint8:
  1766. if (bIsArray)
  1767. {
  1768. long ix = 0;
  1769. bool bCanBeServingSuggestion = true;
  1770. for(ix = lLBound; ix <= lUBound && bCanBeServingSuggestion; ix++)
  1771. {
  1772. short iVal = 0;
  1773. if (SUCCEEDED(SafeArrayGetElement(var.parray,&ix,&iVal)))
  1774. {
  1775. if ((iVal > 0xFF) || (iVal < 0))
  1776. bCanBeServingSuggestion = false;
  1777. }
  1778. else
  1779. bCanBeServingSuggestion = false;
  1780. }
  1781. if (bCanBeServingSuggestion)
  1782. cimType = (WbemCimtypeEnum) iCimType;
  1783. }
  1784. else
  1785. {
  1786. if ((var.iVal <= 0xFF) && (var.iVal >= 0))
  1787. cimType = (WbemCimtypeEnum) iCimType;
  1788. }
  1789. break;
  1790. }
  1791. }
  1792. break;
  1793. case VT_I4:
  1794. {
  1795. cimType = wbemCimtypeSint32; // default
  1796. switch (iCimType)
  1797. {
  1798. case wbemCimtypeSint32:
  1799. case wbemCimtypeUint32:
  1800. case wbemCimtypeSint64:
  1801. case wbemCimtypeUint64:
  1802. cimType = (WbemCimtypeEnum) iCimType;
  1803. break;
  1804. // May be able to use a smaller type but
  1805. // only if the value "fits"
  1806. case wbemCimtypeSint16:
  1807. if (bIsArray)
  1808. {
  1809. long ix = 0;
  1810. bool bCanBeServingSuggestion = true;
  1811. for(ix = lLBound; ix <= lUBound && bCanBeServingSuggestion; ix++)
  1812. {
  1813. long iVal = 0;
  1814. if (SUCCEEDED(SafeArrayGetElement(var.parray,&ix,&iVal)))
  1815. {
  1816. if ((iVal > 0x7FFF) || (-iVal > 0x8000))
  1817. bCanBeServingSuggestion = false;
  1818. }
  1819. else
  1820. bCanBeServingSuggestion = false;
  1821. }
  1822. if (bCanBeServingSuggestion)
  1823. cimType = (WbemCimtypeEnum) iCimType;
  1824. }
  1825. else
  1826. {
  1827. if ((var.lVal <= 0x7FFF) && (-var.lVal <= 0x8000))
  1828. cimType = (WbemCimtypeEnum) iCimType;
  1829. }
  1830. break;
  1831. case wbemCimtypeUint16:
  1832. case wbemCimtypeChar16:
  1833. if (bIsArray)
  1834. {
  1835. long ix = 0;
  1836. bool bCanBeServingSuggestion = true;
  1837. for(ix = lLBound; ix <= lUBound && bCanBeServingSuggestion; ix++)
  1838. {
  1839. long iVal = 0;
  1840. if (SUCCEEDED(SafeArrayGetElement(var.parray,&ix,&iVal)))
  1841. {
  1842. if ((iVal > 0xFFFF) || (iVal < 0))
  1843. bCanBeServingSuggestion = false;
  1844. }
  1845. else
  1846. bCanBeServingSuggestion = false;
  1847. }
  1848. if (bCanBeServingSuggestion)
  1849. cimType = (WbemCimtypeEnum) iCimType;
  1850. }
  1851. else
  1852. {
  1853. if ((var.lVal <= 0xFFFF) && (var.lVal >= 0))
  1854. cimType = (WbemCimtypeEnum) iCimType;
  1855. }
  1856. break;
  1857. case wbemCimtypeSint8:
  1858. if (bIsArray)
  1859. {
  1860. long ix = 0;
  1861. bool bCanBeServingSuggestion = true;
  1862. for(ix = lLBound; ix <= lUBound && bCanBeServingSuggestion; ix++)
  1863. {
  1864. long iVal = 0;
  1865. if (SUCCEEDED(SafeArrayGetElement(var.parray,&ix,&iVal)))
  1866. {
  1867. if ((iVal > 0x7F) || (-iVal > 0x80))
  1868. bCanBeServingSuggestion = false;
  1869. }
  1870. else
  1871. bCanBeServingSuggestion = false;
  1872. }
  1873. if (bCanBeServingSuggestion)
  1874. cimType = (WbemCimtypeEnum) iCimType;
  1875. }
  1876. else
  1877. {
  1878. if ((var.lVal <= 0x7F) && (-var.lVal <= 0x80))
  1879. cimType = (WbemCimtypeEnum) iCimType;
  1880. }
  1881. break;
  1882. case wbemCimtypeUint8:
  1883. if (bIsArray)
  1884. {
  1885. long ix = 0;
  1886. bool bCanBeServingSuggestion = true;
  1887. for(ix = lLBound; ix <= lUBound && bCanBeServingSuggestion; ix++)
  1888. {
  1889. long iVal = 0;
  1890. if (SUCCEEDED(SafeArrayGetElement(var.parray,&ix,&iVal)))
  1891. {
  1892. if ((iVal > 0xFF) || (iVal < 0))
  1893. bCanBeServingSuggestion = false;
  1894. }
  1895. else
  1896. bCanBeServingSuggestion = false;
  1897. }
  1898. if (bCanBeServingSuggestion)
  1899. cimType = (WbemCimtypeEnum) iCimType;
  1900. }
  1901. else
  1902. {
  1903. if ((var.lVal <= 0xFF) && (var.lVal >= 0))
  1904. cimType = (WbemCimtypeEnum) iCimType;
  1905. }
  1906. break;
  1907. }
  1908. }
  1909. break;
  1910. case VT_UI1:
  1911. if ((wbemCimtypeSint16 == iCimType) ||
  1912. (wbemCimtypeUint16 == iCimType) ||
  1913. (wbemCimtypeSint8 == iCimType) ||
  1914. (wbemCimtypeUint8 == iCimType) ||
  1915. (wbemCimtypeChar16 == iCimType) ||
  1916. (wbemCimtypeSint32 == iCimType) ||
  1917. (wbemCimtypeUint32 == iCimType) ||
  1918. (wbemCimtypeSint64 == iCimType) ||
  1919. (wbemCimtypeUint64 == iCimType))
  1920. cimType = (WbemCimtypeEnum) iCimType;
  1921. else
  1922. cimType = wbemCimtypeUint8;
  1923. break;
  1924. case VT_R8:
  1925. if (wbemCimtypeReal64 == iCimType)
  1926. cimType = (WbemCimtypeEnum) iCimType;
  1927. else if (wbemCimtypeReal32 == iCimType)
  1928. {
  1929. if (bIsArray)
  1930. {
  1931. long ix = 0;
  1932. bool bCanBeServingSuggestion = true;
  1933. for(ix = lLBound; ix <= lUBound && bCanBeServingSuggestion; ix++)
  1934. {
  1935. double dblVal = 0;
  1936. if (SUCCEEDED(SafeArrayGetElement(var.parray,&ix,&dblVal)))
  1937. {
  1938. if (dblVal == (float)dblVal)
  1939. bCanBeServingSuggestion = false;
  1940. }
  1941. else
  1942. bCanBeServingSuggestion = false;
  1943. }
  1944. if (bCanBeServingSuggestion)
  1945. cimType = (WbemCimtypeEnum) iCimType;
  1946. }
  1947. else
  1948. {
  1949. if (var.dblVal == (float)(var.dblVal))
  1950. cimType = (WbemCimtypeEnum) iCimType;
  1951. }
  1952. }
  1953. else
  1954. cimType = wbemCimtypeReal64;
  1955. break;
  1956. case VT_R4:
  1957. if ((wbemCimtypeReal32 == iCimType) ||
  1958. (wbemCimtypeReal64 == iCimType))
  1959. cimType = (WbemCimtypeEnum) iCimType;
  1960. else
  1961. cimType = wbemCimtypeReal32;
  1962. break;
  1963. case VT_BOOL:
  1964. cimType = wbemCimtypeBoolean;
  1965. break;
  1966. case VT_CY:
  1967. case VT_DATE:
  1968. cimType = wbemCimtypeString; // Only sensible choice
  1969. break;
  1970. case VT_BSTR:
  1971. {
  1972. cimType = wbemCimtypeString; // Unless we get a tighter fit
  1973. if ((wbemCimtypeString == iCimType) ||
  1974. (wbemCimtypeDatetime == iCimType) ||
  1975. (wbemCimtypeReference == iCimType) ||
  1976. (wbemCimtypeUint64 == iCimType) ||
  1977. (wbemCimtypeSint64 == iCimType))
  1978. {
  1979. if (bIsArray)
  1980. {
  1981. long ix = 0;
  1982. bool bCanBeServingSuggestion = true;
  1983. for(ix = lLBound; ix <= lUBound && bCanBeServingSuggestion; ix++)
  1984. {
  1985. BSTR bsValue = NULL;
  1986. if (SUCCEEDED(SafeArrayGetElement(var.parray,&ix,&bsValue)))
  1987. bCanBeServingSuggestion = CanCoerceString (bsValue, (WbemCimtypeEnum) iCimType);
  1988. else
  1989. bCanBeServingSuggestion = false;
  1990. SysFreeString(bsValue);
  1991. }
  1992. if (bCanBeServingSuggestion)
  1993. cimType = (WbemCimtypeEnum) iCimType;
  1994. }
  1995. else
  1996. {
  1997. if (CanCoerceString (var.bstrVal, (WbemCimtypeEnum) iCimType))
  1998. cimType = (WbemCimtypeEnum) iCimType;
  1999. }
  2000. }
  2001. }
  2002. break;
  2003. }
  2004. return cimType;
  2005. }
  2006. //***************************************************************************
  2007. //
  2008. // BOOL ReadI64
  2009. //
  2010. // DESCRIPTION:
  2011. //
  2012. // Reads a signed 64-bit value from a string
  2013. //
  2014. // PARAMETERS:
  2015. //
  2016. // LPCWSTR wsz String to read from
  2017. // __int64& i64 Destination for the value
  2018. //
  2019. //***************************************************************************
  2020. bool ReadI64(LPCWSTR wsz, __int64& ri64)
  2021. {
  2022. __int64 i64 = 0;
  2023. const WCHAR* pwc = wsz;
  2024. int nSign = 1;
  2025. if(*pwc == L'-')
  2026. {
  2027. nSign = -1;
  2028. pwc++;
  2029. }
  2030. while(i64 >= 0 && i64 < 0x7FFFFFFFFFFFFFFF / 8 &&
  2031. *pwc >= L'0' && *pwc <= L'9')
  2032. {
  2033. i64 = i64 * 10 + (*pwc - L'0');
  2034. pwc++;
  2035. }
  2036. if(*pwc)
  2037. return false;
  2038. if(i64 < 0)
  2039. {
  2040. // Special case --- largest negative number
  2041. // ========================================
  2042. if(nSign == -1 && i64 == (__int64)0x8000000000000000)
  2043. {
  2044. ri64 = i64;
  2045. return true;
  2046. }
  2047. return false;
  2048. }
  2049. ri64 = i64 * nSign;
  2050. return true;
  2051. }
  2052. //***************************************************************************
  2053. //
  2054. // BOOL ReadUI64
  2055. //
  2056. // DESCRIPTION:
  2057. //
  2058. // Reads an unsigned 64-bit value from a string
  2059. //
  2060. // PARAMETERS:
  2061. //
  2062. // LPCWSTR wsz String to read from
  2063. // unsigned __int64& i64 Destination for the value
  2064. //
  2065. //***************************************************************************
  2066. bool ReadUI64(LPCWSTR wsz, unsigned __int64& rui64)
  2067. {
  2068. unsigned __int64 ui64 = 0;
  2069. const WCHAR* pwc = wsz;
  2070. while(ui64 < 0xFFFFFFFFFFFFFFFF / 8 && *pwc >= L'0' && *pwc <= L'9')
  2071. {
  2072. unsigned __int64 ui64old = ui64;
  2073. ui64 = ui64 * 10 + (*pwc - L'0');
  2074. if(ui64 < ui64old)
  2075. return false;
  2076. pwc++;
  2077. }
  2078. if(*pwc)
  2079. {
  2080. return false;
  2081. }
  2082. rui64 = ui64;
  2083. return true;
  2084. }
  2085. HRESULT BuildStringArray (
  2086. SAFEARRAY *pArray,
  2087. VARIANT & var
  2088. )
  2089. {
  2090. HRESULT hr = WBEM_E_FAILED;
  2091. SAFEARRAYBOUND rgsabound;
  2092. rgsabound.lLbound = 0;
  2093. long lBound = 0, uBound = -1;
  2094. if (pArray)
  2095. {
  2096. SafeArrayGetUBound (pArray, 1, &uBound);
  2097. SafeArrayGetLBound (pArray, 1, &lBound);
  2098. }
  2099. rgsabound.cElements = uBound + 1 - lBound;
  2100. SAFEARRAY *pNewArray = SafeArrayCreate (VT_VARIANT, 1, &rgsabound);
  2101. if (pNewArray)
  2102. {
  2103. BSTR bstrName = NULL;
  2104. VARIANT nameVar;
  2105. VariantInit (&nameVar);
  2106. bool ok = true;
  2107. /*
  2108. * If the source array is not empty, copy it over to the
  2109. * new array. Wrap each member in a Variant, and ensure indexing
  2110. * begins at 0.
  2111. */
  2112. if (0 < rgsabound.cElements)
  2113. {
  2114. for (long i = 0; (i <= (rgsabound.cElements - 1)) && ok; i++)
  2115. {
  2116. long j = lBound + i;
  2117. if (SUCCEEDED(SafeArrayGetElement (pArray, &j, &bstrName)))
  2118. {
  2119. BSTR copy = SysAllocString (bstrName);
  2120. if (copy)
  2121. {
  2122. nameVar.vt = VT_BSTR;
  2123. nameVar.bstrVal = copy;
  2124. if (FAILED(SafeArrayPutElement (pNewArray, &i, &nameVar)))
  2125. {
  2126. ok = false;
  2127. hr = WBEM_E_OUT_OF_MEMORY;
  2128. }
  2129. SysFreeString (bstrName);
  2130. VariantClear (&nameVar);
  2131. }
  2132. else
  2133. {
  2134. ok = false;
  2135. hr = WBEM_E_OUT_OF_MEMORY;
  2136. }
  2137. }
  2138. else
  2139. ok = false;
  2140. }
  2141. }
  2142. if (ok)
  2143. {
  2144. // Now plug this array into the VARIANT
  2145. var.vt = VT_ARRAY | VT_VARIANT;
  2146. var.parray = pNewArray;
  2147. hr = S_OK;
  2148. }
  2149. else
  2150. {
  2151. if (pNewArray)
  2152. SafeArrayDestroy (pNewArray);
  2153. }
  2154. }
  2155. else
  2156. hr = WBEM_E_OUT_OF_MEMORY;
  2157. return hr;
  2158. }
  2159. HRESULT SetFromStringArray (
  2160. SAFEARRAY **ppArray,
  2161. VARIANT *pVar
  2162. )
  2163. {
  2164. HRESULT hr = WBEM_E_FAILED;
  2165. if ((NULL == pVar) || (VT_EMPTY == V_VT(pVar)) ||
  2166. (VT_NULL == V_VT(pVar)))
  2167. {
  2168. if (*ppArray)
  2169. {
  2170. SafeArrayDestroy (*ppArray);
  2171. *ppArray = NULL;
  2172. }
  2173. hr = WBEM_S_NO_ERROR;
  2174. }
  2175. else if (((VT_ARRAY | VT_VARIANT) == V_VT(pVar)) ||
  2176. ((VT_ARRAY | VT_VARIANT | VT_BYREF) == V_VT(pVar)))
  2177. {
  2178. VARIANT vTemp;
  2179. VariantInit (&vTemp);
  2180. if (S_OK == ConvertArray(&vTemp, pVar))
  2181. {
  2182. // Is it a string array?
  2183. if (V_VT(&vTemp) == (VT_ARRAY|VT_BSTR))
  2184. {
  2185. // Super - grab it out of the temporary VARIANT
  2186. if (*ppArray)
  2187. SafeArrayDestroy (*ppArray);
  2188. *ppArray = vTemp.parray;
  2189. vTemp.vt = VT_NULL;
  2190. vTemp.parray = NULL;
  2191. hr = WBEM_S_NO_ERROR;
  2192. }
  2193. }
  2194. VariantClear(&vTemp);
  2195. }
  2196. else
  2197. {
  2198. // Look for an IDispatch that needs to be mapped to an array
  2199. if ((VT_DISPATCH == V_VT(pVar))
  2200. || ((VT_DISPATCH|VT_BYREF) == V_VT(pVar)))
  2201. {
  2202. VARIANT vTemp;
  2203. VariantInit (&vTemp);
  2204. if (S_OK == ConvertDispatchToArray (&vTemp, pVar, wbemCimtypeString))
  2205. {
  2206. // Is it a string array?
  2207. if (V_VT(&vTemp) == (VT_ARRAY|VT_BSTR))
  2208. {
  2209. // Super - grab it out of the temporary VARIANT
  2210. if (*ppArray)
  2211. SafeArrayDestroy (*ppArray);
  2212. *ppArray = vTemp.parray;
  2213. vTemp.vt = VT_NULL;
  2214. vTemp.parray = NULL;
  2215. hr = WBEM_S_NO_ERROR;
  2216. }
  2217. }
  2218. VariantClear (&vTemp);
  2219. }
  2220. }
  2221. return hr;
  2222. }
  2223. //***************************************************************************
  2224. //
  2225. // bool IsNullOrEmptyVariant
  2226. //
  2227. // DESCRIPTION:
  2228. //
  2229. // Given a VARIANT, check if it is essentially null/empty or has
  2230. // more than one dimension
  2231. //
  2232. // PARAMETERS:
  2233. //
  2234. // pVar variant to check
  2235. //
  2236. // RETURNS:
  2237. // true if and only if the conversion was possible
  2238. //
  2239. //***************************************************************************
  2240. bool IsNullOrEmptyVariant (VARIANT & var)
  2241. {
  2242. bool result = false;
  2243. if ((VT_EMPTY == var.vt) || (VT_NULL == var.vt))
  2244. result = true;
  2245. else if (VT_ARRAY & var.vt)
  2246. {
  2247. // Check if array that it is not empty or NULL
  2248. if (!(var.parray))
  2249. result = true;
  2250. else
  2251. {
  2252. long lBound, uBound;
  2253. if ((1 != SafeArrayGetDim (var.parray)) ||
  2254. (
  2255. SUCCEEDED(SafeArrayGetLBound (var.parray, 1, &lBound)) &&
  2256. SUCCEEDED(SafeArrayGetUBound (var.parray, 1, &uBound)) &&
  2257. (0 == (uBound - lBound + 1))
  2258. )
  2259. )
  2260. result = true;
  2261. }
  2262. }
  2263. return result;
  2264. }
  2265. //***************************************************************************
  2266. //
  2267. // bool RemoveElementFromArray
  2268. //
  2269. // DESCRIPTION:
  2270. //
  2271. // Given a SAFEARRAY and an index, remove the element at that index
  2272. // and shift left all following elements by one.
  2273. //
  2274. // PARAMETERS:
  2275. //
  2276. // array the SAFEARRAY in qeustion
  2277. // vt Variant type of elements in array
  2278. // iIndex index of element to remove
  2279. //
  2280. // RETURNS:
  2281. // true if and only if the conversion was possible
  2282. //
  2283. //***************************************************************************
  2284. bool RemoveElementFromArray (SAFEARRAY & array, VARTYPE vt, long iIndex)
  2285. {
  2286. /*
  2287. * Note: caller must ensure that the array is within bounds and that the
  2288. *
  2289. */
  2290. bool result = false;
  2291. long lBound, uBound;
  2292. if ((1== SafeArrayGetDim (&array)) &&
  2293. SUCCEEDED(SafeArrayGetLBound (&array, 1, &lBound)) &&
  2294. SUCCEEDED(SafeArrayGetUBound (&array, 1, &uBound)) &&
  2295. (0 < (uBound - lBound + 1)) &&
  2296. (iIndex <= uBound))
  2297. {
  2298. bool ok = true;
  2299. for (long i = iIndex+1; ok && (i <= uBound); i++)
  2300. ok = ShiftLeftElement (array, vt, i);
  2301. // Finally Redim to get rid of the last element
  2302. if (ok)
  2303. {
  2304. SAFEARRAYBOUND rgsabound;
  2305. rgsabound.lLbound = lBound;
  2306. rgsabound.cElements = uBound - lBound;
  2307. result = SUCCEEDED(SafeArrayRedim (&array, &rgsabound));
  2308. }
  2309. else
  2310. result = false;
  2311. }
  2312. return result;
  2313. }
  2314. //***************************************************************************
  2315. //
  2316. // bool ShiftLeftElement
  2317. //
  2318. // DESCRIPTION:
  2319. //
  2320. // Given a SAFEARRAY and an index, remove the element at that index
  2321. // and shift left all following elements by one.
  2322. //
  2323. // PARAMETERS:
  2324. //
  2325. // array the SAFEARRAY in question
  2326. // vt Variant type of elements in array
  2327. // iIndex index of element to remove
  2328. //
  2329. // RETURNS:
  2330. // true if and only if the conversion was possible
  2331. //
  2332. //***************************************************************************
  2333. bool ShiftLeftElement (SAFEARRAY & array, VARTYPE vt, long iIndex)
  2334. {
  2335. bool result = false;
  2336. long iNewIndex = iIndex - 1;
  2337. switch (vt)
  2338. {
  2339. case VT_BSTR:
  2340. {
  2341. BSTR bstrVal;
  2342. if (SUCCEEDED(SafeArrayGetElement (&array, &iIndex, &bstrVal)))
  2343. {
  2344. result = SUCCEEDED(SafeArrayPutElement (&array, &iNewIndex, bstrVal));
  2345. SysFreeString (bstrVal);
  2346. }
  2347. }
  2348. break;
  2349. case VT_UI1:
  2350. {
  2351. unsigned char bVal;
  2352. if (SUCCEEDED(SafeArrayGetElement (&array, &iIndex, &bVal)))
  2353. result = SUCCEEDED(SafeArrayPutElement (&array, &iNewIndex, &bVal));
  2354. }
  2355. break;
  2356. case VT_I2:
  2357. {
  2358. short iVal;
  2359. if (SUCCEEDED(SafeArrayGetElement (&array, &iIndex, &iVal)))
  2360. result = SUCCEEDED(SafeArrayPutElement (&array, &iNewIndex, &iVal));
  2361. }
  2362. break;
  2363. case VT_I4:
  2364. {
  2365. long lVal;
  2366. if (SUCCEEDED(SafeArrayGetElement (&array, &iIndex, &lVal)))
  2367. result = SUCCEEDED(SafeArrayPutElement (&array, &iNewIndex, &lVal));
  2368. }
  2369. break;
  2370. case VT_R4:
  2371. {
  2372. float fltVal;
  2373. if (SUCCEEDED(SafeArrayGetElement (&array, &iIndex, &fltVal)))
  2374. result = SUCCEEDED(SafeArrayPutElement (&array, &iNewIndex, &fltVal));
  2375. }
  2376. break;
  2377. case VT_R8:
  2378. {
  2379. double dblVal;
  2380. if (SUCCEEDED(SafeArrayGetElement (&array, &iIndex, &dblVal)))
  2381. result = SUCCEEDED(SafeArrayPutElement (&array, &iNewIndex, &dblVal));
  2382. }
  2383. break;
  2384. case VT_BOOL:
  2385. {
  2386. VARIANT_BOOL boolVal;
  2387. if (SUCCEEDED(SafeArrayGetElement (&array, &iIndex, &boolVal)))
  2388. result = SUCCEEDED(SafeArrayPutElement (&array, &iNewIndex, &boolVal));
  2389. }
  2390. break;
  2391. }
  2392. return result;
  2393. }
  2394. bool ShiftElementsToRight (SAFEARRAY & array, VARTYPE vt, long iStartIndex,
  2395. long iEndIndex, long iCount)
  2396. {
  2397. bool result = true;
  2398. for (long iIndex = iEndIndex; result && (iIndex >= iStartIndex); iIndex--)
  2399. {
  2400. long iNewIndex = iIndex + iCount;
  2401. switch (vt)
  2402. {
  2403. case VT_BSTR:
  2404. {
  2405. BSTR bstrVal;
  2406. if (SUCCEEDED(SafeArrayGetElement (&array, &iIndex, &bstrVal)))
  2407. {
  2408. result = SUCCEEDED(SafeArrayPutElement (&array, &iNewIndex, bstrVal));
  2409. SysFreeString (bstrVal);
  2410. }
  2411. }
  2412. break;
  2413. case VT_UI1:
  2414. {
  2415. unsigned char bVal;
  2416. if (SUCCEEDED(SafeArrayGetElement (&array, &iIndex, &bVal)))
  2417. result = SUCCEEDED(SafeArrayPutElement (&array, &iNewIndex, &bVal));
  2418. }
  2419. break;
  2420. case VT_I2:
  2421. {
  2422. short iVal;
  2423. if (SUCCEEDED(SafeArrayGetElement (&array, &iIndex, &iVal)))
  2424. result = SUCCEEDED(SafeArrayPutElement (&array, &iNewIndex, &iVal));
  2425. }
  2426. break;
  2427. case VT_I4:
  2428. {
  2429. long lVal;
  2430. if (SUCCEEDED(SafeArrayGetElement (&array, &iIndex, &lVal)))
  2431. result = SUCCEEDED(SafeArrayPutElement (&array, &iNewIndex, &lVal));
  2432. }
  2433. break;
  2434. case VT_R4:
  2435. {
  2436. float fltVal;
  2437. if (SUCCEEDED(SafeArrayGetElement (&array, &iIndex, &fltVal)))
  2438. result = SUCCEEDED(SafeArrayPutElement (&array, &iNewIndex, &fltVal));
  2439. }
  2440. break;
  2441. case VT_R8:
  2442. {
  2443. double dblVal;
  2444. if (SUCCEEDED(SafeArrayGetElement (&array, &iIndex, &dblVal)))
  2445. result = SUCCEEDED(SafeArrayPutElement (&array, &iNewIndex, &dblVal));
  2446. }
  2447. break;
  2448. case VT_BOOL:
  2449. {
  2450. VARIANT_BOOL boolVal;
  2451. if (SUCCEEDED(SafeArrayGetElement (&array, &iIndex, &boolVal)))
  2452. result = SUCCEEDED(SafeArrayPutElement (&array, &iNewIndex, &boolVal));
  2453. }
  2454. break;
  2455. case VT_DISPATCH:
  2456. {
  2457. IDispatch *pdispVal = NULL;
  2458. if (SUCCEEDED(SafeArrayGetElement (&array, &iIndex, &pdispVal)))
  2459. {
  2460. result = SUCCEEDED(SafeArrayPutElement (&array, &iNewIndex, pdispVal));
  2461. if (pdispVal)
  2462. pdispVal->Release ();
  2463. }
  2464. }
  2465. break;
  2466. case VT_UNKNOWN:
  2467. {
  2468. IUnknown *punkVal = NULL;
  2469. if (SUCCEEDED(SafeArrayGetElement (&array, &iIndex, &punkVal)))
  2470. {
  2471. result = SUCCEEDED(SafeArrayPutElement (&array, &iNewIndex, punkVal));
  2472. if (punkVal)
  2473. punkVal->Release ();
  2474. }
  2475. }
  2476. break;
  2477. }
  2478. }
  2479. return result;
  2480. }
  2481. //***************************************************************************
  2482. //
  2483. // bool MatchBSTR
  2484. //
  2485. // DESCRIPTION:
  2486. //
  2487. // Given a VARIANT and a BSTR, find out whether the BSTR matches the
  2488. // VARIANT value (either the complete value or a member thereof).
  2489. //
  2490. // PARAMETERS:
  2491. //
  2492. // var the VARIANT in question
  2493. // bstrVal the BSTR in question
  2494. //
  2495. // RETURNS:
  2496. // true if and only if the match was made
  2497. //
  2498. //***************************************************************************
  2499. bool MatchBSTR (VARIANT & var, BSTR & bstrVal)
  2500. {
  2501. bool result = false;
  2502. // Coerce into the underlying type of the variant
  2503. VARIANT srcVar, dstVar;
  2504. srcVar.vt = VT_BSTR;
  2505. srcVar.bstrVal = SysAllocString (bstrVal);
  2506. VariantInit (&dstVar);
  2507. if (SUCCEEDED (VariantChangeType (&dstVar, &srcVar, 0, var.vt & ~VT_ARRAY)))
  2508. {
  2509. result = MatchValue (var, dstVar);
  2510. VariantClear (&dstVar);
  2511. }
  2512. VariantClear (&srcVar);
  2513. return result;
  2514. }
  2515. //***************************************************************************
  2516. //
  2517. // bool MatchUI1
  2518. //
  2519. // DESCRIPTION:
  2520. //
  2521. // Given a VARIANT and a UI1, find out whether the UI1 matches the
  2522. // VARIANT value (either the complete value or a member thereof).
  2523. //
  2524. // PARAMETERS:
  2525. //
  2526. // var the VARIANT in question
  2527. // bstrVal the BSTR in question
  2528. //
  2529. // RETURNS:
  2530. // true if and only if the match was made
  2531. //
  2532. //***************************************************************************
  2533. bool MatchUI1 (VARIANT & var, unsigned char bVal)
  2534. {
  2535. bool result = false;
  2536. // Coerce into the underlying type of the variant
  2537. VARIANT srcVar, dstVar;
  2538. srcVar.vt = VT_UI1;
  2539. srcVar.bVal = bVal;
  2540. VariantInit (&dstVar);
  2541. if (SUCCEEDED (VariantChangeType (&dstVar, &srcVar, 0, var.vt & ~VT_ARRAY)))
  2542. {
  2543. result = MatchValue (var, dstVar);
  2544. VariantClear (&dstVar);
  2545. }
  2546. return result;
  2547. }
  2548. bool MatchBool (VARIANT & var, VARIANT_BOOL boolVal)
  2549. {
  2550. bool result = false;
  2551. // Coerce into the underlying type of the variant
  2552. VARIANT srcVar, dstVar;
  2553. srcVar.vt = VT_BOOL;
  2554. srcVar.boolVal = boolVal;
  2555. VariantInit (&dstVar);
  2556. if (SUCCEEDED (VariantChangeType (&dstVar, &srcVar, 0, var.vt & ~VT_ARRAY)))
  2557. {
  2558. result = MatchValue (var, dstVar);
  2559. VariantClear (&dstVar);
  2560. }
  2561. return result;
  2562. }
  2563. bool MatchI2 (VARIANT & var, short iVal)
  2564. {
  2565. bool result = false;
  2566. // Coerce into the underlying type of the variant
  2567. VARIANT srcVar, dstVar;
  2568. srcVar.vt = VT_I2;
  2569. srcVar.iVal = iVal;
  2570. VariantInit (&dstVar);
  2571. if (SUCCEEDED (VariantChangeType (&dstVar, &srcVar, 0, var.vt & ~VT_ARRAY)))
  2572. {
  2573. result = MatchValue (var, dstVar);
  2574. VariantClear (&dstVar);
  2575. }
  2576. return result;
  2577. }
  2578. bool MatchI4 (VARIANT & var, long lVal)
  2579. {
  2580. bool result = false;
  2581. // Coerce into the underlying type of the variant
  2582. VARIANT srcVar, dstVar;
  2583. srcVar.vt = VT_I4;
  2584. srcVar.lVal = lVal;
  2585. VariantInit (&dstVar);
  2586. if (SUCCEEDED (VariantChangeType (&dstVar, &srcVar, 0, var.vt & ~VT_ARRAY)))
  2587. {
  2588. result = MatchValue (var, dstVar);
  2589. VariantClear (&dstVar);
  2590. }
  2591. return result;
  2592. }
  2593. bool MatchR4 (VARIANT & var, float fltVal)
  2594. {
  2595. bool result = false;
  2596. // Coerce into the underlying type of the variant
  2597. VARIANT srcVar, dstVar;
  2598. srcVar.vt = VT_R4;
  2599. srcVar.fltVal = fltVal;
  2600. VariantInit (&dstVar);
  2601. if (SUCCEEDED (VariantChangeType (&dstVar, &srcVar, 0, var.vt & ~VT_ARRAY)))
  2602. {
  2603. result = MatchValue (var, dstVar);
  2604. VariantClear (&dstVar);
  2605. }
  2606. return result;
  2607. }
  2608. bool MatchR8 (VARIANT & var, double dblVal)
  2609. {
  2610. bool result = false;
  2611. // Coerce into the underlying type of the variant
  2612. VARIANT srcVar, dstVar;
  2613. srcVar.vt = VT_R8;
  2614. srcVar.dblVal = dblVal;
  2615. VariantInit (&dstVar);
  2616. if (SUCCEEDED (VariantChangeType (&dstVar, &srcVar, 0, var.vt & ~VT_ARRAY)))
  2617. {
  2618. result = MatchValue (var, dstVar);
  2619. VariantClear (&dstVar);
  2620. }
  2621. return result;
  2622. }
  2623. //***************************************************************************
  2624. //
  2625. // bool MatchValue
  2626. //
  2627. // DESCRIPTION:
  2628. //
  2629. // Given a VARIANT (which may or may not be an array) and a second VARIANT
  2630. // (which is not an array) determine whether the second value matches the
  2631. // first or an element of the first.
  2632. //
  2633. // ASSUMPTIONS
  2634. //
  2635. // 1. The two VARIANTS have the same underlying type
  2636. // 2. The second VARIANT cannot be an array
  2637. //
  2638. // PARAMETERS:
  2639. //
  2640. // var the VARIANT in question
  2641. // bstrVal the BSTR in question
  2642. //
  2643. // RETURNS:
  2644. // true if and only if the match was made
  2645. //
  2646. //***************************************************************************
  2647. bool MatchValue (VARIANT &var1, VARIANT &var2)
  2648. {
  2649. bool result = false;
  2650. bool bIsArray = (var1.vt & VT_ARRAY) ? true : false;
  2651. if (bIsArray)
  2652. {
  2653. long lBound, uBound;
  2654. if (var1.parray && (1== SafeArrayGetDim (var1.parray)) &&
  2655. SUCCEEDED(SafeArrayGetLBound (var1.parray, 1, &lBound)) &&
  2656. SUCCEEDED(SafeArrayGetUBound (var1.parray, 1, &uBound)) &&
  2657. (0 < (uBound - lBound + 1)))
  2658. {
  2659. // Break out on first match
  2660. for (long i = lBound; !result && (i <= uBound); i++)
  2661. {
  2662. switch (var1.vt & ~VT_ARRAY)
  2663. {
  2664. case VT_BSTR:
  2665. {
  2666. BSTR bstrVal = NULL;
  2667. if (SUCCEEDED(SafeArrayGetElement (var1.parray, &i, &bstrVal)))
  2668. {
  2669. result = (0 == wcscmp (bstrVal, var2.bstrVal));
  2670. SysFreeString (bstrVal);
  2671. }
  2672. }
  2673. break;
  2674. case VT_UI1:
  2675. {
  2676. unsigned char bVal;
  2677. if (SUCCEEDED(SafeArrayGetElement (var1.parray, &i, &bVal)))
  2678. result = (bVal == var2.bVal);
  2679. }
  2680. break;
  2681. case VT_I2:
  2682. {
  2683. short iVal;
  2684. if (SUCCEEDED(SafeArrayGetElement (var1.parray, &i, &iVal)))
  2685. result = (iVal == var2.iVal);
  2686. }
  2687. break;
  2688. case VT_I4:
  2689. {
  2690. long lVal;
  2691. if (SUCCEEDED(SafeArrayGetElement (var1.parray, &i, &lVal)))
  2692. result = (lVal == var2.lVal);
  2693. }
  2694. break;
  2695. case VT_R4:
  2696. {
  2697. float fltVal;
  2698. if (SUCCEEDED(SafeArrayGetElement (var1.parray, &i, &fltVal)))
  2699. result = (fltVal == var2.fltVal);
  2700. }
  2701. break;
  2702. case VT_R8:
  2703. {
  2704. double dblVal;
  2705. if (SUCCEEDED(SafeArrayGetElement (var1.parray, &i, &dblVal)))
  2706. result = (dblVal == var2.dblVal);
  2707. }
  2708. break;
  2709. case VT_BOOL:
  2710. {
  2711. VARIANT_BOOL boolVal;
  2712. if (SUCCEEDED(SafeArrayGetElement (var1.parray, &i, &boolVal)))
  2713. result = (boolVal == var2.boolVal);
  2714. }
  2715. break;
  2716. }
  2717. }
  2718. }
  2719. }
  2720. else
  2721. {
  2722. switch (var1.vt)
  2723. {
  2724. case VT_BSTR:
  2725. result = (0 == wcscmp (var1.bstrVal, var2.bstrVal));
  2726. break;
  2727. case VT_UI1:
  2728. result = (var1.bVal == var2.bVal);
  2729. break;
  2730. case VT_I2:
  2731. result = (var1.iVal == var2.iVal);
  2732. break;
  2733. case VT_I4:
  2734. result = (var1.lVal == var2.lVal);
  2735. break;
  2736. case VT_R4:
  2737. result = (var1.fltVal == var2.fltVal);
  2738. break;
  2739. case VT_R8:
  2740. result = (var1.dblVal == var2.dblVal);
  2741. break;
  2742. case VT_BOOL:
  2743. result = (var1.boolVal == var2.boolVal);
  2744. break;
  2745. }
  2746. }
  2747. return result;
  2748. }
  2749. //***************************************************************************
  2750. //
  2751. // HRESULT WmiVariantChangeType
  2752. //
  2753. // DESCRIPTION:
  2754. //
  2755. // Given a VARIANT value and a desired CIM type, cast the value to a VARIANT
  2756. // which will be accepted when supplied to CIMOM for a property of that type.
  2757. //
  2758. // PARAMETERS:
  2759. //
  2760. // vOut the cast value
  2761. // pvIn the value to be cast
  2762. // lCimType the required CIM type
  2763. //
  2764. // RETURNS:
  2765. // S_OK if succeeded, WBEM_E_TYPE_MISMATCH if not
  2766. //
  2767. //***************************************************************************
  2768. HRESULT WmiVariantChangeType (
  2769. VARIANT & vOut,
  2770. VARIANT *pvIn,
  2771. CIMTYPE lCimType
  2772. )
  2773. {
  2774. HRESULT hr = WBEM_E_TYPE_MISMATCH;
  2775. VariantInit (&vOut);
  2776. // First we check for a NULL value, as these are easy
  2777. if ((NULL == pvIn) || VT_EMPTY == V_VT(pvIn) || VT_NULL == V_VT(pvIn) ||
  2778. ((VT_ERROR == V_VT(pvIn)) && (DISP_E_PARAMNOTFOUND == pvIn->scode)))
  2779. {
  2780. vOut.vt = VT_NULL;
  2781. hr = S_OK;
  2782. }
  2783. else
  2784. {
  2785. // The kind of variant we will need to construct
  2786. VARTYPE vtOut = CimTypeToVtType (lCimType);
  2787. // The VARTYPE we've been given
  2788. VARTYPE vtIn = V_VT(pvIn);
  2789. if (vtOut == vtIn)
  2790. {
  2791. // Life is easy
  2792. hr = VariantCopy (&vOut, pvIn);
  2793. }
  2794. else
  2795. {
  2796. // Types do not match - we have some work to to
  2797. if (CIM_FLAG_ARRAY & lCimType)
  2798. {
  2799. /*
  2800. * Check for a regular SAFEARRAY type value first; if that fails
  2801. * then look for an IDispatch-style array value.
  2802. */
  2803. if (((VT_ARRAY | VT_VARIANT) == vtIn) ||
  2804. ((VT_ARRAY | VT_VARIANT | VT_BYREF) == vtIn))
  2805. {
  2806. SAFEARRAY *parray = (VT_BYREF & vtIn) ? *(pvIn->pparray) : pvIn->parray;
  2807. hr = WmiConvertSafeArray (vOut, parray, lCimType & ~VT_ARRAY);
  2808. }
  2809. else if ((VT_DISPATCH == vtIn) || ((VT_DISPATCH|VT_BYREF) == vtIn))
  2810. {
  2811. CComPtr<IDispatch> pIDispatch =
  2812. (VT_BYREF & vtIn) ? *(pvIn->ppdispVal) : pvIn->pdispVal;
  2813. hr = WmiConvertDispatchArray (vOut, pIDispatch, lCimType & ~VT_ARRAY);
  2814. }
  2815. }
  2816. else
  2817. {
  2818. switch (lCimType)
  2819. {
  2820. case wbemCimtypeSint8:
  2821. {
  2822. /*
  2823. * These are represented by
  2824. * a VT_I2, but we need to be careful about sign
  2825. * extension from shorter types taking us "out of range".
  2826. */
  2827. if (SUCCEEDED(hr = VariantChangeType (&vOut, pvIn, 0, vtOut)))
  2828. {
  2829. // Did we get sign extended?
  2830. if ((VT_UI1 == vtIn) || (VT_BOOL == vtIn))
  2831. vOut.lVal &= 0x000000FF;
  2832. }
  2833. else
  2834. {
  2835. // If we can't change the type, try the one we're given
  2836. hr = VariantCopy (&vOut, pvIn);
  2837. }
  2838. }
  2839. break;
  2840. case wbemCimtypeSint64:
  2841. case wbemCimtypeUint64:
  2842. {
  2843. /*
  2844. * These types are realized as VT_BSTR in CIM terms, which means
  2845. * that VariantChangeType will almost always succeed but not
  2846. * leave us with a valid numeric value. To be consistent with other
  2847. * numeric types we should round up floating/double
  2848. * values to the next largest integer (as is done by VariantChangeType
  2849. * for VT_R8 to numeric conversion).
  2850. */
  2851. if (VT_R8 == V_VT(pvIn))
  2852. {
  2853. if (SUCCEEDED(hr = VariantCopy (&vOut, pvIn)))
  2854. {
  2855. // Round it up
  2856. vOut.dblVal = ceil (vOut.dblVal);
  2857. // Convert to string
  2858. int dec = 0;
  2859. int sign = 0;
  2860. char *pDbl = _fcvt (vOut.dblVal, 0, &dec, &sign);
  2861. if (pDbl)
  2862. {
  2863. size_t len = strlen (pDbl);
  2864. /*
  2865. * Having rounded up to an integer, we really expect
  2866. * there to be no fractional component to the number
  2867. * returned by _fcvt.
  2868. */
  2869. if (dec == len)
  2870. {
  2871. /*
  2872. * Now convert to a wide string - remember the
  2873. * sign bit!
  2874. */
  2875. if (0 != sign)
  2876. len += 1;
  2877. wchar_t *pValue = new wchar_t [len + 1];
  2878. if (pValue)
  2879. {
  2880. if (0 != sign)
  2881. {
  2882. pValue [0] = L'-';
  2883. mbstowcs (pValue+1, pDbl, len);
  2884. }
  2885. else
  2886. mbstowcs (pValue, pDbl, len);
  2887. pValue [len] = NULL;
  2888. // Now set it in the variant
  2889. vOut.bstrVal = SysAllocString (pValue);
  2890. vOut.vt = VT_BSTR;
  2891. delete [] pValue;
  2892. hr = S_OK;
  2893. }
  2894. }
  2895. }
  2896. }
  2897. }
  2898. else
  2899. hr = VariantChangeType (&vOut, pvIn, 0, vtOut);
  2900. if (FAILED(hr))
  2901. {
  2902. // If we can't change the type, try the one we're given
  2903. hr = VariantCopy (&vOut, pvIn);
  2904. }
  2905. }
  2906. break;
  2907. case wbemCimtypeUint8:
  2908. case wbemCimtypeSint16:
  2909. case wbemCimtypeSint32:
  2910. case wbemCimtypeReal32:
  2911. case wbemCimtypeReal64:
  2912. case wbemCimtypeString:
  2913. case wbemCimtypeDatetime:
  2914. case wbemCimtypeBoolean:
  2915. case wbemCimtypeReference:
  2916. {
  2917. /*
  2918. * These types have a "prefect" fit to their
  2919. * corresponding Variant type.
  2920. */
  2921. if (FAILED(hr = VariantChangeType (&vOut, pvIn, 0, vtOut)))
  2922. hr = VariantCopy (&vOut, pvIn);
  2923. }
  2924. break;
  2925. case wbemCimtypeUint32:
  2926. {
  2927. if (FAILED(hr = VariantChangeType (&vOut, pvIn, 0, vtOut)))
  2928. {
  2929. /*
  2930. * Watch for the case where we have been given a VT_R8
  2931. * in lieu of a "large" unsigned 32-bit integer value.
  2932. */
  2933. if (VT_R8 == V_VT(pvIn))
  2934. {
  2935. // Is this "really" an integer?
  2936. if (floor (pvIn->dblVal) == ceil(pvIn->dblVal))
  2937. {
  2938. // Fool it by casting to a UI4 - all we need is the bit pattern
  2939. if (SUCCEEDED(hr = VarUI4FromR8 (pvIn->dblVal, (ULONG*)&vOut.lVal)))
  2940. vOut.vt = VT_I4;
  2941. }
  2942. }
  2943. }
  2944. // If no joy thus far, just copy and have done with it
  2945. if (FAILED(hr))
  2946. hr = VariantCopy (&vOut, pvIn);
  2947. }
  2948. break;
  2949. case wbemCimtypeChar16:
  2950. case wbemCimtypeUint16:
  2951. {
  2952. /*
  2953. * These types are represented by
  2954. * a VT_I4, but we need to be careful about sign
  2955. * extension taking us "out of range".
  2956. */
  2957. if (SUCCEEDED(hr = VariantChangeType (&vOut, pvIn, 0, vtOut)))
  2958. {
  2959. // Did we get sign extended from a shorter type?
  2960. if ((VT_I2 == vtIn) || (VT_UI1 == vtIn) || (VT_BOOL == vtIn))
  2961. vOut.lVal &= 0x0000FFFF;
  2962. }
  2963. else
  2964. hr = VariantCopy (&vOut, pvIn);
  2965. }
  2966. break;
  2967. case wbemCimtypeObject:
  2968. {
  2969. /*
  2970. * We're looking for an embedded object
  2971. */
  2972. if (SUCCEEDED(hr = VariantCopy (&vOut, pvIn)))
  2973. hr = MapToCIMOMObject (&vOut);
  2974. }
  2975. break;
  2976. }
  2977. }
  2978. }
  2979. }
  2980. return hr;
  2981. }
  2982. //***************************************************************************
  2983. //
  2984. // HRESULT WmiConvertSafeArray
  2985. //
  2986. // Description:
  2987. //
  2988. // This function is applied to VARIANT arrays in order to check for certain
  2989. // restrictions imposed by CIMOM (e.g. they must be homogeneous) or perform
  2990. // conversions (certain VARIANT types have to be mapped to acceptable CIMOM
  2991. // types).
  2992. //
  2993. // Return Value:
  2994. // HRESULT S_OK if successful
  2995. //***************************************************************************
  2996. HRESULT WmiConvertSafeArray(VARIANT &vOut, SAFEARRAY *parray, CIMTYPE lCimType)
  2997. {
  2998. HRESULT hr = WBEM_E_FAILED;
  2999. VARTYPE vtPut; // The underlying type of the target array
  3000. long lLower, lUpper;
  3001. if (parray)
  3002. {
  3003. if (GetSafeArrayDimensions (*parray, lLower, lUpper))
  3004. {
  3005. int iNumElements = lUpper - lLower +1;
  3006. /*
  3007. * For empty arrays, it suffices to create a empty array of
  3008. * VT_VARIANT's. Otherwise we need to build what WMI is expecting.
  3009. */
  3010. vtPut = (iNumElements == 0) ? VT_VARIANT : CimTypeToVtType (lCimType);
  3011. // Now create a destination array of the required size
  3012. SAFEARRAYBOUND rgsabound[1];
  3013. rgsabound[0].lLbound = 0;
  3014. rgsabound[0].cElements = iNumElements;
  3015. SAFEARRAY * pDestArray = SafeArrayCreate(vtPut, 1, rgsabound);
  3016. if (pDestArray)
  3017. {
  3018. bool ok = true;
  3019. for(long i = lLower; (i <= lUpper) && ok; i++)
  3020. {
  3021. VARIANT var;
  3022. VariantInit(&var);
  3023. if (SUCCEEDED(SafeArrayGetElement (parray, &i, &var)))
  3024. {
  3025. // do the conversion to the acceptable type and put that
  3026. VARIANT vWMI;
  3027. VariantInit(&vWMI);
  3028. if (SUCCEEDED(hr = WmiVariantChangeType (vWMI, &var, lCimType)))
  3029. {
  3030. if(V_VT(&vWMI) == VT_BSTR || V_VT(&vWMI) == VT_UNKNOWN || V_VT(&vWMI) == VT_DISPATCH)
  3031. ok = (S_OK == SafeArrayPutElement(pDestArray, &i, (void *)vWMI.bstrVal));
  3032. else
  3033. ok = (S_OK == SafeArrayPutElement(pDestArray, &i, (void *)&vWMI.lVal));
  3034. }
  3035. VariantClear (&vWMI);
  3036. }
  3037. else
  3038. ok = false;
  3039. VariantClear(&var);
  3040. }
  3041. if (!ok)
  3042. {
  3043. SafeArrayDestroy (pDestArray);
  3044. }
  3045. else
  3046. {
  3047. vOut.vt = (VT_ARRAY | vtPut);
  3048. vOut.parray = pDestArray;
  3049. hr = S_OK;
  3050. }
  3051. }
  3052. else
  3053. hr = WBEM_E_OUT_OF_MEMORY;
  3054. }
  3055. }
  3056. return hr;
  3057. }
  3058. //***************************************************************************
  3059. //
  3060. // HRESULT WmiConvertDispatchArray
  3061. //
  3062. // DESCRIPTION:
  3063. //
  3064. // Attempt to convert from an IDispatch value to a CIM array value (property
  3065. // qualifier or context).
  3066. //
  3067. // PARAMETERS:
  3068. //
  3069. // pDest Output value
  3070. // pSrc Input value
  3071. // lCimType CIM Property type (underlying the array) - defaults to
  3072. // CIM_ILLEGAL for Qualifier & Context value mappings.
  3073. // bIsQual true iff we are mapping for a qualifier
  3074. //
  3075. // RETURN VALUES:
  3076. //
  3077. // WBEM_S_NO_ERROR success
  3078. // WBEM_E_FAILED otherwise
  3079. //
  3080. //***************************************************************************
  3081. HRESULT WmiConvertDispatchArray (
  3082. VARIANT &vOut,
  3083. CComPtr<IDispatch> & pIDispatch,
  3084. CIMTYPE lCimType
  3085. )
  3086. {
  3087. HRESULT hr = WBEM_E_FAILED; // Default error
  3088. if (pIDispatch)
  3089. {
  3090. /*
  3091. * Looking for an IDispatchEx to iterate through the properties
  3092. * of the array.
  3093. */
  3094. CComQIPtr<IDispatchEx> pIDispatchEx (pIDispatch);
  3095. if (pIDispatchEx)
  3096. {
  3097. /*
  3098. * Looks promising, but just check if this isn't one of our objects
  3099. */
  3100. CComQIPtr<ISWbemObject> pISWbemObject (pIDispatch);
  3101. if (!pISWbemObject)
  3102. {
  3103. /*
  3104. * Start by determining how many properties there are so we can create
  3105. * a suitable array.
  3106. */
  3107. long iNumElements = 0;
  3108. DISPID dispId = DISPID_STARTENUM;
  3109. while (S_OK == pIDispatchEx->GetNextDispID (fdexEnumAll, dispId, &dispId))
  3110. iNumElements++;
  3111. /*
  3112. * For empty arrays, it suffices to create a empty array of
  3113. * VT_VARIANT's. Otherwise we need to build what WMI is expecting.
  3114. */
  3115. VARTYPE vtPut = (iNumElements == 0) ? VT_VARIANT : CimTypeToVtType (lCimType);
  3116. // Create the safearray - note that it may be empty
  3117. SAFEARRAYBOUND rgsaBound;
  3118. rgsaBound.cElements = iNumElements;
  3119. rgsaBound.lLbound = 0;
  3120. SAFEARRAY *pDestArray = SafeArrayCreate (vtPut, 1, &rgsaBound);
  3121. if (pDestArray)
  3122. {
  3123. bool ok = true;
  3124. if (0 < iNumElements)
  3125. {
  3126. // Enumerate the DISPIDs on this interface
  3127. dispId = DISPID_STARTENUM;
  3128. DISPPARAMS dispParams;
  3129. dispParams.rgvarg = NULL;
  3130. dispParams.rgdispidNamedArgs = NULL;
  3131. dispParams.cArgs = 0;
  3132. dispParams.cNamedArgs = 0;
  3133. long nextExpectedIndex = 0;
  3134. HRESULT enumHr;
  3135. wchar_t *stopString = NULL;
  3136. /*
  3137. * For JScript arrays, the property names are the specified indices of the
  3138. * the array; these can be integer indices or they can be strings. We make
  3139. * the following requirements of the array indices:
  3140. *
  3141. * (1) All of the indices are non-negative integers
  3142. * (2) The indices start at 0 and are contiguous.
  3143. */
  3144. while (ok && SUCCEEDED(enumHr = pIDispatchEx->GetNextDispID (fdexEnumAll, dispId, &dispId)))
  3145. {
  3146. if (S_FALSE == enumHr)
  3147. {
  3148. // We have reached the end
  3149. break;
  3150. }
  3151. CComBSTR memberName;
  3152. if (SUCCEEDED(pIDispatchEx->GetMemberName (dispId, &memberName)))
  3153. {
  3154. // Check that property name is numeric
  3155. long i = wcstol (memberName, &stopString, 10);
  3156. if ((0 != wcslen (stopString)))
  3157. {
  3158. // Failure - cannot convert to integer
  3159. ok = false;
  3160. }
  3161. else if (i != nextExpectedIndex)
  3162. {
  3163. // Failure - non-contiguous array
  3164. ok = false;
  3165. }
  3166. else
  3167. {
  3168. nextExpectedIndex++;
  3169. // Extract the property
  3170. VARIANT var;
  3171. VariantInit (&var);
  3172. if (SUCCEEDED (pIDispatchEx->InvokeEx (dispId, 0,
  3173. DISPATCH_PROPERTYGET, &dispParams, &var, NULL, NULL)))
  3174. {
  3175. // do the conversion to the acceptable type and put that
  3176. VARIANT vWMI;
  3177. VariantInit(&vWMI);
  3178. if (SUCCEEDED(hr = WmiVariantChangeType (vWMI, &var, lCimType)))
  3179. {
  3180. if(V_VT(&vWMI) == VT_BSTR || V_VT(&vWMI) == VT_UNKNOWN || V_VT(&vWMI) == VT_DISPATCH)
  3181. ok = (S_OK == SafeArrayPutElement(pDestArray, &i, (void *)vWMI.bstrVal));
  3182. else
  3183. ok = (S_OK == SafeArrayPutElement(pDestArray, &i, (void *)&vWMI.lVal));
  3184. }
  3185. VariantClear (&vWMI);
  3186. }
  3187. else
  3188. ok = false;
  3189. }
  3190. }
  3191. else
  3192. {
  3193. // Failure - couldn't invoke method
  3194. ok = false;
  3195. }
  3196. }
  3197. }
  3198. if (ok)
  3199. {
  3200. // Now construct the new property value using our array
  3201. vOut.vt = VT_ARRAY | vtPut;
  3202. vOut.parray = pDestArray;
  3203. hr = S_OK;
  3204. }
  3205. else
  3206. SafeArrayDestroy (pDestArray);
  3207. }
  3208. else
  3209. hr = WBEM_E_OUT_OF_MEMORY;
  3210. }
  3211. }
  3212. }
  3213. return hr;
  3214. }
  3215. bool GetSafeArrayDimensions (SAFEARRAY &sArray, long &lLower, long &lUpper)
  3216. {
  3217. bool result = false;
  3218. // Must be 1-dimensional
  3219. if (1 == SafeArrayGetDim(&sArray))
  3220. {
  3221. if (SUCCEEDED(SafeArrayGetLBound(&sArray,1,&lLower)) &&
  3222. SUCCEEDED(SafeArrayGetUBound(&sArray,1,&lUpper)))
  3223. result = true;
  3224. }
  3225. return result;
  3226. }