Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3816 lines
96 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. //We need to check this is a "real" array entry with an index rather than some "dummy" entry
  1013. //for some non-array properties (which can happen with JScript arrays)
  1014. BSTR memberName = NULL;
  1015. wchar_t *stopString=NULL;
  1016. if (SUCCEEDED(pIDispatchEx->GetMemberName (dispId, &memberName)))
  1017. {
  1018. // Check that property name is numeric, only if it is we count it for the array size
  1019. long index = wcstol (memberName, &stopString, 10);
  1020. if ((0 == wcslen (stopString)))
  1021. propertyCount++;
  1022. }
  1023. }
  1024. // Create the safearray - note that it may be empty
  1025. SAFEARRAYBOUND rgsaBound;
  1026. rgsaBound.cElements = propertyCount;
  1027. rgsaBound.lLbound = 0;
  1028. SAFEARRAY *pArray = SafeArrayCreate (expectedVarType, 1, &rgsaBound);
  1029. if (0 < propertyCount)
  1030. {
  1031. // Enumerate the DISPIDs on this interface
  1032. dispId = DISPID_STARTENUM;
  1033. long nextExpectedIndex = 0;
  1034. HRESULT enumHr;
  1035. wchar_t *stopString = NULL;
  1036. /*
  1037. * For JScript arrays, the property names are the specified indices of the
  1038. * the array; these can be integer indices or they can be strings. We make
  1039. * the following requirements of the array indices:
  1040. *
  1041. * (1) All of the indices are non-negative integers
  1042. * (2) The indices start at 0 and are contiguous.
  1043. */
  1044. while (S_OK == (enumHr = pIDispatchEx->GetNextDispID (fdexEnumAll, dispId, &dispId)))
  1045. {
  1046. BSTR memberName = NULL;
  1047. if (SUCCEEDED(pIDispatchEx->GetMemberName (dispId, &memberName)))
  1048. {
  1049. // Check that property name is numeric
  1050. long index = wcstol (memberName, &stopString, 10);
  1051. if ((0 != wcslen (stopString)))
  1052. {
  1053. // Failure - cannot convert to integer
  1054. // Since JScript arrays may have additional "members" that are not real array members,
  1055. // depending on different properties that may be accessed on them, we should just
  1056. // ignore non-numeric items - instead of failing the whole thing...
  1057. SysFreeString (memberName);
  1058. memberName = NULL;
  1059. continue;
  1060. }
  1061. SysFreeString (memberName);
  1062. memberName = NULL;
  1063. if (index != nextExpectedIndex)
  1064. {
  1065. // Failure - non-contiguous array
  1066. break;
  1067. }
  1068. nextExpectedIndex++;
  1069. // Extract the property
  1070. VARIANT vPropVal;
  1071. VariantInit (&vPropVal);
  1072. HRESULT hrInvoke;
  1073. if (SUCCEEDED (hrInvoke = pIDispatchEx->InvokeEx (dispId, 0,
  1074. DISPATCH_PROPERTYGET, &dispParams, &vPropVal, NULL, NULL)))
  1075. {
  1076. HRESULT hr2 = WBEM_E_FAILED;
  1077. // Take care of embedded objects
  1078. if ((S_OK == MapToCIMOMObject (&vPropVal)) &&
  1079. (S_OK == VariantChangeType (&vPropVal, &vPropVal, 0, expectedVarType)))
  1080. {
  1081. switch (expectedVarType)
  1082. {
  1083. case VT_BSTR:
  1084. hr2 = SafeArrayPutElement (pArray, &index, (void*)vPropVal.bstrVal);
  1085. break;
  1086. case VT_UNKNOWN:
  1087. if (!bIsQual)
  1088. hr2 = SafeArrayPutElement (pArray, &index, (void*)vPropVal.punkVal);
  1089. break;
  1090. default:
  1091. hr2 = SafeArrayPutElement (pArray, &index, (void*)&vPropVal.lVal);
  1092. break;
  1093. }
  1094. }
  1095. VariantClear (&vPropVal);
  1096. if (FAILED(hr2))
  1097. break;
  1098. }
  1099. else
  1100. {
  1101. // Failure - couldn't invoke method
  1102. break;
  1103. }
  1104. } // GetMemberName SUCCEEDED
  1105. } // while loop
  1106. if (S_FALSE == enumHr)
  1107. {
  1108. // Now construct the new property value using our array
  1109. VariantInit (pvDest);
  1110. pvDest->vt = VT_ARRAY | expectedVarType;
  1111. pvDest->parray = pArray;
  1112. hr = S_OK;
  1113. }
  1114. else
  1115. {
  1116. // Something went wrong
  1117. SafeArrayDestroy (pArray);
  1118. hr = WBEM_E_INVALID_PARAMETER;
  1119. }
  1120. }
  1121. else
  1122. {
  1123. // Degenerate case of an empty array - simply create an empty
  1124. // copy with a VT_VARIANT type for properties
  1125. if (!bIsQual)
  1126. expectedVarType = VT_VARIANT;
  1127. else
  1128. {
  1129. // For qualifiers, we can hope that we've been given a candidate
  1130. // type from an existing value; otherwise we'll just have to make one up.
  1131. expectedVarType = (VT_NULL != requiredQualifierType) ? requiredQualifierType :
  1132. VT_I4;
  1133. }
  1134. VariantInit (pvDest);
  1135. pvDest->vt = VT_ARRAY | expectedVarType;
  1136. pvDest->parray = pArray;
  1137. hr = S_OK;
  1138. }
  1139. }
  1140. }
  1141. return hr;
  1142. }
  1143. //***************************************************************************
  1144. //
  1145. // void MapNulls
  1146. //
  1147. // Description:
  1148. //
  1149. // The passing of a "null" value from script (where "null" in VB/VBS and JS
  1150. // is the keyword null, and is an undefined variable in Perl) may be interpreted
  1151. // by this API as equivalent to a default value for certain method calls.
  1152. //
  1153. // This function is used to map VT_NULL dispatch parameters to the VB standard
  1154. // realization of "missing" parameters, i.e. a VT_ERROR value whose scode is
  1155. // DISP_E_PARAMNOTFOUND.
  1156. //
  1157. // Parameters:
  1158. //
  1159. // pdispparams the input dispatch parameters
  1160. //
  1161. //***************************************************************************
  1162. void MapNulls (DISPPARAMS FAR* pdispparams)
  1163. {
  1164. if (pdispparams)
  1165. {
  1166. for (unsigned int i = 0; i < pdispparams->cArgs; i++)
  1167. {
  1168. VARIANTARG &v = pdispparams->rgvarg [i];
  1169. if (VT_NULL == V_VT(&v))
  1170. {
  1171. v.vt = VT_ERROR;
  1172. v.scode = DISP_E_PARAMNOTFOUND;
  1173. }
  1174. else if (((VT_VARIANT|VT_BYREF) == V_VT(&v)) &&
  1175. (VT_NULL == V_VT(v.pvarVal)))
  1176. {
  1177. v.vt = VT_ERROR;
  1178. v.scode = DISP_E_PARAMNOTFOUND;
  1179. }
  1180. }
  1181. }
  1182. }
  1183. //***************************************************************************
  1184. //
  1185. // BSTR FormatAssociatorsQuery
  1186. //
  1187. // Description:
  1188. //
  1189. // Takes the parameters to an AssociatorsOf call and constructs a WQL
  1190. // query string from them.
  1191. //
  1192. // Returns: The constructed WQL query; this must be freed using
  1193. // SysFreeString by the caller.
  1194. //
  1195. // pdispparams the input dispatch parameters
  1196. //
  1197. //***************************************************************************
  1198. BSTR FormatAssociatorsQuery
  1199. (
  1200. BSTR strObjectPath,
  1201. BSTR strAssocClass,
  1202. BSTR strResultClass,
  1203. BSTR strResultRole,
  1204. BSTR strRole,
  1205. VARIANT_BOOL bClassesOnly,
  1206. VARIANT_BOOL bSchemaOnly,
  1207. BSTR strRequiredAssocQualifier,
  1208. BSTR strRequiredQualifier
  1209. )
  1210. {
  1211. BSTR bsQuery = NULL;
  1212. // Get the length of the string:
  1213. // associators of {SourceObject} where
  1214. // AssocClass = AssocClassName
  1215. // ClassDefsOnly
  1216. // SchemaOnly
  1217. // RequiredAssocQualifier = QualifierName
  1218. // RequiredQualifier = QualifierName
  1219. // ResultClass = ClassName
  1220. // ResultRole = PropertyName
  1221. // Role = PropertyName
  1222. long queryLength = 1; // Terminating NULL
  1223. queryLength += wcslen (WBEMS_QUERY_ASSOCOF) +
  1224. wcslen (WBEMS_QUERY_OPENBRACE) +
  1225. wcslen (WBEMS_QUERY_CLOSEBRACE) +
  1226. wcslen (strObjectPath);
  1227. bool needWhere = false;
  1228. if ((strAssocClass && (0 < wcslen (strAssocClass))) ||
  1229. (strResultClass && (0 < wcslen (strResultClass))) ||
  1230. (strResultRole && (0 < wcslen (strResultRole))) ||
  1231. (strRole && (0 < wcslen (strRole))) ||
  1232. (VARIANT_FALSE != bClassesOnly) ||
  1233. (VARIANT_FALSE != bSchemaOnly) ||
  1234. (strRequiredAssocQualifier && (0 < wcslen (strRequiredAssocQualifier))) ||
  1235. (strRequiredQualifier && (0 < wcslen (strRequiredQualifier))))
  1236. {
  1237. needWhere = true;
  1238. queryLength += wcslen (WBEMS_QUERY_WHERE);
  1239. }
  1240. if (strAssocClass && (0 < wcslen (strAssocClass)))
  1241. queryLength += wcslen (WBEMS_QUERY_ASSOCCLASS) +
  1242. wcslen (WBEMS_QUERY_EQUALS) +
  1243. wcslen (strAssocClass);
  1244. if (strResultClass && (0 < wcslen (strResultClass)))
  1245. queryLength += wcslen (WBEMS_QUERY_RESCLASS) +
  1246. wcslen (WBEMS_QUERY_EQUALS) +
  1247. wcslen (strResultClass);
  1248. if (strResultRole && (0 < wcslen (strResultRole)))
  1249. queryLength += wcslen (WBEMS_QUERY_RESROLE) +
  1250. wcslen (WBEMS_QUERY_EQUALS) +
  1251. wcslen (strResultRole);
  1252. if (strRole && (0 < wcslen (strRole)))
  1253. queryLength += wcslen (WBEMS_QUERY_ROLE) +
  1254. wcslen (WBEMS_QUERY_EQUALS) +
  1255. wcslen (strRole);
  1256. if (VARIANT_FALSE != bClassesOnly)
  1257. queryLength += wcslen (WBEMS_QUERY_CLASSDEFS);
  1258. if (VARIANT_FALSE != bSchemaOnly)
  1259. queryLength += wcslen (WBEMS_QUERY_SCHEMAONLY);
  1260. if (strRequiredAssocQualifier && (0 < wcslen (strRequiredAssocQualifier)))
  1261. queryLength += wcslen (WBEMS_QUERY_REQASSOCQ) +
  1262. wcslen (WBEMS_QUERY_EQUALS) +
  1263. wcslen (strRequiredAssocQualifier);
  1264. if (strRequiredQualifier && (0 < wcslen (strRequiredQualifier)))
  1265. queryLength += wcslen (WBEMS_QUERY_REQQUAL) +
  1266. wcslen (WBEMS_QUERY_EQUALS) +
  1267. wcslen (strRequiredQualifier);
  1268. // Allocate the string and fill it in
  1269. bsQuery = SysAllocStringLen (WBEMS_QUERY_ASSOCOF, queryLength);
  1270. wcscat (bsQuery, WBEMS_QUERY_OPENBRACE);
  1271. wcscat (bsQuery, strObjectPath);
  1272. wcscat (bsQuery, WBEMS_QUERY_CLOSEBRACE);
  1273. if (needWhere)
  1274. {
  1275. wcscat (bsQuery, WBEMS_QUERY_WHERE);
  1276. if (strAssocClass && (0 < wcslen (strAssocClass)))
  1277. {
  1278. wcscat (bsQuery, WBEMS_QUERY_ASSOCCLASS);
  1279. wcscat (bsQuery, WBEMS_QUERY_EQUALS);
  1280. wcscat (bsQuery, strAssocClass);
  1281. }
  1282. if (strResultClass && (0 < wcslen (strResultClass)))
  1283. {
  1284. wcscat (bsQuery, WBEMS_QUERY_RESCLASS);
  1285. wcscat (bsQuery, WBEMS_QUERY_EQUALS);
  1286. wcscat (bsQuery, strResultClass);
  1287. }
  1288. if (strResultRole && (0 < wcslen (strResultRole)))
  1289. {
  1290. wcscat (bsQuery, WBEMS_QUERY_RESROLE);
  1291. wcscat (bsQuery, WBEMS_QUERY_EQUALS);
  1292. wcscat (bsQuery, strResultRole);
  1293. }
  1294. if (strRole && (0 < wcslen (strRole)))
  1295. {
  1296. wcscat (bsQuery, WBEMS_QUERY_ROLE);
  1297. wcscat (bsQuery, WBEMS_QUERY_EQUALS);
  1298. wcscat (bsQuery, strRole);
  1299. }
  1300. if (VARIANT_FALSE != bClassesOnly)
  1301. wcscat (bsQuery, WBEMS_QUERY_CLASSDEFS);
  1302. if (VARIANT_FALSE != bSchemaOnly)
  1303. wcscat (bsQuery, WBEMS_QUERY_SCHEMAONLY);
  1304. if (strRequiredAssocQualifier && (0 < wcslen (strRequiredAssocQualifier)))
  1305. {
  1306. wcscat (bsQuery, WBEMS_QUERY_REQASSOCQ);
  1307. wcscat (bsQuery, WBEMS_QUERY_EQUALS);
  1308. wcscat (bsQuery, strRequiredAssocQualifier);
  1309. }
  1310. if (strRequiredQualifier && (0 < wcslen (strRequiredQualifier)))
  1311. {
  1312. wcscat (bsQuery, WBEMS_QUERY_REQQUAL);
  1313. wcscat (bsQuery, WBEMS_QUERY_EQUALS);
  1314. wcscat (bsQuery, strRequiredQualifier);
  1315. }
  1316. }
  1317. return bsQuery;
  1318. }
  1319. //***************************************************************************
  1320. //
  1321. // BSTR FormatReferencesQuery
  1322. //
  1323. // Description:
  1324. //
  1325. // Takes the parameters to an ReferencesOf call and constructs a WQL
  1326. // query string from them.
  1327. //
  1328. // Returns: The constructed WQL query; this must be freed using
  1329. // SysFreeString by the caller.
  1330. //
  1331. // pdispparams the input dispatch parameters
  1332. //
  1333. //***************************************************************************
  1334. BSTR FormatReferencesQuery
  1335. (
  1336. BSTR strObjectPath,
  1337. BSTR strResultClass,
  1338. BSTR strRole,
  1339. VARIANT_BOOL bClassesOnly,
  1340. VARIANT_BOOL bSchemaOnly,
  1341. BSTR strRequiredQualifier
  1342. )
  1343. {
  1344. BSTR bsQuery = NULL;
  1345. // Get the length of the string:
  1346. // references of {SourceObject} where
  1347. // ClassDefsOnly
  1348. // SchemaOnly
  1349. // RequiredQualifier = QualifierName
  1350. // ResultClass = ClassName
  1351. // Role = PropertyName
  1352. long queryLength = 1; // Terminating NULL
  1353. queryLength += wcslen (WBEMS_QUERY_REFOF) +
  1354. wcslen (WBEMS_QUERY_OPENBRACE) +
  1355. wcslen (WBEMS_QUERY_CLOSEBRACE) +
  1356. wcslen (strObjectPath);
  1357. bool needWhere = false;
  1358. if ((strResultClass && (0 < wcslen (strResultClass))) ||
  1359. (strRole && (0 < wcslen (strRole))) ||
  1360. (VARIANT_FALSE != bClassesOnly) ||
  1361. (VARIANT_FALSE != bSchemaOnly) ||
  1362. (strRequiredQualifier && (0 < wcslen (strRequiredQualifier))))
  1363. {
  1364. needWhere = true;
  1365. queryLength += wcslen (WBEMS_QUERY_WHERE);
  1366. }
  1367. if (strResultClass && (0 < wcslen (strResultClass)))
  1368. queryLength += wcslen (WBEMS_QUERY_RESCLASS) +
  1369. wcslen (WBEMS_QUERY_EQUALS) +
  1370. wcslen (strResultClass);
  1371. if (strRole && (0 < wcslen (strRole)))
  1372. queryLength += wcslen (WBEMS_QUERY_ROLE) +
  1373. wcslen (WBEMS_QUERY_EQUALS) +
  1374. wcslen (strRole);
  1375. if (VARIANT_FALSE != bClassesOnly)
  1376. queryLength += wcslen (WBEMS_QUERY_CLASSDEFS);
  1377. if (VARIANT_FALSE != bSchemaOnly)
  1378. queryLength += wcslen (WBEMS_QUERY_SCHEMAONLY);
  1379. if (strRequiredQualifier && (0 < wcslen (strRequiredQualifier)))
  1380. queryLength += wcslen (WBEMS_QUERY_REQQUAL) +
  1381. wcslen (WBEMS_QUERY_EQUALS) +
  1382. wcslen (strRequiredQualifier);
  1383. // Allocate the string and fill it in
  1384. bsQuery = SysAllocStringLen (WBEMS_QUERY_REFOF, queryLength);
  1385. wcscat (bsQuery, WBEMS_QUERY_OPENBRACE);
  1386. wcscat (bsQuery, strObjectPath);
  1387. wcscat (bsQuery, WBEMS_QUERY_CLOSEBRACE);
  1388. if (needWhere)
  1389. {
  1390. wcscat (bsQuery, WBEMS_QUERY_WHERE);
  1391. if (strResultClass && (0 < wcslen (strResultClass)))
  1392. {
  1393. wcscat (bsQuery, WBEMS_QUERY_RESCLASS);
  1394. wcscat (bsQuery, WBEMS_QUERY_EQUALS);
  1395. wcscat (bsQuery, strResultClass);
  1396. }
  1397. if (strRole && (0 < wcslen (strRole)))
  1398. {
  1399. wcscat (bsQuery, WBEMS_QUERY_ROLE);
  1400. wcscat (bsQuery, WBEMS_QUERY_EQUALS);
  1401. wcscat (bsQuery, strRole);
  1402. }
  1403. if (VARIANT_FALSE != bClassesOnly)
  1404. wcscat (bsQuery, WBEMS_QUERY_CLASSDEFS);
  1405. if (VARIANT_FALSE != bSchemaOnly)
  1406. wcscat (bsQuery, WBEMS_QUERY_SCHEMAONLY);
  1407. if (strRequiredQualifier && (0 < wcslen (strRequiredQualifier)))
  1408. {
  1409. wcscat (bsQuery, WBEMS_QUERY_REQQUAL);
  1410. wcscat (bsQuery, WBEMS_QUERY_EQUALS);
  1411. wcscat (bsQuery, strRequiredQualifier);
  1412. }
  1413. }
  1414. return bsQuery;
  1415. }
  1416. //***************************************************************************
  1417. //
  1418. // BSTR FormatMultiQuery
  1419. //
  1420. // Description:
  1421. //
  1422. // Takes an array of class names and formats a multi query
  1423. //
  1424. // Returns: The constructed WQL query; this must be freed using
  1425. // SysFreeString by the caller.
  1426. //
  1427. // classArray SAFEARRAY of class names
  1428. // iNumElements length of array
  1429. //
  1430. //***************************************************************************
  1431. BSTR FormatMultiQuery (
  1432. SAFEARRAY & classArray,
  1433. long iNumElements
  1434. )
  1435. {
  1436. BSTR bsQuery = NULL;
  1437. long queryLength = 1; // Terminating NULL
  1438. queryLength += (iNumElements * wcslen (WBEMS_QUERY_SELECT)) +
  1439. ((iNumElements - 1) * wcslen (WBEMS_QUERY_GO));
  1440. // Work out the string lengths
  1441. HRESULT hr = S_OK;
  1442. for (long i = 0; i < iNumElements && hr == S_OK; i++)
  1443. {
  1444. BSTR bsName = NULL;
  1445. if (SUCCEEDED(hr = SafeArrayGetElement(&classArray, &i, &bsName)))
  1446. {
  1447. queryLength += wcslen (bsName);
  1448. SysFreeString (bsName);
  1449. }
  1450. }
  1451. if (SUCCEEDED(hr))
  1452. {
  1453. // Allocate the string and fill it in
  1454. bsQuery = SysAllocStringLen (WBEMS_QUERY_SELECT, queryLength);
  1455. for (long i = 0; i < iNumElements && hr == S_OK; i++)
  1456. {
  1457. BSTR bsName = NULL;
  1458. if (SUCCEEDED(hr = SafeArrayGetElement(&classArray, &i, &bsName)))
  1459. {
  1460. if (i > 0)
  1461. wcscat (bsQuery, WBEMS_QUERY_SELECT);
  1462. wcscat (bsQuery, bsName);
  1463. SysFreeString (bsName);
  1464. if (i < iNumElements - 1)
  1465. wcscat (bsQuery, WBEMS_QUERY_GO);
  1466. }
  1467. }
  1468. }
  1469. return bsQuery;
  1470. }
  1471. //***************************************************************************
  1472. //
  1473. // EnsureGlobalsInitialized
  1474. //
  1475. // DESCRIPTION:
  1476. //
  1477. // Checks whether the g_pErrorCache global pointer is correctly initialized
  1478. // and, if not, assigns it appropriately.
  1479. //
  1480. //***************************************************************************
  1481. void EnsureGlobalsInitialized ()
  1482. {
  1483. // Initialize security
  1484. CSWbemSecurity::Initialize ();
  1485. EnterCriticalSection (&g_csErrorCache);
  1486. // Initlialize the error cache if proof be need be
  1487. if ( ! g_pErrorCache )
  1488. g_pErrorCache = new CWbemErrorCache ();
  1489. LeaveCriticalSection (&g_csErrorCache);
  1490. }
  1491. #ifdef _RDEBUG
  1492. #undef _RPrint
  1493. void _RRPrint(int line, const char *file, const char *func,
  1494. const char *str, long code, const char *str2)
  1495. {
  1496. FILE *fp = fopen("c:/out.txt", "a");
  1497. fprintf (fp, "%s %s(%d): %s - %s %ld(0x%lx)\n", file, func, line, str, str2, code, code);
  1498. fclose(fp);
  1499. }
  1500. #endif
  1501. //***************************************************************************
  1502. //
  1503. // CanCoerceString
  1504. //
  1505. // DESCRIPTION:
  1506. //
  1507. // Attempts to determine whether the supplied BSTR value can be cast
  1508. // more tightly to the given CIM type.
  1509. //
  1510. // PARAMETERS:
  1511. // pVal the variant in question
  1512. // cimType the casting CIM type
  1513. //
  1514. // RETURN VALUES:
  1515. // TRUE iff the cast is OK.
  1516. //
  1517. //***************************************************************************
  1518. bool CanCoerceString (
  1519. const BSTR & bsValue,
  1520. WbemCimtypeEnum cimType
  1521. )
  1522. {
  1523. bool result = false;
  1524. switch (cimType)
  1525. {
  1526. case wbemCimtypeReference:
  1527. {
  1528. CSWbemObjectPath objPath;
  1529. result = SUCCEEDED (objPath.put_Path (bsValue));
  1530. }
  1531. break;
  1532. case wbemCimtypeDatetime:
  1533. {
  1534. CSWbemDateTime dateTime;
  1535. result = SUCCEEDED (dateTime.put_Value (bsValue));
  1536. }
  1537. break;
  1538. case wbemCimtypeSint64:
  1539. {
  1540. __int64 ri64;
  1541. result = ReadI64(bsValue, ri64);
  1542. }
  1543. break;
  1544. case wbemCimtypeUint64:
  1545. {
  1546. unsigned __int64 ri64;
  1547. result = ReadUI64(bsValue, ri64);
  1548. }
  1549. break;
  1550. case wbemCimtypeString:
  1551. result = true;
  1552. break;
  1553. }
  1554. return result;
  1555. }
  1556. //***************************************************************************
  1557. //
  1558. // MapVariantTypeToCimType
  1559. //
  1560. // DESCRIPTION:
  1561. //
  1562. // Attempts to come up with a decent CIM type for the supplied VARIANT value.
  1563. //
  1564. // PARAMETERS:
  1565. // pVal the variant in question
  1566. // iCimType preferred cimtype (if appropriate)
  1567. //
  1568. // RETURN VALUES:
  1569. // A best match CIM type
  1570. //
  1571. //***************************************************************************
  1572. WbemCimtypeEnum MapVariantTypeToCimType (
  1573. VARIANT *pVal,
  1574. CIMTYPE iCimType)
  1575. {
  1576. WbemCimtypeEnum cimType = wbemCimtypeSint32;
  1577. if (pVal)
  1578. {
  1579. VARIANT vTemp;
  1580. VariantInit (&vTemp);
  1581. if ((VT_EMPTY == V_VT(pVal)) || (VT_NULL == V_VT(pVal)))
  1582. cimType = (CIM_ILLEGAL == iCimType) ?
  1583. wbemCimtypeSint32 : (WbemCimtypeEnum) iCimType;
  1584. else if (((VT_ARRAY | VT_VARIANT) == V_VT(pVal)) ||
  1585. ((VT_ARRAY | VT_VARIANT | VT_BYREF) == V_VT(pVal)))
  1586. {
  1587. // Need to dig out the array type
  1588. if ((S_OK == ConvertArray(&vTemp, pVal)) &&
  1589. (S_OK == MapToCIMOMObject(&vTemp)))
  1590. {
  1591. // Check for empty array
  1592. long lLower, lUpper;
  1593. if ((SUCCEEDED(SafeArrayGetLBound(vTemp.parray,1,&lLower))) &&
  1594. (SUCCEEDED(SafeArrayGetUBound(vTemp.parray,1,&lUpper))))
  1595. {
  1596. if (0 == lUpper - lLower + 1)
  1597. {
  1598. // For an empty array, we use wbemCimtypeSint32 unless
  1599. // we have been supplied a valid override
  1600. cimType = (CIM_ILLEGAL == iCimType) ?
  1601. wbemCimtypeSint32 : (WbemCimtypeEnum) iCimType;
  1602. }
  1603. else
  1604. {
  1605. // Pick something that matches our value and override
  1606. // as best we can
  1607. cimType = GetCIMType (vTemp, iCimType, true, lLower, lUpper);
  1608. }
  1609. }
  1610. }
  1611. }
  1612. else
  1613. {
  1614. // Look for an IDispatch that needs to be mapped to an array
  1615. if (((VT_DISPATCH == V_VT(pVal)) || ((VT_DISPATCH|VT_BYREF) == V_VT(pVal))))
  1616. {
  1617. if (S_OK == ConvertDispatchToArray (&vTemp, pVal, cimType & ~CIM_FLAG_ARRAY))
  1618. {
  1619. // Check for empty array
  1620. long lLower, lUpper;
  1621. if ((SUCCEEDED(SafeArrayGetLBound(vTemp.parray,1,&lLower))) &&
  1622. (SUCCEEDED(SafeArrayGetUBound(vTemp.parray,1,&lUpper))))
  1623. {
  1624. if (0 == lUpper - lLower + 1)
  1625. cimType = (CIM_ILLEGAL == iCimType) ?
  1626. wbemCimtypeSint32 : (WbemCimtypeEnum) iCimType;
  1627. else
  1628. cimType = GetCIMType (vTemp, iCimType, true, lLower, lUpper);
  1629. }
  1630. }
  1631. else
  1632. {
  1633. // Could be a plain old interface pointer for CIM_IUNKNOWN
  1634. if (SUCCEEDED(VariantCopy (&vTemp, pVal)))
  1635. {
  1636. if (S_OK == MapToCIMOMObject(&vTemp))
  1637. cimType = GetCIMType (vTemp, iCimType);
  1638. }
  1639. }
  1640. }
  1641. else
  1642. {
  1643. // The vanilla case
  1644. if (SUCCEEDED(VariantCopy (&vTemp, pVal)))
  1645. {
  1646. if (S_OK == MapToCIMOMObject(&vTemp))
  1647. cimType = GetCIMType (vTemp, iCimType);
  1648. }
  1649. }
  1650. }
  1651. VariantClear (&vTemp);
  1652. }
  1653. return cimType;
  1654. }
  1655. //***************************************************************************
  1656. //
  1657. // GetCIMType
  1658. //
  1659. // DESCRIPTION:
  1660. //
  1661. // Attempts to come up with a decent CIM type for the supplied VARIANT,
  1662. // with (optionally) a legal CIMType "serving suggestion" to help resolve
  1663. // ambiguities.
  1664. //
  1665. // Note that this function doesn't deal with empty arrays; that has
  1666. // already been taken care of by the caller. It also can assume that the
  1667. // array is (VARTYPE) homogeneous, for the same reason.
  1668. //
  1669. // PARAMETERS:
  1670. // pVal the variant in question
  1671. // iCimType preferred cimtype (if appropriate, else wbemCimtypeIllegal)
  1672. //
  1673. // RETURN VALUES:
  1674. // A best match CIM type
  1675. //
  1676. //***************************************************************************
  1677. WbemCimtypeEnum GetCIMType (
  1678. VARIANT & var,
  1679. CIMTYPE iCimType,
  1680. bool bIsArray,
  1681. long lLBound,
  1682. long lUBound
  1683. )
  1684. {
  1685. WbemCimtypeEnum cimType = wbemCimtypeSint32;
  1686. switch (V_VT(&var) & ~VT_ARRAY)
  1687. {
  1688. /*
  1689. * Note that prior to this function being called
  1690. * we will have transformed VT_DISPATCH's to
  1691. * VT_UNKNOWN's.
  1692. */
  1693. case VT_UNKNOWN:
  1694. {
  1695. /*
  1696. * Could be an embedded object or just a regular
  1697. * IUnknown.
  1698. */
  1699. if (bIsArray)
  1700. {
  1701. long ix = 0;
  1702. bool bCanBeServingSuggestion = true;
  1703. for(ix = lLBound; ix <= lUBound && bCanBeServingSuggestion; ix++)
  1704. {
  1705. CComPtr<IUnknown> pIUnknown;
  1706. if (SUCCEEDED(SafeArrayGetElement(var.parray,&ix,&pIUnknown)))
  1707. {
  1708. CComQIPtr<IWbemClassObject> pIWbemClassObject (pIUnknown);
  1709. if (!pIWbemClassObject)
  1710. bCanBeServingSuggestion = false;
  1711. }
  1712. else
  1713. bCanBeServingSuggestion = false;
  1714. }
  1715. if (bCanBeServingSuggestion)
  1716. cimType = wbemCimtypeObject;
  1717. }
  1718. else
  1719. {
  1720. CComQIPtr<IWbemClassObject> pIWbemClassObject (var.punkVal);
  1721. if (pIWbemClassObject)
  1722. cimType = wbemCimtypeObject;
  1723. }
  1724. }
  1725. break;
  1726. case VT_EMPTY:
  1727. case VT_ERROR:
  1728. case VT_NULL:
  1729. if (CIM_ILLEGAL == iCimType)
  1730. cimType = wbemCimtypeSint32; // Pick something
  1731. else
  1732. cimType = (WbemCimtypeEnum) iCimType; // Anything goes
  1733. break;
  1734. case VT_VARIANT:
  1735. case VT_DISPATCH:
  1736. // Can't handle these with CIM types
  1737. break;
  1738. case VT_I2:
  1739. {
  1740. cimType = wbemCimtypeSint16; // default
  1741. switch (iCimType)
  1742. {
  1743. case wbemCimtypeSint32:
  1744. case wbemCimtypeUint32:
  1745. case wbemCimtypeSint64:
  1746. case wbemCimtypeUint64:
  1747. case wbemCimtypeSint16:
  1748. case wbemCimtypeUint16:
  1749. case wbemCimtypeChar16:
  1750. cimType = (WbemCimtypeEnum) iCimType;
  1751. break;
  1752. // May be able to use a smaller type but
  1753. // only if the value "fits"
  1754. case wbemCimtypeSint8:
  1755. if (bIsArray)
  1756. {
  1757. long ix = 0;
  1758. bool bCanBeServingSuggestion = true;
  1759. for(ix = lLBound; ix <= lUBound && bCanBeServingSuggestion; ix++)
  1760. {
  1761. short iVal = 0;
  1762. if (SUCCEEDED(SafeArrayGetElement(var.parray,&ix,&iVal)))
  1763. {
  1764. if ((iVal > 0x7F) || (-iVal > 0x80))
  1765. bCanBeServingSuggestion = false;
  1766. }
  1767. else
  1768. bCanBeServingSuggestion = false;
  1769. }
  1770. if (bCanBeServingSuggestion)
  1771. cimType = (WbemCimtypeEnum) iCimType;
  1772. }
  1773. else
  1774. {
  1775. if ((var.iVal <= 0x7F) && (-var.iVal <= 0x80))
  1776. cimType = (WbemCimtypeEnum) iCimType;
  1777. }
  1778. break;
  1779. case wbemCimtypeUint8:
  1780. if (bIsArray)
  1781. {
  1782. long ix = 0;
  1783. bool bCanBeServingSuggestion = true;
  1784. for(ix = lLBound; ix <= lUBound && bCanBeServingSuggestion; ix++)
  1785. {
  1786. short iVal = 0;
  1787. if (SUCCEEDED(SafeArrayGetElement(var.parray,&ix,&iVal)))
  1788. {
  1789. if ((iVal > 0xFF) || (iVal < 0))
  1790. bCanBeServingSuggestion = false;
  1791. }
  1792. else
  1793. bCanBeServingSuggestion = false;
  1794. }
  1795. if (bCanBeServingSuggestion)
  1796. cimType = (WbemCimtypeEnum) iCimType;
  1797. }
  1798. else
  1799. {
  1800. if ((var.iVal <= 0xFF) && (var.iVal >= 0))
  1801. cimType = (WbemCimtypeEnum) iCimType;
  1802. }
  1803. break;
  1804. }
  1805. }
  1806. break;
  1807. case VT_I4:
  1808. {
  1809. cimType = wbemCimtypeSint32; // default
  1810. switch (iCimType)
  1811. {
  1812. case wbemCimtypeSint32:
  1813. case wbemCimtypeUint32:
  1814. case wbemCimtypeSint64:
  1815. case wbemCimtypeUint64:
  1816. cimType = (WbemCimtypeEnum) iCimType;
  1817. break;
  1818. // May be able to use a smaller type but
  1819. // only if the value "fits"
  1820. case wbemCimtypeSint16:
  1821. if (bIsArray)
  1822. {
  1823. long ix = 0;
  1824. bool bCanBeServingSuggestion = true;
  1825. for(ix = lLBound; ix <= lUBound && bCanBeServingSuggestion; ix++)
  1826. {
  1827. long iVal = 0;
  1828. if (SUCCEEDED(SafeArrayGetElement(var.parray,&ix,&iVal)))
  1829. {
  1830. if ((iVal > 0x7FFF) || (-iVal > 0x8000))
  1831. bCanBeServingSuggestion = false;
  1832. }
  1833. else
  1834. bCanBeServingSuggestion = false;
  1835. }
  1836. if (bCanBeServingSuggestion)
  1837. cimType = (WbemCimtypeEnum) iCimType;
  1838. }
  1839. else
  1840. {
  1841. if ((var.lVal <= 0x7FFF) && (-var.lVal <= 0x8000))
  1842. cimType = (WbemCimtypeEnum) iCimType;
  1843. }
  1844. break;
  1845. case wbemCimtypeUint16:
  1846. case wbemCimtypeChar16:
  1847. if (bIsArray)
  1848. {
  1849. long ix = 0;
  1850. bool bCanBeServingSuggestion = true;
  1851. for(ix = lLBound; ix <= lUBound && bCanBeServingSuggestion; ix++)
  1852. {
  1853. long iVal = 0;
  1854. if (SUCCEEDED(SafeArrayGetElement(var.parray,&ix,&iVal)))
  1855. {
  1856. if ((iVal > 0xFFFF) || (iVal < 0))
  1857. bCanBeServingSuggestion = false;
  1858. }
  1859. else
  1860. bCanBeServingSuggestion = false;
  1861. }
  1862. if (bCanBeServingSuggestion)
  1863. cimType = (WbemCimtypeEnum) iCimType;
  1864. }
  1865. else
  1866. {
  1867. if ((var.lVal <= 0xFFFF) && (var.lVal >= 0))
  1868. cimType = (WbemCimtypeEnum) iCimType;
  1869. }
  1870. break;
  1871. case wbemCimtypeSint8:
  1872. if (bIsArray)
  1873. {
  1874. long ix = 0;
  1875. bool bCanBeServingSuggestion = true;
  1876. for(ix = lLBound; ix <= lUBound && bCanBeServingSuggestion; ix++)
  1877. {
  1878. long iVal = 0;
  1879. if (SUCCEEDED(SafeArrayGetElement(var.parray,&ix,&iVal)))
  1880. {
  1881. if ((iVal > 0x7F) || (-iVal > 0x80))
  1882. bCanBeServingSuggestion = false;
  1883. }
  1884. else
  1885. bCanBeServingSuggestion = false;
  1886. }
  1887. if (bCanBeServingSuggestion)
  1888. cimType = (WbemCimtypeEnum) iCimType;
  1889. }
  1890. else
  1891. {
  1892. if ((var.lVal <= 0x7F) && (-var.lVal <= 0x80))
  1893. cimType = (WbemCimtypeEnum) iCimType;
  1894. }
  1895. break;
  1896. case wbemCimtypeUint8:
  1897. if (bIsArray)
  1898. {
  1899. long ix = 0;
  1900. bool bCanBeServingSuggestion = true;
  1901. for(ix = lLBound; ix <= lUBound && bCanBeServingSuggestion; ix++)
  1902. {
  1903. long iVal = 0;
  1904. if (SUCCEEDED(SafeArrayGetElement(var.parray,&ix,&iVal)))
  1905. {
  1906. if ((iVal > 0xFF) || (iVal < 0))
  1907. bCanBeServingSuggestion = false;
  1908. }
  1909. else
  1910. bCanBeServingSuggestion = false;
  1911. }
  1912. if (bCanBeServingSuggestion)
  1913. cimType = (WbemCimtypeEnum) iCimType;
  1914. }
  1915. else
  1916. {
  1917. if ((var.lVal <= 0xFF) && (var.lVal >= 0))
  1918. cimType = (WbemCimtypeEnum) iCimType;
  1919. }
  1920. break;
  1921. }
  1922. }
  1923. break;
  1924. case VT_UI1:
  1925. if ((wbemCimtypeSint16 == iCimType) ||
  1926. (wbemCimtypeUint16 == iCimType) ||
  1927. (wbemCimtypeSint8 == iCimType) ||
  1928. (wbemCimtypeUint8 == iCimType) ||
  1929. (wbemCimtypeChar16 == iCimType) ||
  1930. (wbemCimtypeSint32 == iCimType) ||
  1931. (wbemCimtypeUint32 == iCimType) ||
  1932. (wbemCimtypeSint64 == iCimType) ||
  1933. (wbemCimtypeUint64 == iCimType))
  1934. cimType = (WbemCimtypeEnum) iCimType;
  1935. else
  1936. cimType = wbemCimtypeUint8;
  1937. break;
  1938. case VT_R8:
  1939. if (wbemCimtypeReal64 == iCimType)
  1940. cimType = (WbemCimtypeEnum) iCimType;
  1941. else if (wbemCimtypeReal32 == iCimType)
  1942. {
  1943. if (bIsArray)
  1944. {
  1945. long ix = 0;
  1946. bool bCanBeServingSuggestion = true;
  1947. for(ix = lLBound; ix <= lUBound && bCanBeServingSuggestion; ix++)
  1948. {
  1949. double dblVal = 0;
  1950. if (SUCCEEDED(SafeArrayGetElement(var.parray,&ix,&dblVal)))
  1951. {
  1952. if (dblVal != (double)dblVal)
  1953. bCanBeServingSuggestion = false;
  1954. }
  1955. else
  1956. bCanBeServingSuggestion = false;
  1957. }
  1958. if (bCanBeServingSuggestion)
  1959. cimType = (WbemCimtypeEnum) iCimType;
  1960. }
  1961. else
  1962. {
  1963. if (var.dblVal == (float)(var.dblVal))
  1964. cimType = (WbemCimtypeEnum) iCimType;
  1965. }
  1966. }
  1967. else
  1968. cimType = wbemCimtypeReal64;
  1969. break;
  1970. case VT_R4:
  1971. if ((wbemCimtypeReal32 == iCimType) ||
  1972. (wbemCimtypeReal64 == iCimType))
  1973. cimType = (WbemCimtypeEnum) iCimType;
  1974. else
  1975. cimType = wbemCimtypeReal32;
  1976. break;
  1977. case VT_BOOL:
  1978. cimType = wbemCimtypeBoolean;
  1979. break;
  1980. case VT_CY:
  1981. case VT_DATE:
  1982. cimType = wbemCimtypeString; // Only sensible choice
  1983. break;
  1984. case VT_BSTR:
  1985. {
  1986. cimType = wbemCimtypeString; // Unless we get a tighter fit
  1987. if ((wbemCimtypeString == iCimType) ||
  1988. (wbemCimtypeDatetime == iCimType) ||
  1989. (wbemCimtypeReference == iCimType) ||
  1990. (wbemCimtypeUint64 == iCimType) ||
  1991. (wbemCimtypeSint64 == iCimType))
  1992. {
  1993. if (bIsArray)
  1994. {
  1995. long ix = 0;
  1996. bool bCanBeServingSuggestion = true;
  1997. for(ix = lLBound; ix <= lUBound && bCanBeServingSuggestion; ix++)
  1998. {
  1999. BSTR bsValue = NULL;
  2000. if (SUCCEEDED(SafeArrayGetElement(var.parray,&ix,&bsValue)))
  2001. bCanBeServingSuggestion = CanCoerceString (bsValue, (WbemCimtypeEnum) iCimType);
  2002. else
  2003. bCanBeServingSuggestion = false;
  2004. SysFreeString(bsValue);
  2005. }
  2006. if (bCanBeServingSuggestion)
  2007. cimType = (WbemCimtypeEnum) iCimType;
  2008. }
  2009. else
  2010. {
  2011. if (CanCoerceString (var.bstrVal, (WbemCimtypeEnum) iCimType))
  2012. cimType = (WbemCimtypeEnum) iCimType;
  2013. }
  2014. }
  2015. }
  2016. break;
  2017. }
  2018. return cimType;
  2019. }
  2020. //***************************************************************************
  2021. //
  2022. // BOOL ReadI64
  2023. //
  2024. // DESCRIPTION:
  2025. //
  2026. // Reads a signed 64-bit value from a string
  2027. //
  2028. // PARAMETERS:
  2029. //
  2030. // LPCWSTR wsz String to read from
  2031. // __int64& i64 Destination for the value
  2032. //
  2033. //***************************************************************************
  2034. bool ReadI64(LPCWSTR wsz, __int64& ri64)
  2035. {
  2036. __int64 i64 = 0;
  2037. const WCHAR* pwc = wsz;
  2038. __int64 ia64max = ((0x7FFFFFFFFFFFFFFF / 0xA) + 0xA);
  2039. int nSign = 1;
  2040. if(*pwc == L'-')
  2041. {
  2042. nSign = -1;
  2043. pwc++;
  2044. }
  2045. while(i64 >= 0 && i64 < ia64max &&
  2046. *pwc >= L'0' && *pwc <= L'9')
  2047. {
  2048. i64 = i64 * 10 + (*pwc - L'0');
  2049. pwc++;
  2050. }
  2051. if(*pwc)
  2052. return false;
  2053. if(i64 < 0)
  2054. {
  2055. // Special case --- largest negative number
  2056. // ========================================
  2057. if(nSign == -1 && i64 == (__int64)0x8000000000000000)
  2058. {
  2059. ri64 = i64;
  2060. return true;
  2061. }
  2062. return false;
  2063. }
  2064. ri64 = i64 * nSign;
  2065. return true;
  2066. }
  2067. //***************************************************************************
  2068. //
  2069. // BOOL ReadUI64
  2070. //
  2071. // DESCRIPTION:
  2072. //
  2073. // Reads an unsigned 64-bit value from a string
  2074. //
  2075. // PARAMETERS:
  2076. //
  2077. // LPCWSTR wsz String to read from
  2078. // unsigned __int64& i64 Destination for the value
  2079. //
  2080. //***************************************************************************
  2081. bool ReadUI64(LPCWSTR wsz, unsigned __int64& rui64)
  2082. {
  2083. unsigned __int64 ui64 = 0;
  2084. const WCHAR* pwc = wsz;
  2085. while(ui64 < 0xFFFFFFFFFFFFFFFF / 8 && *pwc >= L'0' && *pwc <= L'9')
  2086. {
  2087. unsigned __int64 ui64old = ui64;
  2088. ui64 = ui64 * 10 + (*pwc - L'0');
  2089. if(ui64 < ui64old)
  2090. return false;
  2091. pwc++;
  2092. }
  2093. if(*pwc)
  2094. {
  2095. return false;
  2096. }
  2097. rui64 = ui64;
  2098. return true;
  2099. }
  2100. HRESULT BuildStringArray (
  2101. SAFEARRAY *pArray,
  2102. VARIANT & var
  2103. )
  2104. {
  2105. HRESULT hr = WBEM_E_FAILED;
  2106. SAFEARRAYBOUND rgsabound;
  2107. rgsabound.lLbound = 0;
  2108. long lBound = 0, uBound = -1;
  2109. if (pArray)
  2110. {
  2111. SafeArrayGetUBound (pArray, 1, &uBound);
  2112. SafeArrayGetLBound (pArray, 1, &lBound);
  2113. }
  2114. rgsabound.cElements = uBound + 1 - lBound;
  2115. SAFEARRAY *pNewArray = SafeArrayCreate (VT_VARIANT, 1, &rgsabound);
  2116. if (pNewArray)
  2117. {
  2118. BSTR bstrName = NULL;
  2119. VARIANT nameVar;
  2120. VariantInit (&nameVar);
  2121. bool ok = true;
  2122. /*
  2123. * If the source array is not empty, copy it over to the
  2124. * new array. Wrap each member in a Variant, and ensure indexing
  2125. * begins at 0.
  2126. */
  2127. if (0 < rgsabound.cElements)
  2128. {
  2129. for (long i = 0; (i <= (rgsabound.cElements - 1)) && ok; i++)
  2130. {
  2131. long j = lBound + i;
  2132. if (SUCCEEDED(SafeArrayGetElement (pArray, &j, &bstrName)))
  2133. {
  2134. BSTR copy = SysAllocString (bstrName);
  2135. if (copy)
  2136. {
  2137. nameVar.vt = VT_BSTR;
  2138. nameVar.bstrVal = copy;
  2139. if (FAILED(SafeArrayPutElement (pNewArray, &i, &nameVar)))
  2140. {
  2141. ok = false;
  2142. hr = WBEM_E_OUT_OF_MEMORY;
  2143. }
  2144. SysFreeString (bstrName);
  2145. VariantClear (&nameVar);
  2146. }
  2147. else
  2148. {
  2149. ok = false;
  2150. hr = WBEM_E_OUT_OF_MEMORY;
  2151. }
  2152. }
  2153. else
  2154. ok = false;
  2155. }
  2156. }
  2157. if (ok)
  2158. {
  2159. // Now plug this array into the VARIANT
  2160. var.vt = VT_ARRAY | VT_VARIANT;
  2161. var.parray = pNewArray;
  2162. hr = S_OK;
  2163. }
  2164. else
  2165. {
  2166. if (pNewArray)
  2167. SafeArrayDestroy (pNewArray);
  2168. }
  2169. }
  2170. else
  2171. hr = WBEM_E_OUT_OF_MEMORY;
  2172. return hr;
  2173. }
  2174. HRESULT SetFromStringArray (
  2175. SAFEARRAY **ppArray,
  2176. VARIANT *pVar
  2177. )
  2178. {
  2179. HRESULT hr = WBEM_E_FAILED;
  2180. if ((NULL == pVar) || (VT_EMPTY == V_VT(pVar)) ||
  2181. (VT_NULL == V_VT(pVar)))
  2182. {
  2183. if (*ppArray)
  2184. {
  2185. SafeArrayDestroy (*ppArray);
  2186. *ppArray = NULL;
  2187. }
  2188. hr = WBEM_S_NO_ERROR;
  2189. }
  2190. else if (((VT_ARRAY | VT_VARIANT) == V_VT(pVar)) ||
  2191. ((VT_ARRAY | VT_VARIANT | VT_BYREF) == V_VT(pVar)))
  2192. {
  2193. VARIANT vTemp;
  2194. VariantInit (&vTemp);
  2195. if (S_OK == ConvertArray(&vTemp, pVar))
  2196. {
  2197. // Is it a string array?
  2198. if (V_VT(&vTemp) == (VT_ARRAY|VT_BSTR))
  2199. {
  2200. // Super - grab it out of the temporary VARIANT
  2201. if (*ppArray)
  2202. SafeArrayDestroy (*ppArray);
  2203. *ppArray = vTemp.parray;
  2204. vTemp.vt = VT_NULL;
  2205. vTemp.parray = NULL;
  2206. hr = WBEM_S_NO_ERROR;
  2207. }
  2208. }
  2209. VariantClear(&vTemp);
  2210. }
  2211. else
  2212. {
  2213. // Look for an IDispatch that needs to be mapped to an array
  2214. if ((VT_DISPATCH == V_VT(pVar))
  2215. || ((VT_DISPATCH|VT_BYREF) == V_VT(pVar)))
  2216. {
  2217. VARIANT vTemp;
  2218. VariantInit (&vTemp);
  2219. if (S_OK == ConvertDispatchToArray (&vTemp, pVar, wbemCimtypeString))
  2220. {
  2221. // Is it a string array?
  2222. if (V_VT(&vTemp) == (VT_ARRAY|VT_BSTR))
  2223. {
  2224. // Super - grab it out of the temporary VARIANT
  2225. if (*ppArray)
  2226. SafeArrayDestroy (*ppArray);
  2227. *ppArray = vTemp.parray;
  2228. vTemp.vt = VT_NULL;
  2229. vTemp.parray = NULL;
  2230. hr = WBEM_S_NO_ERROR;
  2231. }
  2232. }
  2233. VariantClear (&vTemp);
  2234. }
  2235. }
  2236. return hr;
  2237. }
  2238. //***************************************************************************
  2239. //
  2240. // bool IsNullOrEmptyVariant
  2241. //
  2242. // DESCRIPTION:
  2243. //
  2244. // Given a VARIANT, check if it is essentially null/empty or has
  2245. // more than one dimension
  2246. //
  2247. // PARAMETERS:
  2248. //
  2249. // pVar variant to check
  2250. //
  2251. // RETURNS:
  2252. // true if and only if the conversion was possible
  2253. //
  2254. //***************************************************************************
  2255. bool IsNullOrEmptyVariant (VARIANT & var)
  2256. {
  2257. bool result = false;
  2258. if ((VT_EMPTY == var.vt) || (VT_NULL == var.vt))
  2259. result = true;
  2260. else if (VT_ARRAY & var.vt)
  2261. {
  2262. // Check if array that it is not empty or NULL
  2263. if (!(var.parray))
  2264. result = true;
  2265. else
  2266. {
  2267. long lBound, uBound;
  2268. if ((1 != SafeArrayGetDim (var.parray)) ||
  2269. (
  2270. SUCCEEDED(SafeArrayGetLBound (var.parray, 1, &lBound)) &&
  2271. SUCCEEDED(SafeArrayGetUBound (var.parray, 1, &uBound)) &&
  2272. (0 == (uBound - lBound + 1))
  2273. )
  2274. )
  2275. result = true;
  2276. }
  2277. }
  2278. return result;
  2279. }
  2280. //***************************************************************************
  2281. //
  2282. // bool RemoveElementFromArray
  2283. //
  2284. // DESCRIPTION:
  2285. //
  2286. // Given a SAFEARRAY and an index, remove the element at that index
  2287. // and shift left all following elements by one.
  2288. //
  2289. // PARAMETERS:
  2290. //
  2291. // array the SAFEARRAY in qeustion
  2292. // vt Variant type of elements in array
  2293. // iIndex index of element to remove
  2294. //
  2295. // RETURNS:
  2296. // true if and only if the conversion was possible
  2297. //
  2298. //***************************************************************************
  2299. bool RemoveElementFromArray (SAFEARRAY & array, VARTYPE vt, long iIndex)
  2300. {
  2301. /*
  2302. * Note: caller must ensure that the array is within bounds and that the
  2303. *
  2304. */
  2305. bool result = false;
  2306. long lBound, uBound;
  2307. if ((1== SafeArrayGetDim (&array)) &&
  2308. SUCCEEDED(SafeArrayGetLBound (&array, 1, &lBound)) &&
  2309. SUCCEEDED(SafeArrayGetUBound (&array, 1, &uBound)) &&
  2310. (0 < (uBound - lBound + 1)) &&
  2311. (iIndex <= uBound))
  2312. {
  2313. bool ok = true;
  2314. for (long i = iIndex+1; ok && (i <= uBound); i++)
  2315. ok = ShiftLeftElement (array, vt, i);
  2316. // Finally Redim to get rid of the last element
  2317. if (ok)
  2318. {
  2319. SAFEARRAYBOUND rgsabound;
  2320. rgsabound.lLbound = lBound;
  2321. rgsabound.cElements = uBound - lBound;
  2322. result = SUCCEEDED(SafeArrayRedim (&array, &rgsabound));
  2323. }
  2324. else
  2325. result = false;
  2326. }
  2327. return result;
  2328. }
  2329. //***************************************************************************
  2330. //
  2331. // bool ShiftLeftElement
  2332. //
  2333. // DESCRIPTION:
  2334. //
  2335. // Given a SAFEARRAY and an index, remove the element at that index
  2336. // and shift left all following elements by one.
  2337. //
  2338. // PARAMETERS:
  2339. //
  2340. // array the SAFEARRAY in question
  2341. // vt Variant type of elements in array
  2342. // iIndex index of element to remove
  2343. //
  2344. // RETURNS:
  2345. // true if and only if the conversion was possible
  2346. //
  2347. //***************************************************************************
  2348. bool ShiftLeftElement (SAFEARRAY & array, VARTYPE vt, long iIndex)
  2349. {
  2350. bool result = false;
  2351. long iNewIndex = iIndex - 1;
  2352. switch (vt)
  2353. {
  2354. case VT_BSTR:
  2355. {
  2356. BSTR bstrVal;
  2357. if (SUCCEEDED(SafeArrayGetElement (&array, &iIndex, &bstrVal)))
  2358. {
  2359. result = SUCCEEDED(SafeArrayPutElement (&array, &iNewIndex, bstrVal));
  2360. SysFreeString (bstrVal);
  2361. }
  2362. }
  2363. break;
  2364. case VT_UI1:
  2365. {
  2366. unsigned char bVal;
  2367. if (SUCCEEDED(SafeArrayGetElement (&array, &iIndex, &bVal)))
  2368. result = SUCCEEDED(SafeArrayPutElement (&array, &iNewIndex, &bVal));
  2369. }
  2370. break;
  2371. case VT_I2:
  2372. {
  2373. short iVal;
  2374. if (SUCCEEDED(SafeArrayGetElement (&array, &iIndex, &iVal)))
  2375. result = SUCCEEDED(SafeArrayPutElement (&array, &iNewIndex, &iVal));
  2376. }
  2377. break;
  2378. case VT_I4:
  2379. {
  2380. long lVal;
  2381. if (SUCCEEDED(SafeArrayGetElement (&array, &iIndex, &lVal)))
  2382. result = SUCCEEDED(SafeArrayPutElement (&array, &iNewIndex, &lVal));
  2383. }
  2384. break;
  2385. case VT_R4:
  2386. {
  2387. float fltVal;
  2388. if (SUCCEEDED(SafeArrayGetElement (&array, &iIndex, &fltVal)))
  2389. result = SUCCEEDED(SafeArrayPutElement (&array, &iNewIndex, &fltVal));
  2390. }
  2391. break;
  2392. case VT_R8:
  2393. {
  2394. double dblVal;
  2395. if (SUCCEEDED(SafeArrayGetElement (&array, &iIndex, &dblVal)))
  2396. result = SUCCEEDED(SafeArrayPutElement (&array, &iNewIndex, &dblVal));
  2397. }
  2398. break;
  2399. case VT_BOOL:
  2400. {
  2401. VARIANT_BOOL boolVal;
  2402. if (SUCCEEDED(SafeArrayGetElement (&array, &iIndex, &boolVal)))
  2403. result = SUCCEEDED(SafeArrayPutElement (&array, &iNewIndex, &boolVal));
  2404. }
  2405. break;
  2406. }
  2407. return result;
  2408. }
  2409. bool ShiftElementsToRight (SAFEARRAY & array, VARTYPE vt, long iStartIndex,
  2410. long iEndIndex, long iCount)
  2411. {
  2412. bool result = true;
  2413. for (long iIndex = iEndIndex; result && (iIndex >= iStartIndex); iIndex--)
  2414. {
  2415. long iNewIndex = iIndex + iCount;
  2416. switch (vt)
  2417. {
  2418. case VT_BSTR:
  2419. {
  2420. BSTR bstrVal;
  2421. if (SUCCEEDED(SafeArrayGetElement (&array, &iIndex, &bstrVal)))
  2422. {
  2423. result = SUCCEEDED(SafeArrayPutElement (&array, &iNewIndex, bstrVal));
  2424. SysFreeString (bstrVal);
  2425. }
  2426. }
  2427. break;
  2428. case VT_UI1:
  2429. {
  2430. unsigned char bVal;
  2431. if (SUCCEEDED(SafeArrayGetElement (&array, &iIndex, &bVal)))
  2432. result = SUCCEEDED(SafeArrayPutElement (&array, &iNewIndex, &bVal));
  2433. }
  2434. break;
  2435. case VT_I2:
  2436. {
  2437. short iVal;
  2438. if (SUCCEEDED(SafeArrayGetElement (&array, &iIndex, &iVal)))
  2439. result = SUCCEEDED(SafeArrayPutElement (&array, &iNewIndex, &iVal));
  2440. }
  2441. break;
  2442. case VT_I4:
  2443. {
  2444. long lVal;
  2445. if (SUCCEEDED(SafeArrayGetElement (&array, &iIndex, &lVal)))
  2446. result = SUCCEEDED(SafeArrayPutElement (&array, &iNewIndex, &lVal));
  2447. }
  2448. break;
  2449. case VT_R4:
  2450. {
  2451. float fltVal;
  2452. if (SUCCEEDED(SafeArrayGetElement (&array, &iIndex, &fltVal)))
  2453. result = SUCCEEDED(SafeArrayPutElement (&array, &iNewIndex, &fltVal));
  2454. }
  2455. break;
  2456. case VT_R8:
  2457. {
  2458. double dblVal;
  2459. if (SUCCEEDED(SafeArrayGetElement (&array, &iIndex, &dblVal)))
  2460. result = SUCCEEDED(SafeArrayPutElement (&array, &iNewIndex, &dblVal));
  2461. }
  2462. break;
  2463. case VT_BOOL:
  2464. {
  2465. VARIANT_BOOL boolVal;
  2466. if (SUCCEEDED(SafeArrayGetElement (&array, &iIndex, &boolVal)))
  2467. result = SUCCEEDED(SafeArrayPutElement (&array, &iNewIndex, &boolVal));
  2468. }
  2469. break;
  2470. case VT_DISPATCH:
  2471. {
  2472. IDispatch *pdispVal = NULL;
  2473. if (SUCCEEDED(SafeArrayGetElement (&array, &iIndex, &pdispVal)))
  2474. {
  2475. result = SUCCEEDED(SafeArrayPutElement (&array, &iNewIndex, pdispVal));
  2476. if (pdispVal)
  2477. pdispVal->Release ();
  2478. }
  2479. }
  2480. break;
  2481. case VT_UNKNOWN:
  2482. {
  2483. IUnknown *punkVal = NULL;
  2484. if (SUCCEEDED(SafeArrayGetElement (&array, &iIndex, &punkVal)))
  2485. {
  2486. result = SUCCEEDED(SafeArrayPutElement (&array, &iNewIndex, punkVal));
  2487. if (punkVal)
  2488. punkVal->Release ();
  2489. }
  2490. }
  2491. break;
  2492. }
  2493. }
  2494. return result;
  2495. }
  2496. //***************************************************************************
  2497. //
  2498. // bool MatchBSTR
  2499. //
  2500. // DESCRIPTION:
  2501. //
  2502. // Given a VARIANT and a BSTR, find out whether the BSTR matches the
  2503. // VARIANT value (either the complete value or a member thereof).
  2504. //
  2505. // PARAMETERS:
  2506. //
  2507. // var the VARIANT in question
  2508. // bstrVal the BSTR in question
  2509. //
  2510. // RETURNS:
  2511. // true if and only if the match was made
  2512. //
  2513. //***************************************************************************
  2514. bool MatchBSTR (VARIANT & var, BSTR & bstrVal)
  2515. {
  2516. bool result = false;
  2517. // Coerce into the underlying type of the variant
  2518. VARIANT srcVar, dstVar;
  2519. srcVar.vt = VT_BSTR;
  2520. srcVar.bstrVal = SysAllocString (bstrVal);
  2521. VariantInit (&dstVar);
  2522. if (SUCCEEDED (VariantChangeType (&dstVar, &srcVar, 0, var.vt & ~VT_ARRAY)))
  2523. {
  2524. result = MatchValue (var, dstVar);
  2525. VariantClear (&dstVar);
  2526. }
  2527. VariantClear (&srcVar);
  2528. return result;
  2529. }
  2530. //***************************************************************************
  2531. //
  2532. // bool MatchUI1
  2533. //
  2534. // DESCRIPTION:
  2535. //
  2536. // Given a VARIANT and a UI1, find out whether the UI1 matches the
  2537. // VARIANT value (either the complete value or a member thereof).
  2538. //
  2539. // PARAMETERS:
  2540. //
  2541. // var the VARIANT in question
  2542. // bstrVal the BSTR in question
  2543. //
  2544. // RETURNS:
  2545. // true if and only if the match was made
  2546. //
  2547. //***************************************************************************
  2548. bool MatchUI1 (VARIANT & var, unsigned char bVal)
  2549. {
  2550. bool result = false;
  2551. // Coerce into the underlying type of the variant
  2552. VARIANT srcVar, dstVar;
  2553. srcVar.vt = VT_UI1;
  2554. srcVar.bVal = bVal;
  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 MatchBool (VARIANT & var, VARIANT_BOOL boolVal)
  2564. {
  2565. bool result = false;
  2566. // Coerce into the underlying type of the variant
  2567. VARIANT srcVar, dstVar;
  2568. srcVar.vt = VT_BOOL;
  2569. srcVar.boolVal = boolVal;
  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 MatchI2 (VARIANT & var, short iVal)
  2579. {
  2580. bool result = false;
  2581. // Coerce into the underlying type of the variant
  2582. VARIANT srcVar, dstVar;
  2583. srcVar.vt = VT_I2;
  2584. srcVar.iVal = iVal;
  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 MatchI4 (VARIANT & var, long lVal)
  2594. {
  2595. bool result = false;
  2596. // Coerce into the underlying type of the variant
  2597. VARIANT srcVar, dstVar;
  2598. srcVar.vt = VT_I4;
  2599. srcVar.lVal = lVal;
  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 MatchR4 (VARIANT & var, float fltVal)
  2609. {
  2610. bool result = false;
  2611. // Coerce into the underlying type of the variant
  2612. VARIANT srcVar, dstVar;
  2613. srcVar.vt = VT_R4;
  2614. srcVar.fltVal = fltVal;
  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. bool MatchR8 (VARIANT & var, double dblVal)
  2624. {
  2625. bool result = false;
  2626. // Coerce into the underlying type of the variant
  2627. VARIANT srcVar, dstVar;
  2628. srcVar.vt = VT_R8;
  2629. srcVar.dblVal = dblVal;
  2630. VariantInit (&dstVar);
  2631. if (SUCCEEDED (VariantChangeType (&dstVar, &srcVar, 0, var.vt & ~VT_ARRAY)))
  2632. {
  2633. result = MatchValue (var, dstVar);
  2634. VariantClear (&dstVar);
  2635. }
  2636. return result;
  2637. }
  2638. //***************************************************************************
  2639. //
  2640. // bool MatchValue
  2641. //
  2642. // DESCRIPTION:
  2643. //
  2644. // Given a VARIANT (which may or may not be an array) and a second VARIANT
  2645. // (which is not an array) determine whether the second value matches the
  2646. // first or an element of the first.
  2647. //
  2648. // ASSUMPTIONS
  2649. //
  2650. // 1. The two VARIANTS have the same underlying type
  2651. // 2. The second VARIANT cannot be an array
  2652. //
  2653. // PARAMETERS:
  2654. //
  2655. // var the VARIANT in question
  2656. // bstrVal the BSTR in question
  2657. //
  2658. // RETURNS:
  2659. // true if and only if the match was made
  2660. //
  2661. //***************************************************************************
  2662. bool MatchValue (VARIANT &var1, VARIANT &var2)
  2663. {
  2664. bool result = false;
  2665. bool bIsArray = (var1.vt & VT_ARRAY) ? true : false;
  2666. if (bIsArray)
  2667. {
  2668. long lBound, uBound;
  2669. if (var1.parray && (1== SafeArrayGetDim (var1.parray)) &&
  2670. SUCCEEDED(SafeArrayGetLBound (var1.parray, 1, &lBound)) &&
  2671. SUCCEEDED(SafeArrayGetUBound (var1.parray, 1, &uBound)) &&
  2672. (0 < (uBound - lBound + 1)))
  2673. {
  2674. // Break out on first match
  2675. for (long i = lBound; !result && (i <= uBound); i++)
  2676. {
  2677. switch (var1.vt & ~VT_ARRAY)
  2678. {
  2679. case VT_BSTR:
  2680. {
  2681. BSTR bstrVal = NULL;
  2682. if (SUCCEEDED(SafeArrayGetElement (var1.parray, &i, &bstrVal)))
  2683. {
  2684. result = (0 == wcscmp (bstrVal, var2.bstrVal));
  2685. SysFreeString (bstrVal);
  2686. }
  2687. }
  2688. break;
  2689. case VT_UI1:
  2690. {
  2691. unsigned char bVal;
  2692. if (SUCCEEDED(SafeArrayGetElement (var1.parray, &i, &bVal)))
  2693. result = (bVal == var2.bVal);
  2694. }
  2695. break;
  2696. case VT_I2:
  2697. {
  2698. short iVal;
  2699. if (SUCCEEDED(SafeArrayGetElement (var1.parray, &i, &iVal)))
  2700. result = (iVal == var2.iVal);
  2701. }
  2702. break;
  2703. case VT_I4:
  2704. {
  2705. long lVal;
  2706. if (SUCCEEDED(SafeArrayGetElement (var1.parray, &i, &lVal)))
  2707. result = (lVal == var2.lVal);
  2708. }
  2709. break;
  2710. case VT_R4:
  2711. {
  2712. float fltVal;
  2713. if (SUCCEEDED(SafeArrayGetElement (var1.parray, &i, &fltVal)))
  2714. result = (fltVal == var2.fltVal);
  2715. }
  2716. break;
  2717. case VT_R8:
  2718. {
  2719. double dblVal;
  2720. if (SUCCEEDED(SafeArrayGetElement (var1.parray, &i, &dblVal)))
  2721. result = (dblVal == var2.dblVal);
  2722. }
  2723. break;
  2724. case VT_BOOL:
  2725. {
  2726. VARIANT_BOOL boolVal;
  2727. if (SUCCEEDED(SafeArrayGetElement (var1.parray, &i, &boolVal)))
  2728. result = (boolVal == var2.boolVal);
  2729. }
  2730. break;
  2731. }
  2732. }
  2733. }
  2734. }
  2735. else
  2736. {
  2737. switch (var1.vt)
  2738. {
  2739. case VT_BSTR:
  2740. result = (0 == wcscmp (var1.bstrVal, var2.bstrVal));
  2741. break;
  2742. case VT_UI1:
  2743. result = (var1.bVal == var2.bVal);
  2744. break;
  2745. case VT_I2:
  2746. result = (var1.iVal == var2.iVal);
  2747. break;
  2748. case VT_I4:
  2749. result = (var1.lVal == var2.lVal);
  2750. break;
  2751. case VT_R4:
  2752. result = (var1.fltVal == var2.fltVal);
  2753. break;
  2754. case VT_R8:
  2755. result = (var1.dblVal == var2.dblVal);
  2756. break;
  2757. case VT_BOOL:
  2758. result = (var1.boolVal == var2.boolVal);
  2759. break;
  2760. }
  2761. }
  2762. return result;
  2763. }
  2764. //***************************************************************************
  2765. //
  2766. // HRESULT WmiVariantChangeType
  2767. //
  2768. // DESCRIPTION:
  2769. //
  2770. // Given a VARIANT value and a desired CIM type, cast the value to a VARIANT
  2771. // which will be accepted when supplied to CIMOM for a property of that type.
  2772. //
  2773. // PARAMETERS:
  2774. //
  2775. // vOut the cast value
  2776. // pvIn the value to be cast
  2777. // lCimType the required CIM type
  2778. //
  2779. // RETURNS:
  2780. // S_OK if succeeded, WBEM_E_TYPE_MISMATCH if not
  2781. //
  2782. //***************************************************************************
  2783. // NTBUG#21788: IA64 workaround until compiler version 2210 or greater drop.
  2784. HRESULT WmiVariantChangeType (
  2785. VARIANT & vOut,
  2786. VARIANT *pvIn,
  2787. CIMTYPE lCimType
  2788. )
  2789. {
  2790. HRESULT hr = WBEM_E_TYPE_MISMATCH;
  2791. VariantInit (&vOut);
  2792. // First we check for a NULL value, as these are easy
  2793. if ((NULL == pvIn) || VT_EMPTY == V_VT(pvIn) || VT_NULL == V_VT(pvIn) ||
  2794. ((VT_ERROR == V_VT(pvIn)) && (DISP_E_PARAMNOTFOUND == pvIn->scode)))
  2795. {
  2796. ZeroMemory( &vOut, sizeof( VARIANT ) );
  2797. vOut.vt = VT_NULL;
  2798. hr = S_OK;
  2799. }
  2800. else
  2801. {
  2802. // The kind of variant we will need to construct
  2803. VARTYPE vtOut = CimTypeToVtType (lCimType);
  2804. // The VARTYPE we've been given
  2805. VARTYPE vtIn = V_VT(pvIn);
  2806. if (vtOut == vtIn)
  2807. {
  2808. // Life is easy
  2809. hr = VariantCopy (&vOut, pvIn);
  2810. }
  2811. else
  2812. {
  2813. // Types do not match - we have some work to to
  2814. if (CIM_FLAG_ARRAY & lCimType)
  2815. {
  2816. /*
  2817. * Check for a regular SAFEARRAY type value first; if that fails
  2818. * then look for an IDispatch-style array value.
  2819. */
  2820. if (((VT_ARRAY | VT_VARIANT) == vtIn) ||
  2821. ((VT_ARRAY | VT_VARIANT | VT_BYREF) == vtIn))
  2822. {
  2823. SAFEARRAY *parray = (VT_BYREF & vtIn) ? *(pvIn->pparray) : pvIn->parray;
  2824. hr = WmiConvertSafeArray (vOut, parray, lCimType & ~VT_ARRAY);
  2825. }
  2826. else if ((VT_DISPATCH == vtIn) || ((VT_DISPATCH|VT_BYREF) == vtIn))
  2827. {
  2828. CComPtr<IDispatch> pIDispatch =
  2829. (VT_BYREF & vtIn) ? *(pvIn->ppdispVal) : pvIn->pdispVal;
  2830. hr = WmiConvertDispatchArray (vOut, pIDispatch, lCimType & ~VT_ARRAY);
  2831. }
  2832. else if (((VT_ARRAY | VT_DISPATCH) == vtIn) ||
  2833. ((VT_ARRAY | VT_DISPATCH | VT_BYREF) == vtIn))
  2834. {
  2835. if (SUCCEEDED(hr = VariantCopy (&vOut, pvIn)))
  2836. hr = MapToCIMOMObject (&vOut);
  2837. }
  2838. }
  2839. else
  2840. {
  2841. switch (lCimType)
  2842. {
  2843. case wbemCimtypeSint8:
  2844. {
  2845. /*
  2846. * These are represented by
  2847. * a VT_I2, but we need to be careful about sign
  2848. * extension from shorter types taking us "out of range".
  2849. */
  2850. if (SUCCEEDED(hr = VariantChangeType (&vOut, pvIn, 0, vtOut)))
  2851. {
  2852. // Did we get sign extended?
  2853. if ((VT_UI1 == vtIn) || (VT_BOOL == vtIn))
  2854. vOut.lVal &= 0x000000FF;
  2855. }
  2856. else
  2857. {
  2858. // If we can't change the type, try the one we're given
  2859. hr = VariantCopy (&vOut, pvIn);
  2860. }
  2861. }
  2862. break;
  2863. case wbemCimtypeSint64:
  2864. case wbemCimtypeUint64:
  2865. {
  2866. /*
  2867. * These types are realized as VT_BSTR in CIM terms, which means
  2868. * that VariantChangeType will almost always succeed but not
  2869. * leave us with a valid numeric value. To be consistent with other
  2870. * numeric types we should round up floating/double
  2871. * values to the next largest integer (as is done by VariantChangeType
  2872. * for VT_R8 to numeric conversion).
  2873. */
  2874. if (VT_R8 == V_VT(pvIn))
  2875. {
  2876. // if (SUCCEEDED(hr = VariantCopy (&vOut, pvIn)))
  2877. {
  2878. vOut.vt = pvIn->vt;
  2879. // Round it up
  2880. vOut.dblVal = (pvIn->dblVal + 0.5) > ceil(pvIn->dblVal) ?
  2881. ceil(pvIn->dblVal) :
  2882. ceil(pvIn->dblVal - 0.5);
  2883. // Convert to string
  2884. int dec = 0;
  2885. int sign = 0;
  2886. char *pDbl = _fcvt (vOut.dblVal, 0, &dec, &sign);
  2887. if (pDbl)
  2888. {
  2889. size_t len = strlen (pDbl);
  2890. /*
  2891. * Having rounded up to an integer, we really expect
  2892. * there to be no fractional component to the number
  2893. * returned by _fcvt.
  2894. */
  2895. if (dec == len)
  2896. {
  2897. /*
  2898. * Now convert to a wide string - remember the
  2899. * sign bit!
  2900. */
  2901. if (0 != sign)
  2902. len += 1;
  2903. wchar_t *pValue = new wchar_t [len + 1];
  2904. if (pValue)
  2905. {
  2906. if (0 != sign)
  2907. {
  2908. pValue [0] = L'-';
  2909. mbstowcs (pValue+1, pDbl, len);
  2910. }
  2911. else
  2912. mbstowcs (pValue, pDbl, len);
  2913. pValue [len] = NULL;
  2914. // Now set it in the variant
  2915. vOut.bstrVal = SysAllocString (pValue);
  2916. vOut.vt = VT_BSTR;
  2917. delete [] pValue;
  2918. hr = S_OK;
  2919. }
  2920. }
  2921. }
  2922. }
  2923. }
  2924. else
  2925. hr = VariantChangeType (&vOut, pvIn, 0, vtOut);
  2926. if (FAILED(hr))
  2927. {
  2928. // If we can't change the type, try the one we're given
  2929. hr = VariantCopy (&vOut, pvIn);
  2930. }
  2931. }
  2932. break;
  2933. case wbemCimtypeUint8:
  2934. case wbemCimtypeSint16:
  2935. case wbemCimtypeSint32:
  2936. case wbemCimtypeReal32:
  2937. case wbemCimtypeReal64:
  2938. case wbemCimtypeString:
  2939. case wbemCimtypeDatetime:
  2940. case wbemCimtypeBoolean:
  2941. case wbemCimtypeReference:
  2942. {
  2943. /*
  2944. * These types have a "prefect" fit to their
  2945. * corresponding Variant type.
  2946. */
  2947. if (FAILED(hr = VariantChangeType (&vOut, pvIn, 0, vtOut)))
  2948. hr = VariantCopy (&vOut, pvIn);
  2949. }
  2950. break;
  2951. case wbemCimtypeUint32:
  2952. {
  2953. if (FAILED(hr = VariantChangeType (&vOut, pvIn, 0, vtOut)))
  2954. {
  2955. /*
  2956. * Watch for the case where we have been given a VT_R8
  2957. * in lieu of a "large" unsigned 32-bit integer value.
  2958. */
  2959. if (VT_R8 == V_VT(pvIn))
  2960. {
  2961. // Is this "really" an integer?
  2962. if (floor (pvIn->dblVal) == ceil(pvIn->dblVal))
  2963. {
  2964. // Fool it by casting to a UI4 - all we need is the bit pattern
  2965. if (SUCCEEDED(hr = VarUI4FromR8 (pvIn->dblVal, (ULONG*)&vOut.lVal)))
  2966. vOut.vt = VT_I4;
  2967. }
  2968. }
  2969. }
  2970. // If no joy thus far, just copy and have done with it
  2971. if (FAILED(hr))
  2972. hr = VariantCopy (&vOut, pvIn);
  2973. }
  2974. break;
  2975. case wbemCimtypeChar16:
  2976. case wbemCimtypeUint16:
  2977. {
  2978. /*
  2979. * These types are represented by
  2980. * a VT_I4, but we need to be careful about sign
  2981. * extension taking us "out of range".
  2982. */
  2983. if (SUCCEEDED(hr = VariantChangeType (&vOut, pvIn, 0, vtOut)))
  2984. {
  2985. // Did we get sign extended from a shorter type?
  2986. if ((VT_I2 == vtIn) || (VT_UI1 == vtIn) || (VT_BOOL == vtIn))
  2987. vOut.lVal &= 0x0000FFFF;
  2988. }
  2989. else
  2990. hr = VariantCopy (&vOut, pvIn);
  2991. }
  2992. break;
  2993. case wbemCimtypeObject:
  2994. {
  2995. /*
  2996. * We're looking for an embedded object
  2997. */
  2998. if (SUCCEEDED(hr = VariantCopy (&vOut, pvIn)))
  2999. hr = MapToCIMOMObject (&vOut);
  3000. }
  3001. break;
  3002. }
  3003. }
  3004. }
  3005. }
  3006. return hr;
  3007. }
  3008. //***************************************************************************
  3009. //
  3010. // HRESULT WmiConvertSafeArray
  3011. //
  3012. // Description:
  3013. //
  3014. // This function is applied to VARIANT arrays in order to check for certain
  3015. // restrictions imposed by CIMOM (e.g. they must be homogeneous) or perform
  3016. // conversions (certain VARIANT types have to be mapped to acceptable CIMOM
  3017. // types).
  3018. //
  3019. // Return Value:
  3020. // HRESULT S_OK if successful
  3021. //***************************************************************************
  3022. HRESULT WmiConvertSafeArray(VARIANT &vOut, SAFEARRAY *parray, CIMTYPE lCimType)
  3023. {
  3024. HRESULT hr = WBEM_E_FAILED;
  3025. VARTYPE vtPut; // The underlying type of the target array
  3026. long lLower, lUpper;
  3027. if (parray)
  3028. {
  3029. if (GetSafeArrayDimensions (*parray, lLower, lUpper))
  3030. {
  3031. int iNumElements = lUpper - lLower +1;
  3032. /*
  3033. * For empty arrays, it suffices to create a empty array of
  3034. * VT_VARIANT's. Otherwise we need to build what WMI is expecting.
  3035. */
  3036. vtPut = (iNumElements == 0) ? VT_VARIANT : CimTypeToVtType (lCimType);
  3037. // Now create a destination array of the required size
  3038. SAFEARRAYBOUND rgsabound[1];
  3039. rgsabound[0].lLbound = 0;
  3040. rgsabound[0].cElements = iNumElements;
  3041. SAFEARRAY * pDestArray = SafeArrayCreate(vtPut, 1, rgsabound);
  3042. if (pDestArray)
  3043. {
  3044. bool ok = true;
  3045. for(long i = lLower; (i <= lUpper) && ok; i++)
  3046. {
  3047. VARIANT var;
  3048. VariantInit(&var);
  3049. if (SUCCEEDED(SafeArrayGetElement (parray, &i, &var)))
  3050. {
  3051. // do the conversion to the acceptable type and put that
  3052. VARIANT vWMI;
  3053. VariantInit(&vWMI);
  3054. if (SUCCEEDED(hr = WmiVariantChangeType (vWMI, &var, lCimType)))
  3055. {
  3056. if(V_VT(&vWMI) == VT_BSTR || V_VT(&vWMI) == VT_UNKNOWN || V_VT(&vWMI) == VT_DISPATCH)
  3057. ok = (S_OK == SafeArrayPutElement(pDestArray, &i, (void *)vWMI.bstrVal));
  3058. else
  3059. ok = (S_OK == SafeArrayPutElement(pDestArray, &i, (void *)&vWMI.lVal));
  3060. }
  3061. VariantClear (&vWMI);
  3062. }
  3063. else
  3064. ok = false;
  3065. VariantClear(&var);
  3066. }
  3067. if (!ok)
  3068. {
  3069. SafeArrayDestroy (pDestArray);
  3070. }
  3071. else
  3072. {
  3073. vOut.vt = (VT_ARRAY | vtPut);
  3074. vOut.parray = pDestArray;
  3075. hr = S_OK;
  3076. }
  3077. }
  3078. else
  3079. hr = WBEM_E_OUT_OF_MEMORY;
  3080. }
  3081. }
  3082. return hr;
  3083. }
  3084. //***************************************************************************
  3085. //
  3086. // HRESULT WmiConvertDispatchArray
  3087. //
  3088. // DESCRIPTION:
  3089. //
  3090. // Attempt to convert from an IDispatch value to a CIM array value (property
  3091. // qualifier or context).
  3092. //
  3093. // PARAMETERS:
  3094. //
  3095. // pDest Output value
  3096. // pSrc Input value
  3097. // lCimType CIM Property type (underlying the array) - defaults to
  3098. // CIM_ILLEGAL for Qualifier & Context value mappings.
  3099. // bIsQual true iff we are mapping for a qualifier
  3100. //
  3101. // RETURN VALUES:
  3102. //
  3103. // WBEM_S_NO_ERROR success
  3104. // WBEM_E_FAILED otherwise
  3105. //
  3106. //***************************************************************************
  3107. HRESULT WmiConvertDispatchArray (
  3108. VARIANT &vOut,
  3109. CComPtr<IDispatch> & pIDispatch,
  3110. CIMTYPE lCimType
  3111. )
  3112. {
  3113. HRESULT hr = WBEM_E_FAILED; // Default error
  3114. if (pIDispatch)
  3115. {
  3116. /*
  3117. * Looking for an IDispatchEx to iterate through the properties
  3118. * of the array.
  3119. */
  3120. CComQIPtr<IDispatchEx> pIDispatchEx (pIDispatch);
  3121. if (pIDispatchEx)
  3122. {
  3123. /*
  3124. * Looks promising, but just check if this isn't one of our objects
  3125. */
  3126. CComQIPtr<ISWbemObject> pISWbemObject (pIDispatch);
  3127. if (!pISWbemObject)
  3128. {
  3129. /*
  3130. * Start by determining how many properties there are so we can create
  3131. * a suitable array.
  3132. */
  3133. long iNumElements = 0;
  3134. DISPID dispId = DISPID_STARTENUM;
  3135. while (S_OK == pIDispatchEx->GetNextDispID (fdexEnumAll, dispId, &dispId))
  3136. {
  3137. //We need to check this is a "real" array entry with an index rather than some "dummy" entry
  3138. //for some non-array properties (which can happen with JScript arrays)
  3139. BSTR memberName = NULL;
  3140. wchar_t *stopString=NULL;
  3141. if (SUCCEEDED(pIDispatchEx->GetMemberName (dispId, &memberName)))
  3142. {
  3143. // Check that property name is numeric, only if it is we count it for the array size
  3144. long index = wcstol (memberName, &stopString, 10);
  3145. if ((0 == wcslen (stopString)))
  3146. iNumElements++;
  3147. }
  3148. }
  3149. /*
  3150. * For empty arrays, it suffices to create a empty array of
  3151. * VT_VARIANT's. Otherwise we need to build what WMI is expecting.
  3152. */
  3153. VARTYPE vtPut = (iNumElements == 0) ? VT_VARIANT : CimTypeToVtType (lCimType);
  3154. // Create the safearray - note that it may be empty
  3155. SAFEARRAYBOUND rgsaBound;
  3156. rgsaBound.cElements = iNumElements;
  3157. rgsaBound.lLbound = 0;
  3158. SAFEARRAY *pDestArray = SafeArrayCreate (vtPut, 1, &rgsaBound);
  3159. if (pDestArray)
  3160. {
  3161. bool ok = true;
  3162. if (0 < iNumElements)
  3163. {
  3164. // Enumerate the DISPIDs on this interface
  3165. dispId = DISPID_STARTENUM;
  3166. DISPPARAMS dispParams;
  3167. dispParams.rgvarg = NULL;
  3168. dispParams.rgdispidNamedArgs = NULL;
  3169. dispParams.cArgs = 0;
  3170. dispParams.cNamedArgs = 0;
  3171. long nextExpectedIndex = 0;
  3172. HRESULT enumHr;
  3173. wchar_t *stopString = NULL;
  3174. /*
  3175. * For JScript arrays, the property names are the specified indices of the
  3176. * the array; these can be integer indices or they can be strings. We make
  3177. * the following requirements of the array indices:
  3178. *
  3179. * (1) All of the indices are non-negative integers
  3180. * (2) The indices start at 0 and are contiguous.
  3181. */
  3182. while (ok && SUCCEEDED(enumHr = pIDispatchEx->GetNextDispID (fdexEnumAll, dispId, &dispId)))
  3183. {
  3184. if (S_FALSE == enumHr)
  3185. {
  3186. // We have reached the end
  3187. break;
  3188. }
  3189. CComBSTR memberName;
  3190. if (SUCCEEDED(pIDispatchEx->GetMemberName (dispId, &memberName)))
  3191. {
  3192. // Check that property name is numeric
  3193. long i = wcstol (memberName, &stopString, 10);
  3194. if ((0 != wcslen (stopString)))
  3195. {
  3196. // Failure - cannot convert to integer
  3197. // Since JScript arrays may have additional "members" that are not real array members,
  3198. // depending on different properties that may be accessed on them, we should just
  3199. // ignore non-numeric items - instead of failing the whole thing...
  3200. continue;
  3201. }
  3202. else if (i != nextExpectedIndex)
  3203. {
  3204. // Failure - non-contiguous array
  3205. ok = false;
  3206. }
  3207. else
  3208. {
  3209. nextExpectedIndex++;
  3210. // Extract the property
  3211. VARIANT var;
  3212. VariantInit (&var);
  3213. if (SUCCEEDED (pIDispatchEx->InvokeEx (dispId, 0,
  3214. DISPATCH_PROPERTYGET, &dispParams, &var, NULL, NULL)))
  3215. {
  3216. // do the conversion to the acceptable type and put that
  3217. VARIANT vWMI;
  3218. VariantInit(&vWMI);
  3219. if (SUCCEEDED(hr = WmiVariantChangeType (vWMI, &var, lCimType)))
  3220. {
  3221. if(V_VT(&vWMI) == VT_BSTR || V_VT(&vWMI) == VT_UNKNOWN || V_VT(&vWMI) == VT_DISPATCH)
  3222. ok = (S_OK == SafeArrayPutElement(pDestArray, &i, (void *)vWMI.bstrVal));
  3223. else
  3224. ok = (S_OK == SafeArrayPutElement(pDestArray, &i, (void *)&vWMI.lVal));
  3225. }
  3226. VariantClear (&vWMI);
  3227. }
  3228. else
  3229. ok = false;
  3230. }
  3231. }
  3232. else
  3233. {
  3234. // Failure - couldn't invoke method
  3235. ok = false;
  3236. }
  3237. }
  3238. }
  3239. if (ok)
  3240. {
  3241. // Now construct the new property value using our array
  3242. vOut.vt = VT_ARRAY | vtPut;
  3243. vOut.parray = pDestArray;
  3244. hr = S_OK;
  3245. }
  3246. else
  3247. SafeArrayDestroy (pDestArray);
  3248. }
  3249. else
  3250. hr = WBEM_E_OUT_OF_MEMORY;
  3251. }
  3252. }
  3253. }
  3254. return hr;
  3255. }
  3256. bool GetSafeArrayDimensions (SAFEARRAY &sArray, long &lLower, long &lUpper)
  3257. {
  3258. bool result = false;
  3259. // Must be 1-dimensional
  3260. if (1 == SafeArrayGetDim(&sArray))
  3261. {
  3262. if (SUCCEEDED(SafeArrayGetLBound(&sArray,1,&lLower)) &&
  3263. SUCCEEDED(SafeArrayGetUBound(&sArray,1,&lUpper)))
  3264. result = true;
  3265. }
  3266. return result;
  3267. }