Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1803 lines
47 KiB

  1. //***************************************************************************
  2. //
  3. // Copyright (c) 1998-2000 Microsoft Corporation.
  4. //
  5. // File: cwbemdsp.cpp
  6. //
  7. // Description :
  8. // Implementation of the IDispatch interface for Wbem Objects.
  9. // This is mostly standard, except for the additional support for
  10. // specifying the name of a Wbem class property/method directly as if it
  11. // was a property/method of the actual CWbemObject class ("dot notation")
  12. //
  13. // Part of : WBEM automation interface layer
  14. //
  15. // History:
  16. // corinaf 4/3/98 Created
  17. //
  18. //***************************************************************************
  19. #include "precomp.h"
  20. const unsigned long CWbemDispID::s_wmiDispIdTypeMask = 0x03000000;
  21. const unsigned long CWbemDispID::s_wmiDispIdTypeStatic = 0x00000000;
  22. const unsigned long CWbemDispID::s_wmiDispIdTypeSchema = 0x01000000;
  23. const unsigned long CWbemDispID::s_wmiDispIdSchemaTypeMask = 0x00800000;
  24. const unsigned long CWbemDispID::s_wmiDispIdSchemaTypeProperty = 0x00800000;
  25. const unsigned long CWbemDispID::s_wmiDispIdSchemaTypeMethod = 0x00000000;
  26. const unsigned long CWbemDispID::s_wmiDispIdSchemaElementIDMask = 0x007FFFFF;
  27. //Forward declaration
  28. HRESULT assignArrayElementToVariant(SAFEARRAY *psa, VARTYPE vt, long inx, VARIANT *pvResult);
  29. void assignVariantToArrayElement(SAFEARRAY *psa, VARTYPE vt, long inx, VARIANT *pvNewVal);
  30. VARTYPE CimTypeToVtType(CIMTYPE lType);
  31. HRESULT VariantChangeByValToByRef(VARIANT *dest, VARIANT *source, VARTYPE destType);
  32. class CWbemSchemaIDCache
  33. {
  34. private:
  35. typedef map<CComBSTR, CWbemDispID, BSTRless> DispIDNameMap;
  36. unsigned long m_nextId;
  37. DispIDNameMap m_cache;
  38. CWbemDispatchMgr *m_pDispatchMgr;
  39. bool FindPropertyName (BSTR bsName);
  40. bool GetMethod (BSTR bstrMethodName, SAFEARRAY **ppsaInParams, SAFEARRAY **ppsaOutParams,
  41. CComPtr<IWbemClassObject> & pInParams, CComPtr<IWbemClassObject> & pOutParams);
  42. bool GetIdOfMethodParameter(BSTR bstrParamName, CComPtr<IWbemClassObject> & pParams, long *pId);
  43. static bool FindMemberInArray(BSTR bstrName, SAFEARRAY *psaNames);
  44. public:
  45. CWbemSchemaIDCache (CWbemDispatchMgr *pDispMgr) :
  46. m_nextId (0),
  47. m_pDispatchMgr (pDispMgr) {}
  48. virtual ~CWbemSchemaIDCache ();
  49. HRESULT GetDispID (LPWSTR FAR* rgszNames, unsigned int cNames, DISPID FAR* rgdispid);
  50. bool GetName (DISPID dispId, CComBSTR & bsName);
  51. };
  52. CWbemDispatchMgr::CWbemDispatchMgr(CSWbemServices *pWbemServices,
  53. CSWbemObject *pSWbemObject) :
  54. m_pWbemServices (pWbemServices),
  55. m_pSWbemObject (pSWbemObject), // Backpointer to parent (not AddRef'd)
  56. m_pWbemClass (NULL),
  57. m_pTypeInfo (NULL),
  58. m_pCTypeInfo (NULL),
  59. m_hResult (S_OK)
  60. {
  61. m_pSchemaCache = new CWbemSchemaIDCache (this);
  62. if (m_pWbemServices)
  63. m_pWbemServices->AddRef ();
  64. m_pWbemObject = pSWbemObject->GetIWbemClassObject ();
  65. }
  66. CWbemDispatchMgr::~CWbemDispatchMgr()
  67. {
  68. RELEASEANDNULL(m_pWbemServices)
  69. RELEASEANDNULL(m_pWbemObject)
  70. RELEASEANDNULL(m_pWbemClass)
  71. RELEASEANDNULL(m_pTypeInfo)
  72. RELEASEANDNULL(m_pCTypeInfo)
  73. DELETEANDNULL(m_pSchemaCache)
  74. }
  75. void CWbemDispatchMgr::SetNewObject (IWbemClassObject *pNewObject)
  76. {
  77. if (m_pWbemObject && pNewObject)
  78. {
  79. m_pWbemObject->Release ();
  80. m_pWbemObject = pNewObject;
  81. m_pWbemObject->AddRef ();
  82. CComVariant var;
  83. if (SUCCEEDED(pNewObject->Get (WBEMS_SP_GENUS, 0, &var, NULL, NULL)) &&
  84. (WBEM_GENUS_CLASS == var.lVal))
  85. {
  86. // This is a class, so update the class object too
  87. if (m_pWbemClass)
  88. m_pWbemClass->Release ();
  89. m_pWbemClass = pNewObject;
  90. m_pWbemClass->AddRef ();
  91. }
  92. // Clear out the caches
  93. if (m_pSchemaCache)
  94. {
  95. delete m_pSchemaCache;
  96. m_pSchemaCache = new CWbemSchemaIDCache (this);
  97. }
  98. }
  99. }
  100. STDMETHODIMP
  101. CWbemDispatchMgr::GetTypeInfoCount(unsigned int FAR* pctinfo)
  102. {
  103. *pctinfo = 1;
  104. return NOERROR;
  105. }
  106. STDMETHODIMP CWbemDispatchMgr::GetTypeInfo(unsigned int itinfo,
  107. LCID lcid,
  108. ITypeInfo FAR* FAR* pptinfo)
  109. {
  110. HRESULT hr;
  111. ITypeLib *pTypeLib = NULL;
  112. //If Type Info is not cached already - load the library and
  113. //get the Type Info, then cache it for further access
  114. if (!m_pTypeInfo)
  115. {
  116. // Load Type Library.
  117. hr = LoadRegTypeLib(LIBID_WbemScripting, 1, 0, lcid, &pTypeLib);
  118. if (FAILED(hr))
  119. {
  120. // if it wasn't registered, try to load it from the path
  121. // if this succeeds, it will have registered the type library for us
  122. // for the next time.
  123. hr = LoadTypeLib(OLESTR("wbemdisp.tlb"), &pTypeLib);
  124. if(FAILED(hr))
  125. return hr;
  126. }
  127. // Get type information for interface of the object.
  128. hr = pTypeLib->GetTypeInfoOfGuid(IID_ISWbemObjectEx, &m_pTypeInfo);
  129. pTypeLib->Release();
  130. if (FAILED(hr))
  131. return hr;
  132. }
  133. //AddRef whenever returning another pointer to this
  134. m_pTypeInfo->AddRef();
  135. *pptinfo = m_pTypeInfo;
  136. return NOERROR;
  137. }
  138. STDMETHODIMP CWbemDispatchMgr::GetClassInfo(ITypeInfo FAR* FAR* pptinfo)
  139. {
  140. HRESULT hr;
  141. ITypeLib *pTypeLib = NULL;
  142. //If Type Info is not cached already - load the library and
  143. //get the Type Info, then cache it for further access
  144. if (!m_pCTypeInfo)
  145. {
  146. // Load Type Library.
  147. hr = LoadRegTypeLib(LIBID_WbemScripting, 1, 0, 0, &pTypeLib);
  148. if (FAILED(hr))
  149. {
  150. // if it wasn't registered, try to load it from the path
  151. // if this succeeds, it will have registered the type library for us
  152. // for the next time.
  153. hr = LoadTypeLib(OLESTR("wbemdisp.tlb"), &pTypeLib);
  154. if(FAILED(hr))
  155. return hr;
  156. }
  157. // Get type information for coclass of the object.
  158. hr = pTypeLib->GetTypeInfoOfGuid(CLSID_SWbemObjectEx, &m_pCTypeInfo);
  159. pTypeLib->Release();
  160. if (FAILED(hr))
  161. return hr;
  162. }
  163. //AddRef whenever returning another pointer to this
  164. m_pCTypeInfo->AddRef();
  165. *pptinfo = m_pCTypeInfo;
  166. return NOERROR;
  167. }
  168. STDMETHODIMP
  169. CWbemDispatchMgr::GetIDsOfNames(REFIID iid, //always IID_NULL
  170. LPWSTR FAR* rgszNames,
  171. unsigned int cNames,
  172. LCID lcid,
  173. DISPID FAR* rgdispid)
  174. {
  175. HRESULT hr = E_FAIL;
  176. CComPtr<ITypeInfo> pITypeInfo;
  177. if (SUCCEEDED(hr = GetTypeInfo(0, lcid, &pITypeInfo)))
  178. {
  179. // See if this is a static property or method
  180. if (FAILED(hr = DispGetIDsOfNames(pITypeInfo,
  181. rgszNames,
  182. cNames,
  183. rgdispid)))
  184. {
  185. // Not static - try schema
  186. if (m_pSchemaCache && FAILED(hr = m_pSchemaCache->GetDispID (rgszNames, cNames, rgdispid)))
  187. {
  188. rgdispid[0] = DISPID_UNKNOWN;
  189. hr = DISP_E_UNKNOWNNAME;
  190. }
  191. }
  192. }
  193. return hr;
  194. }
  195. STDMETHODIMP CWbemDispatchMgr::Invoke(DISPID dispidMember,
  196. REFIID iid, LCID lcid,
  197. unsigned short wFlags,
  198. DISPPARAMS FAR* pdispparams,
  199. VARIANT FAR* pvarResult,
  200. EXCEPINFO FAR* pexcepinfo,
  201. unsigned int FAR* puArgErr)
  202. {
  203. HRESULT hr;
  204. ITypeInfo *pTypeInfo = NULL;
  205. //Get the type info
  206. hr = GetTypeInfo(0, lcid, &pTypeInfo);
  207. if (FAILED(hr))
  208. return hr;
  209. m_hResult = S_OK;
  210. CWbemDispID dispId (dispidMember);
  211. // Is this a regular dispId
  212. if (dispId.IsStatic ())
  213. {
  214. // Check for inbound NULLs masquerading as defaulted parameters
  215. if (wFlags & DISPATCH_METHOD)
  216. MapNulls (pdispparams);
  217. hr = DispInvoke((IDispatch *) ((ISWbemObjectEx *)m_pSWbemObject),
  218. pTypeInfo,
  219. dispidMember,
  220. wFlags,
  221. pdispparams,
  222. pvarResult,
  223. pexcepinfo,
  224. puArgErr
  225. );
  226. if (FAILED(hr))
  227. {
  228. // Try the error handler for this object in case it can handle this
  229. hr = HandleError (dispidMember, wFlags, pdispparams, pvarResult, puArgErr, hr);
  230. }
  231. }
  232. else if (dispId.IsSchema ())
  233. {
  234. //Otherwise - this is a WBEM property or method, so we implement
  235. //the invocation ourselves...
  236. ResetLastErrors ();
  237. if (dispId.IsSchemaMethod ()) //WBEM method
  238. hr = InvokeWbemMethod(dispidMember,
  239. pdispparams,
  240. pvarResult);
  241. else if (dispId.IsSchemaProperty ()) //WBEM property
  242. hr = InvokeWbemProperty(dispidMember,
  243. wFlags,
  244. pdispparams,
  245. pvarResult,
  246. pexcepinfo,
  247. puArgErr);
  248. else
  249. hr = DISP_E_MEMBERNOTFOUND;
  250. if (FAILED(hr))
  251. RaiseException (hr);
  252. }
  253. if (FAILED (m_hResult))
  254. {
  255. if (NULL != pexcepinfo)
  256. SetException (pexcepinfo, m_hResult, L"SWbemObjectEx");
  257. hr = DISP_E_EXCEPTION;
  258. }
  259. if (pTypeInfo)
  260. pTypeInfo->Release();
  261. return hr;
  262. }
  263. HRESULT
  264. CWbemDispatchMgr::InvokeWbemProperty(DISPID dispid,
  265. unsigned short wFlags,
  266. DISPPARAMS FAR* pdispparams,
  267. VARIANT FAR* pvarResult,
  268. EXCEPINFO FAR* pexcepinfo,
  269. unsigned int FAR* puArgErr)
  270. {
  271. HRESULT hr = E_FAIL;
  272. if (m_pSchemaCache)
  273. {
  274. BOOL bIsGetOperation = (DISPATCH_PROPERTYGET & wFlags);
  275. if (bIsGetOperation)
  276. {
  277. //Check that the output parameter is valid
  278. if (pvarResult == NULL)
  279. return E_INVALIDARG;
  280. }
  281. else
  282. {
  283. //Check input parameters
  284. if ((pdispparams->cArgs < 1) || (pdispparams->cArgs > 2))
  285. return DISP_E_BADPARAMCOUNT;
  286. if ((pdispparams->cNamedArgs != 1) ||
  287. (pdispparams->cNamedArgs == 1 &&
  288. pdispparams->rgdispidNamedArgs[0] != DISPID_PROPERTYPUT))
  289. return DISP_E_PARAMNOTOPTIONAL;
  290. }
  291. //For both get & put, we need to first get the property
  292. // (for put we need to validate the syntax)
  293. CComBSTR bsPropertyName;
  294. if (m_pSchemaCache->GetName (dispid, bsPropertyName))
  295. {
  296. SAFEARRAY *psaNames = NULL;
  297. long inx;
  298. VARIANT vPropVal;
  299. long lArrayPropInx;
  300. CIMTYPE lPropType;
  301. //Get the value of this property
  302. //-------------------------------------
  303. VariantInit(&vPropVal);
  304. if (FAILED (hr = m_pWbemObject->Get(bsPropertyName, 0, &vPropVal, &lPropType, NULL)))
  305. {
  306. return hr;
  307. }
  308. // The expected VT type for the proposed property value
  309. VARTYPE expectedVarType = CimTypeToVtType (lPropType & ~CIM_FLAG_ARRAY);
  310. //If we are in a get operation
  311. //----------------------------------
  312. if (bIsGetOperation)
  313. {
  314. //If the property is an embedded object, we might need to convert it from
  315. //a VT_UNKNOWN to a VT_DISPATCH
  316. if (SUCCEEDED(hr = MapFromCIMOMObject(m_pWbemServices, &vPropVal,
  317. m_pSWbemObject, bsPropertyName)))
  318. {
  319. //If the property is an array, need to check for index and get that element
  320. if ((lPropType & CIM_FLAG_ARRAY) && (pdispparams->cArgs > 0))
  321. {
  322. //Note: currently we support single dimension arrays only, so we only
  323. // look for one index
  324. VARIANT indexVar;
  325. VariantInit (&indexVar);
  326. // Attempt to coerce the index argument into a value suitable for an array index
  327. if (S_OK == VariantChangeType (&indexVar, &pdispparams->rgvarg[0], 0, VT_I4))
  328. {
  329. lArrayPropInx = V_I4(&indexVar);
  330. //Fill in the result variant with the requested array element
  331. hr = assignArrayElementToVariant(vPropVal.parray, (V_VT(&vPropVal) & ~VT_ARRAY),
  332. lArrayPropInx, pvarResult);
  333. }
  334. else
  335. hr = DISP_E_TYPEMISMATCH;
  336. VariantClear (&indexVar);
  337. }
  338. else //If it's not an array index - copy to output param and we're done
  339. {
  340. // Check if it's an array value and convert as necessary
  341. if (V_ISARRAY(&vPropVal))
  342. hr = ConvertArrayRev(pvarResult, &vPropVal);
  343. else
  344. hr = VariantCopy (pvarResult, &vPropVal);
  345. }
  346. }
  347. } //Property Get
  348. //Otherwise (put operation)
  349. //---------------------------------
  350. else
  351. {
  352. /*
  353. * Need to translate this into a call to SWbemProperty.put_Value: easiest way
  354. * to do this is to
  355. * (A) get the SWbemProperty object for this property
  356. * (B) Call IDispatch::Invoke on that object, passing in the value
  357. * This way we get the error handling behavior too.
  358. */
  359. CComPtr<ISWbemPropertySet> pISWbemPropertySet;
  360. if (SUCCEEDED(hr = m_pSWbemObject->get_Properties_ (&pISWbemPropertySet)))
  361. {
  362. CComPtr<ISWbemProperty> pISWbemProperty;
  363. if (SUCCEEDED(hr = pISWbemPropertySet->Item (bsPropertyName, 0, &pISWbemProperty)))
  364. {
  365. // NB: The Value property of ISWbemProperty is the "default" automation property
  366. hr = pISWbemProperty->Invoke (
  367. DISPID_VALUE,
  368. IID_NULL,
  369. 0,
  370. wFlags,
  371. pdispparams,
  372. pvarResult,
  373. pexcepinfo,
  374. puArgErr);
  375. // Use our more specific error here if we have one
  376. if (FAILED(hr) && pexcepinfo)
  377. hr = pexcepinfo->scode;
  378. }
  379. }
  380. } //Property Put
  381. VariantClear(&vPropVal);
  382. }
  383. }
  384. return hr;
  385. }
  386. //***************************************************************************
  387. //
  388. // SCODE CWbemDispatchMgr::InvokeWbemMethod
  389. //
  390. // DESCRIPTION:
  391. //
  392. // Invoke the method via direct access.
  393. //
  394. // PARAMETERS:
  395. //
  396. // dispid The dispid od the method
  397. // pdispparams Pointer to DISPPARAMS for this invocation
  398. // pvarResult On successful return holds return value (if any)
  399. //
  400. // RETURN VALUES:
  401. //
  402. //***************************************************************************
  403. HRESULT CWbemDispatchMgr::InvokeWbemMethod(
  404. DISPID dispid,
  405. DISPPARAMS FAR* pdispparams,
  406. VARIANT FAR* pvarResult
  407. )
  408. {
  409. HRESULT hr = E_FAIL;
  410. if (m_pWbemServices && m_pSchemaCache)
  411. {
  412. //Currently we don't support named arguments
  413. if (pdispparams->cNamedArgs > 0)
  414. return DISP_E_NONAMEDARGS;
  415. //Map the dispid to a method name
  416. CComBSTR bsMethodName;
  417. if (m_pSchemaCache->GetName (dispid, bsMethodName))
  418. {
  419. // Build up the inparameters (if any)
  420. CComPtr<IWbemClassObject> pInParameters;
  421. CComPtr<IWbemClassObject> pOutParameters;
  422. //Get the input parameters object of the method (may be NULL)
  423. if (SUCCEEDED (hr = m_pWbemClass->GetMethod(bsMethodName, 0, &pInParameters,
  424. &pOutParameters)))
  425. {
  426. CComPtr<IWbemClassObject> pInParamsInstance;
  427. if (pInParameters)
  428. hr = MapInParameters (pdispparams, pInParameters, &pInParamsInstance);
  429. if (SUCCEEDED (hr))
  430. {
  431. CComPtr<IWbemServices> pService = m_pWbemServices->GetIWbemServices ();
  432. if (pService)
  433. {
  434. // Need the RELPATH to specify the target class or instance
  435. VARIANT vObjectPathVal;
  436. VariantInit(&vObjectPathVal);
  437. if (SUCCEEDED (hr = m_pWbemObject->Get
  438. (WBEMS_SP_RELPATH, 0, &vObjectPathVal, NULL, NULL)))
  439. {
  440. /*
  441. * If a "keyless" object slips through the net its __RELPATH
  442. * value will be VT_NULL. At this point we should fail gracefully.
  443. */
  444. if (VT_BSTR == V_VT(&vObjectPathVal))
  445. {
  446. // Execute the CIMOM method
  447. CComPtr<IWbemClassObject> pOutParamsInstance;
  448. bool needToResetSecurity = false;
  449. HANDLE hThreadToken = NULL;
  450. CSWbemSecurity *pSecurityInfo = m_pWbemServices->GetSecurityInfo ();
  451. if (pSecurityInfo && pSecurityInfo->SetSecurity (needToResetSecurity, hThreadToken))
  452. {
  453. if (SUCCEEDED(hr = pService->ExecMethod(V_BSTR(&vObjectPathVal),
  454. bsMethodName, 0, NULL,
  455. pInParamsInstance, &pOutParamsInstance, NULL)))
  456. hr = MapOutParameters (pdispparams, pOutParameters,
  457. pOutParamsInstance, pvarResult);
  458. SetWbemError (m_pWbemServices);
  459. }
  460. if (pSecurityInfo)
  461. {
  462. // Restore original privileges on this thread
  463. if (needToResetSecurity)
  464. pSecurityInfo->ResetSecurity (hThreadToken);
  465. pSecurityInfo->Release ();
  466. }
  467. }
  468. else
  469. hr = WBEM_E_FAILED;
  470. }
  471. VariantClear (&vObjectPathVal);
  472. }
  473. }
  474. }
  475. }
  476. }
  477. return hr;
  478. }
  479. //***************************************************************************
  480. //
  481. // SCODE CWbemDispatchMgr::MapOutParameters
  482. //
  483. // DESCRIPTION:
  484. //
  485. // Invoke the method via direct access.
  486. //
  487. // PARAMETERS:
  488. //
  489. // dispparams Pointer to DISPPARAMS for this invocation
  490. // pOutParameters Class template for out parameters
  491. // pOutParamsInstance Addresses the IWbemClassObject to hold the
  492. // out parameters (if any) - may be NULL
  493. // pvarResult On successful return holds return value (if any)
  494. //
  495. // RETURN VALUES:
  496. //
  497. //***************************************************************************
  498. HRESULT CWbemDispatchMgr::MapOutParameters (
  499. DISPPARAMS FAR* pdispparams,
  500. IWbemClassObject *pOutParameters,
  501. IWbemClassObject *pOutParamsInstance,
  502. VARIANT FAR* pvarResult
  503. )
  504. {
  505. HRESULT hr = S_OK;
  506. //For each "out" parameter in the output parameters object (if there is one),
  507. //find it's id, then look for the parameter with this id in the arguments array
  508. //and set the return parameter value accordingly
  509. //----------------------------------------------------------------------------
  510. if (pOutParameters && pOutParamsInstance)
  511. {
  512. //Start an enumeration through the "out" parameters class template
  513. if (SUCCEEDED (hr = pOutParameters->BeginEnumeration(WBEM_FLAG_NONSYSTEM_ONLY)))
  514. {
  515. BSTR bstrId = SysAllocString(L"id");
  516. BSTR bstrParamName = NULL;
  517. /*
  518. * For each property in the outparams class template, get the [id]
  519. * to map the relevant posistional value in the pdispparams.
  520. */
  521. while (WBEM_S_NO_ERROR ==
  522. (hr != pOutParameters->Next(0, &bstrParamName, NULL, NULL, NULL)))
  523. {
  524. // Get the returned parameter value from the instance
  525. VARIANT vParamVal;
  526. VariantInit(&vParamVal);
  527. if (SUCCEEDED (pOutParamsInstance->Get (bstrParamName, 0, &vParamVal, NULL, NULL)))
  528. {
  529. //If this is the return value, set it separately
  530. if (!_wcsicmp(bstrParamName, L"ReturnValue"))
  531. {
  532. if (pvarResult)
  533. hr = MapReturnValue (pvarResult, &vParamVal);
  534. }
  535. //Otherwise - regular out parameter
  536. else
  537. {
  538. IWbemQualifierSet *pQualSet = NULL;
  539. //Get the id of this parameter (it's the "id" qualifier)
  540. if (SUCCEEDED (hr = pOutParameters->GetPropertyQualifierSet
  541. (bstrParamName, &pQualSet)))
  542. {
  543. VARIANT vIdVal;
  544. VariantInit(&vIdVal);
  545. if (SUCCEEDED (hr = pQualSet->Get(bstrId, 0, &vIdVal, NULL)))
  546. {
  547. //Calculate the position of this id in the arguments array
  548. long pos = (pdispparams->cArgs - 1) - V_I4(&vIdVal);
  549. // If its out of range, too bad
  550. if ((0 <= pos) && (pos < (long) pdispparams->cArgs))
  551. hr = MapOutParameter (&pdispparams->rgvarg[pos], &vParamVal);
  552. }
  553. VariantClear(&vIdVal);
  554. pQualSet->Release();
  555. }
  556. }
  557. }
  558. VariantClear (&vParamVal);
  559. SysFreeString (bstrParamName);
  560. bstrParamName = NULL;
  561. } //while
  562. SysFreeString (bstrId);
  563. }
  564. } //if pOutParameters
  565. return hr;
  566. }
  567. //***************************************************************************
  568. //
  569. // SCODE CWbemDispatchMgr::MapReturnValue
  570. //
  571. // DESCRIPTION:
  572. //
  573. // Map the method return value
  574. //
  575. // PARAMETERS:
  576. //
  577. // pDest On successful return holds return value (if any)
  578. // pSrc The variant value to map
  579. //
  580. //
  581. // RETURN VALUES:
  582. //
  583. //***************************************************************************
  584. HRESULT CWbemDispatchMgr::MapReturnValue (
  585. VARIANT FAR* pDest,
  586. VARIANT FAR* pSrc
  587. )
  588. {
  589. HRESULT hr = S_OK;
  590. //If the return value is a VT_UNKNOWN, we need to wrap into a
  591. //VT_DISPATCH before passing it back
  592. if (SUCCEEDED (hr = MapFromCIMOMObject(m_pWbemServices, pSrc)))
  593. {
  594. // Handle arrays correctly (must always be VT_ARRAY|VT_VARIANT)
  595. if(V_VT(pSrc) & VT_ARRAY)
  596. hr = ConvertArrayRev(pDest, pSrc);
  597. else
  598. hr = VariantCopy (pDest, pSrc);
  599. }
  600. return hr;
  601. }
  602. //***************************************************************************
  603. //
  604. // SCODE CWbemDispatchMgr::MapOutParameter
  605. //
  606. // DESCRIPTION:
  607. //
  608. // Map a (possibly by reference) out parameter
  609. //
  610. // PARAMETERS:
  611. //
  612. // pDest On successful return holds return value (if any)
  613. // pVal The variant value to map
  614. //
  615. //
  616. // RETURN VALUES:
  617. //
  618. //***************************************************************************
  619. HRESULT CWbemDispatchMgr::MapOutParameter (
  620. VARIANT FAR* pDest,
  621. VARIANT FAR* pSrc
  622. )
  623. {
  624. HRESULT hr = S_OK;
  625. //If the return value is a VT_UNKNOWN, we need to wrap into a
  626. //VT_DISPATCH before passing it back
  627. if (SUCCEEDED (hr = MapFromCIMOMObject(m_pWbemServices, pSrc)))
  628. {
  629. VARIANT tempVal;
  630. VariantInit (&tempVal);
  631. // Handle arrays correctly (must always be VT_ARRAY|VT_VARIANT)
  632. if(V_VT(pSrc) & VT_ARRAY)
  633. hr = ConvertArrayRev(&tempVal, pSrc);
  634. else
  635. hr = VariantCopy (&tempVal, pSrc);
  636. // Finally take care of ensuring we produce BYREFs if necessary
  637. if (SUCCEEDED (hr))
  638. hr = VariantChangeByValToByRef(pDest, &tempVal, V_VT(pDest));
  639. VariantClear (&tempVal);
  640. }
  641. return hr;
  642. }
  643. //***************************************************************************
  644. //
  645. // SCODE CWbemDispatchMgr::MapInParameters
  646. //
  647. // DESCRIPTION:
  648. //
  649. // Map the in parameters to a method
  650. //
  651. // PARAMETERS:
  652. //
  653. // pdispparams DISPPARAMS containing the in parameters
  654. // pInParameters Class template for method input parameters
  655. // ppInParamsInstance On successful return holds the mapped parameters
  656. //
  657. // RETURN VALUES:
  658. //
  659. //***************************************************************************
  660. HRESULT CWbemDispatchMgr::MapInParameters (
  661. DISPPARAMS FAR* pdispparams,
  662. IWbemClassObject *pInParameters,
  663. IWbemClassObject **ppInParamsInstance
  664. )
  665. {
  666. HRESULT hr = S_OK;
  667. *ppInParamsInstance = NULL;
  668. //Spawn an instance to fill in with values
  669. if (SUCCEEDED (hr = pInParameters->SpawnInstance(0, ppInParamsInstance)))
  670. {
  671. /*
  672. * Iterate through the "in" parameters object properties in the class to find the
  673. * ID positional qualifier. Note we do this in the InParams class rather than
  674. * the spawned instance to protect ourselves against the case where the [id]
  675. * qualifier has been declared without the "propagate to instance" flavor setting,
  676. */
  677. if (SUCCEEDED (hr = pInParameters->BeginEnumeration(WBEM_FLAG_NONSYSTEM_ONLY)))
  678. {
  679. BSTR bstrParamName = NULL;
  680. BSTR bstrId = SysAllocString(L"id");
  681. CIMTYPE lType;
  682. //For each property in the inparams object
  683. while (WBEM_S_NO_ERROR ==
  684. (hr = pInParameters->Next(0, &bstrParamName, NULL, &lType, NULL)))
  685. {
  686. IWbemQualifierSet *pQualSet = NULL;
  687. //Get the id of this parameter (it's the "id" qualifier)
  688. if (SUCCEEDED(hr =
  689. pInParameters->GetPropertyQualifierSet(bstrParamName, &pQualSet)))
  690. {
  691. VARIANT vIdVal;
  692. VariantInit(&vIdVal);
  693. if (SUCCEEDED(hr = pQualSet->Get(bstrId, 0, &vIdVal, NULL)))
  694. {
  695. //Calculate the position of this id in the arguments array
  696. long pos = (pdispparams->cArgs - 1) - V_I4(&vIdVal);
  697. // If no argument specified, we won't set it in ppInParamsInstance
  698. // and just assume it will be defaulted
  699. if ((0 <= pos) && (pos < (long) pdispparams->cArgs))
  700. {
  701. VARIANT vParamVal;
  702. VariantInit (&vParamVal);
  703. if (SUCCEEDED (hr = MapInParameter
  704. (&vParamVal, &pdispparams->rgvarg[pos], lType)))
  705. {
  706. // If we have a VT_ERROR with DISP_E_PARAMNOTFOUND this
  707. // is a "missing" parameter - we just fail to set it and
  708. // let it default in the instance
  709. if ((VT_ERROR == V_VT(&vParamVal)) && (DISP_E_PARAMNOTFOUND == vParamVal.scode))
  710. {
  711. // Let it default
  712. }
  713. else
  714. {
  715. //Copy the value for this parameter from the argument array
  716. //into the inparamsinstance object property
  717. hr = (*ppInParamsInstance)->Put(bstrParamName, 0, &vParamVal, NULL);
  718. }
  719. }
  720. VariantClear (&vParamVal);
  721. }
  722. }
  723. VariantClear(&vIdVal);
  724. pQualSet->Release();
  725. pQualSet = NULL;
  726. }
  727. SysFreeString (bstrParamName);
  728. bstrParamName = NULL;
  729. if (FAILED(hr))
  730. break;
  731. } //while
  732. SysFreeString (bstrId);
  733. }
  734. }
  735. return hr;
  736. }
  737. //***************************************************************************
  738. //
  739. // SCODE CWbemDispatchMgr::MapInParameter
  740. //
  741. // DESCRIPTION:
  742. //
  743. // Map a in parameter
  744. //
  745. // PARAMETERS:
  746. //
  747. // pDest On successful return holds return value
  748. // pVal The variant value to map
  749. // lType CIMTYPE of target property value
  750. //
  751. //
  752. // RETURN VALUES:
  753. //
  754. //***************************************************************************
  755. HRESULT CWbemDispatchMgr::MapInParameter (
  756. VARIANT FAR* pDest,
  757. VARIANT FAR* pSrc,
  758. CIMTYPE lType
  759. )
  760. {
  761. HRESULT hr = S_OK;
  762. if ((NULL == pSrc) || (VT_EMPTY == V_VT(pSrc))
  763. || (VT_NULL == V_VT(pSrc)))
  764. {
  765. // Map all of these to a VT_NULL
  766. pDest->vt = VT_NULL;
  767. }
  768. else if (((VT_ARRAY | VT_VARIANT) == V_VT(pSrc)) ||
  769. ((VT_ARRAY | VT_VARIANT | VT_BYREF) == V_VT(pSrc)))
  770. {
  771. // Arrays need to be mapped "down" to their raw form (and watch out
  772. // for embedded objects!)
  773. if (SUCCEEDED(hr = ConvertArray(pDest, pSrc)))
  774. hr = MapToCIMOMObject(pDest);
  775. }
  776. else if ((CIM_FLAG_ARRAY & lType) &&
  777. ((VT_DISPATCH == V_VT(pSrc))
  778. || ((VT_DISPATCH|VT_BYREF) == V_VT(pSrc))))
  779. {
  780. // Look for a JScript-style IDispatch that needs to be mapped to an array
  781. hr = ConvertDispatchToArray (pDest, pSrc, lType & ~CIM_FLAG_ARRAY);
  782. }
  783. else if ((VT_BYREF | VT_VARIANT) == V_VT(pSrc))
  784. {
  785. // May be used if the scripting language supports functions that can change
  786. // the type of a reference. CIMOM won't do this, wo we unwrap the
  787. // variant before proceeding
  788. hr = MapInParameter (pDest, pSrc->pvarVal, lType);
  789. }
  790. else
  791. {
  792. // A "straightforward" value - all we have to watch for is an embedded object
  793. // and a possible byRef
  794. if (SUCCEEDED(hr = VariantCopy (pDest, pSrc)))
  795. {
  796. hr = MapToCIMOMObject(pDest);
  797. // Is it byref - if so remove the indirection
  798. if (VT_BYREF & V_VT(pDest))
  799. hr = VariantChangeType(pDest, pDest, 0, V_VT(pDest) & ~VT_BYREF);
  800. }
  801. }
  802. return hr;
  803. }
  804. //-------------------------------------------------------------
  805. // CWbemDispatchMgr::RaiseException
  806. //
  807. // Description : signal exception to automation client
  808. //
  809. // Parameters : hr - HRESULT
  810. //-------------------------------------------------------------
  811. void CWbemDispatchMgr::RaiseException (HRESULT hr)
  812. {
  813. // Store the HRESULT for processing in the Invoke routine
  814. m_hResult = hr;
  815. // Set a WMI scripting error on this thread for the client
  816. ICreateErrorInfo *pCreateErrorInfo = NULL;
  817. if (SUCCEEDED (CreateErrorInfo (&pCreateErrorInfo)))
  818. {
  819. BSTR bsDescr = MapHresultToWmiDescription (hr);
  820. pCreateErrorInfo->SetDescription (bsDescr);
  821. SysFreeString (bsDescr);
  822. pCreateErrorInfo->SetGUID (IID_ISWbemObjectEx);
  823. pCreateErrorInfo->SetSource (L"SWbemObjectEx");
  824. IErrorInfo *pErrorInfo = NULL;
  825. if (SUCCEEDED (pCreateErrorInfo->QueryInterface(IID_IErrorInfo, (void**) &pErrorInfo)))
  826. {
  827. SetErrorInfo (0, pErrorInfo);
  828. pErrorInfo->Release ();
  829. }
  830. pCreateErrorInfo->Release ();
  831. }
  832. }
  833. //-------------------------------------------------------------
  834. // Name : assignArrayElementToVariant
  835. //
  836. // Description : According to the type of the array elements,
  837. // retrieves the requested element from the array
  838. // into a variant
  839. //
  840. // Parameters : psa - pointer to the SAFEARRAY
  841. // vt - vartype of array elements
  842. // inx - index of the element in the array
  843. // pvResult - resulting variant
  844. //-------------------------------------------------------------
  845. HRESULT assignArrayElementToVariant(SAFEARRAY *psa, VARTYPE vt, long inx, VARIANT *pvResult)
  846. {
  847. HRESULT hr = WBEM_S_NO_ERROR;
  848. switch (vt)
  849. {
  850. case VT_I2 :
  851. V_VT(pvResult) = VT_I2;
  852. SafeArrayGetElement(psa, &inx, &V_I2(pvResult));
  853. break;
  854. case VT_I4 :
  855. V_VT(pvResult) = VT_I4;
  856. SafeArrayGetElement(psa, &inx, &V_I4(pvResult));
  857. break;
  858. case VT_R4 :
  859. V_VT(pvResult) = VT_R4;
  860. SafeArrayGetElement(psa, &inx, &V_R4(pvResult));
  861. break;
  862. case VT_R8 :
  863. V_VT(pvResult) = VT_R8;
  864. SafeArrayGetElement(psa, &inx, &V_R8(pvResult));
  865. break;
  866. case VT_DATE :
  867. V_VT(pvResult) = VT_DATE;
  868. SafeArrayGetElement(psa, &inx, &V_DATE(pvResult));
  869. break;
  870. case VT_BSTR :
  871. V_VT(pvResult) = VT_BSTR;
  872. SafeArrayGetElement(psa, &inx, &V_BSTR(pvResult));
  873. break;
  874. case VT_DISPATCH :
  875. V_VT(pvResult) = VT_DISPATCH;
  876. SafeArrayGetElement(psa, &inx, &V_DISPATCH(pvResult));
  877. break;
  878. case VT_UNKNOWN :
  879. V_VT(pvResult) = VT_UNKNOWN;
  880. SafeArrayGetElement(psa, &inx, &V_UNKNOWN(pvResult));
  881. break;
  882. case VT_BOOL :
  883. V_VT(pvResult) = VT_BOOL;
  884. SafeArrayGetElement(psa, &inx, &V_BOOL(pvResult));
  885. break;
  886. case VT_VARIANT :
  887. {
  888. V_VT(pvResult) = VT_BYREF | VT_VARIANT;
  889. VARIANT *pVar = new VARIANT;
  890. if (pVar)
  891. {
  892. VariantInit (pVar);
  893. SafeArrayGetElement(psa, &inx, pVar);
  894. V_VARIANTREF(pvResult) = pVar;
  895. }
  896. else
  897. hr = WBEM_E_OUT_OF_MEMORY;
  898. }
  899. break;
  900. case VT_UI1 :
  901. V_VT(pvResult) = VT_UI1;
  902. SafeArrayGetElement(psa, &inx, &V_UI1(pvResult));
  903. break;
  904. default :
  905. V_VT(pvResult) = VT_ERROR;
  906. break;
  907. }
  908. return hr;
  909. }
  910. //-------------------------------------------------------------
  911. // Name : CheckArrayBounds
  912. //
  913. // Description : Check that index is within bounds and if not
  914. // Redim the array
  915. //
  916. // Parameters : psa - pointer to the SAFEARRAY
  917. // inx - putative index
  918. //-------------------------------------------------------------
  919. void CheckArrayBounds(SAFEARRAY *psa, long inx)
  920. {
  921. long lBound, uBound;
  922. SafeArrayGetUBound (psa, 1, &uBound);
  923. SafeArrayGetLBound (psa, 1, &lBound);
  924. if ((inx < lBound) || (inx > uBound))
  925. {
  926. // Need to redim
  927. SAFEARRAYBOUND psaBound;
  928. psaBound.cElements = ((inx < lBound) ?
  929. (uBound + 1 - inx) : (inx + 1 - lBound));
  930. psaBound.lLbound = (inx < lBound) ? inx : lBound;
  931. SafeArrayRedim (psa, &psaBound);
  932. }
  933. }
  934. //-------------------------------------------------------------
  935. // Name : assignVariantToArrayElement
  936. //
  937. // Description : According to the type of the array elements,
  938. // puts the new value from the variant into the
  939. // requested element of the array
  940. //
  941. // Parameters : psa - pointer to the SAFEARRAY
  942. // vt - vartype of array elements
  943. // inx - index of the element in the array
  944. // pvNewVal - variant containing the new value
  945. //-------------------------------------------------------------
  946. void assignVariantToArrayElement(SAFEARRAY *psa, VARTYPE vt, long inx, VARIANT *pvNewVal)
  947. {
  948. HRESULT hr = E_FAIL;
  949. // Firstly check for out-of-bounds case and grow accordingly
  950. CheckArrayBounds (psa, inx);
  951. switch (vt)
  952. {
  953. case VT_I2 :
  954. hr = SafeArrayPutElement(psa, &inx, &V_I2(pvNewVal));
  955. break;
  956. case VT_I4 :
  957. hr = SafeArrayPutElement(psa, &inx, &V_I4(pvNewVal));
  958. break;
  959. case VT_R4 :
  960. hr = SafeArrayPutElement(psa, &inx, &V_R4(pvNewVal));
  961. break;
  962. case VT_R8 :
  963. hr = SafeArrayPutElement(psa, &inx, &V_R8(pvNewVal));
  964. break;
  965. case VT_DATE :
  966. hr = SafeArrayPutElement(psa, &inx, &V_DATE(pvNewVal));
  967. break;
  968. case VT_BSTR :
  969. hr = SafeArrayPutElement(psa, &inx, V_BSTR(pvNewVal));
  970. break;
  971. case VT_DISPATCH :
  972. hr = SafeArrayPutElement(psa, &inx, V_DISPATCH(pvNewVal));
  973. break;
  974. case VT_UNKNOWN:
  975. hr = SafeArrayPutElement(psa, &inx, V_UNKNOWN(pvNewVal));
  976. break;
  977. case VT_BOOL :
  978. hr = SafeArrayPutElement(psa, &inx, &V_BOOL(pvNewVal));
  979. break;
  980. case VT_VARIANT :
  981. hr = SafeArrayPutElement(psa, &inx, V_VARIANTREF(pvNewVal));
  982. break;
  983. case VT_UI1 :
  984. hr = SafeArrayPutElement(psa, &inx, &V_UI1(pvNewVal));
  985. break;
  986. default :
  987. //????????????
  988. break;
  989. } //switch
  990. }
  991. //-------------------------------------------------------------
  992. // Name : CimTypeToVtType
  993. //
  994. // Description : Returns the coresponding VARTYPE for
  995. // a given CIMTYPE
  996. // Parameters : lType - the CIMTYPE we want to convert
  997. //-------------------------------------------------------------
  998. VARTYPE CimTypeToVtType(CIMTYPE lType)
  999. {
  1000. VARTYPE ret = VT_EMPTY;
  1001. if (lType & CIM_FLAG_ARRAY)
  1002. ret = VT_ARRAY;
  1003. switch(lType & ~CIM_FLAG_ARRAY)
  1004. {
  1005. case CIM_EMPTY : ret = (ret | VT_EMPTY); break;
  1006. case CIM_SINT8 : ret = (ret | VT_I2); break;
  1007. case CIM_UINT8 : ret = (ret | VT_UI1); break;
  1008. case CIM_SINT16 : ret = (ret | VT_I2); break;
  1009. case CIM_UINT16 : ret = (ret | VT_I4); break;
  1010. case CIM_SINT32 : ret = (ret | VT_I4); break;
  1011. case CIM_UINT32 : ret = (ret | VT_I4); break;
  1012. case CIM_SINT64 : ret = (ret | VT_BSTR); break;
  1013. case CIM_UINT64 : ret = (ret | VT_BSTR); break;
  1014. case CIM_REAL32 : ret = (ret | VT_R4); break;
  1015. case CIM_REAL64 : ret = (ret | VT_R8); break;
  1016. case CIM_BOOLEAN : ret = (ret | VT_BOOL); break;
  1017. case CIM_STRING : ret = (ret | VT_BSTR); break;
  1018. case CIM_DATETIME : ret = (ret | VT_BSTR); break;
  1019. case CIM_REFERENCE :ret = (ret | VT_BSTR); break;
  1020. case CIM_CHAR16 : ret = (ret | VT_I2); break;
  1021. case CIM_OBJECT : ret = (ret | VT_UNKNOWN); break;
  1022. default : ret = VT_ERROR;
  1023. }
  1024. return ret;
  1025. }
  1026. //-------------------------------------------------------------
  1027. // Name : VariantChangeByValToByRef
  1028. //
  1029. // Description : Copies a variant, while converting a "byval" to a
  1030. // "byref" if the destination type requires it
  1031. //
  1032. // Parameters : dest - destination variant to hold the result
  1033. // source - source variant to be copied
  1034. // destType - the VARTYPE required for the result.
  1035. // when this type is a BY_REF, the appropriate
  1036. // conversion is made from the source.
  1037. //-------------------------------------------------------------
  1038. HRESULT VariantChangeByValToByRef(VARIANT *dest, VARIANT *source, VARTYPE destType)
  1039. {
  1040. HRESULT hr = S_OK;
  1041. if (!(destType & VT_BYREF)) //the destination is not by ref. we can do a straight copy
  1042. hr = VariantCopy(dest, source);
  1043. else
  1044. {
  1045. if ((destType & ~VT_BYREF) & VT_ARRAY)
  1046. hr = SafeArrayCopy(V_ARRAY(source), V_ARRAYREF(dest));
  1047. else
  1048. {
  1049. switch (destType & ~VT_BYREF)
  1050. {
  1051. case VT_UI1 : *V_UI1REF(dest) = V_UI1(source); break;
  1052. case VT_I2 : *V_I2REF(dest) = V_I2(source); break;
  1053. case VT_I4 : *V_I4REF(dest) = V_I4(source); break;
  1054. case VT_R4 : *V_R4REF(dest) = V_R4(source); break;
  1055. case VT_R8 : *V_R8REF(dest) = V_R8(source); break;
  1056. case VT_CY : *V_CYREF(dest) = V_CY(source); break;
  1057. case VT_BSTR : SysReAllocString(V_BSTRREF(dest), V_BSTR(source)); break;
  1058. case VT_BOOL : *V_BOOLREF(dest) = V_BOOL(source); break;
  1059. case VT_DATE : *V_DATEREF(dest) = V_DATE(source); break;
  1060. case VT_DISPATCH :
  1061. //I need to addref the object behind this interface so
  1062. //that it doesn't get released when we release the original VARIANT
  1063. //that's holding it
  1064. V_DISPATCH(source)->AddRef();
  1065. *V_DISPATCHREF(dest) = V_DISPATCH(source);
  1066. break;
  1067. case VT_UNKNOWN :
  1068. //Again, need to addref so that the object doesn't get released
  1069. V_UNKNOWN(source)->AddRef();
  1070. *V_UNKNOWNREF(dest) = V_UNKNOWN(source); break;
  1071. break;
  1072. case VT_VARIANT : hr = VariantCopy(V_VARIANTREF(dest), source); break;
  1073. default : hr = DISP_E_TYPEMISMATCH;
  1074. }
  1075. }
  1076. }
  1077. return hr;
  1078. }
  1079. //***************************************************************************
  1080. //
  1081. // void CWbemDispatchMgr::EnsureClassRetrieved
  1082. //
  1083. // DESCRIPTION:
  1084. //
  1085. // Make sure we have a class pointer
  1086. //
  1087. //***************************************************************************
  1088. void CWbemDispatchMgr::EnsureClassRetrieved ()
  1089. {
  1090. if (!m_pWbemClass)
  1091. {
  1092. CComVariant vGenusVal, vClassName;
  1093. bool bIsClass;
  1094. if (SUCCEEDED(m_pWbemObject->Get(WBEMS_SP_GENUS, 0, &vGenusVal, NULL, NULL)))
  1095. {
  1096. bIsClass = (WBEM_GENUS_CLASS == vGenusVal.lVal);
  1097. //If the object is a class, point the class pointer to it as well
  1098. if (bIsClass)
  1099. {
  1100. m_pWbemClass = m_pWbemObject;
  1101. m_pWbemClass->AddRef () ;
  1102. }
  1103. //Otherwise (it's an instance) we need to get the class
  1104. else
  1105. {
  1106. // Check we have an IWbemServices pointer
  1107. if (m_pWbemServices)
  1108. {
  1109. /*
  1110. * Note we must check that returned value is a BSTR - it could be a VT_NULL if
  1111. * the __CLASS property has not yet been set.
  1112. */
  1113. if (SUCCEEDED(m_pWbemObject->Get(WBEMS_SP_CLASS, 0, &vClassName, NULL, NULL))
  1114. && (VT_BSTR == V_VT(&vClassName)))
  1115. {
  1116. CComPtr<IWbemServices> pIWbemServices = m_pWbemServices->GetIWbemServices ();
  1117. if (pIWbemServices)
  1118. {
  1119. CSWbemSecurity *pSecurity = m_pWbemServices->GetSecurityInfo ();
  1120. if (pSecurity)
  1121. {
  1122. bool needToResetSecurity = false;
  1123. HANDLE hThreadToken = NULL;
  1124. if (pSecurity->SetSecurity (needToResetSecurity, hThreadToken))
  1125. pIWbemServices->GetObject (vClassName.bstrVal, 0, NULL, &m_pWbemClass, NULL);
  1126. // Restore original privileges on this thread
  1127. if (needToResetSecurity)
  1128. pSecurity->ResetSecurity (hThreadToken);
  1129. pSecurity->Release ();
  1130. }
  1131. }
  1132. }
  1133. }
  1134. }
  1135. }
  1136. }
  1137. }
  1138. //***************************************************************************
  1139. //
  1140. // SCODE CWbemDispatchMgr::HandleError
  1141. //
  1142. // DESCRIPTION:
  1143. //
  1144. // Provide bespoke handling of error conditions in the bolierplate
  1145. // Dispatch implementation.
  1146. //
  1147. // PARAMETERS:
  1148. //
  1149. // dispidMember, wFlags,
  1150. // pdispparams, pvarResult,
  1151. // puArgErr, All passed directly from IDispatch::Invoke
  1152. // hr The return code from the bolierplate invoke
  1153. //
  1154. // RETURN VALUES:
  1155. // The new return code (to be ultimately returned from Invoke)
  1156. //
  1157. // WBEM_S_NO_ERROR success
  1158. // WBEM_E_INVALID_PARAMETER bad input parameters
  1159. // WBEM_E_FAILED otherwise
  1160. //
  1161. //***************************************************************************
  1162. HRESULT CWbemDispatchMgr::HandleError (
  1163. DISPID dispidMember,
  1164. unsigned short wFlags,
  1165. DISPPARAMS FAR* pdispparams,
  1166. VARIANT FAR* pvarResult,
  1167. UINT FAR* puArgErr,
  1168. HRESULT hr
  1169. )
  1170. {
  1171. /*
  1172. * We are looking for GET calls on the Derivation_ property which
  1173. * supplied an argument. Since this property returns a SAFEARRAY, this may
  1174. * be legal but undetectable by the standard Dispatch mechanism. It is meaningful
  1175. * to pass an index (the interpretation is that the index specifies an offset in
  1176. * the SAFEARRAY structure that represents the derivation value).
  1177. */
  1178. if ((dispidMember == WBEMS_DISPID_DERIVATION) && (DISP_E_NOTACOLLECTION == hr) && (1 == pdispparams->cArgs)
  1179. && (DISPATCH_PROPERTYGET & wFlags))
  1180. {
  1181. // Looks promising - get the __DERIVATION property to try and resolve this
  1182. if (m_pWbemObject)
  1183. {
  1184. VARIANT var;
  1185. VariantInit (&var);
  1186. if (WBEM_S_NO_ERROR == m_pWbemObject->Get (WBEMS_SP_DERIVATION, 0, &var, NULL, NULL))
  1187. {
  1188. /* The value should be a VT_BSTR|VT_ARRAY */
  1189. if (((VT_ARRAY | VT_BSTR) == var.vt) && (NULL != var.parray))
  1190. {
  1191. VARIANT indexVar;
  1192. VariantInit (&indexVar);
  1193. // Attempt to coerce the index argument into a value suitable for an array index
  1194. if (S_OK == VariantChangeType (&indexVar, &pdispparams->rgvarg[0], 0, VT_I4))
  1195. {
  1196. long lArrayPropInx = V_I4(&indexVar);
  1197. // We should have a VT_ARRAY|VT_BSTR value at this point; extract the
  1198. // BSTR and set it into the VARIANT
  1199. VariantInit (pvarResult);
  1200. BSTR nameValue = NULL;
  1201. if (SUCCEEDED(hr = SafeArrayGetElement (var.parray, &lArrayPropInx, &nameValue)))
  1202. {
  1203. VariantInit (pvarResult);
  1204. pvarResult->vt = VT_BSTR;
  1205. pvarResult->bstrVal = nameValue;
  1206. }
  1207. }
  1208. else
  1209. {
  1210. hr = DISP_E_TYPEMISMATCH;
  1211. if (puArgErr)
  1212. *puArgErr = 0;
  1213. }
  1214. VariantClear (&indexVar);
  1215. }
  1216. }
  1217. VariantClear (&var);
  1218. }
  1219. }
  1220. return hr;
  1221. }
  1222. // IDispatchEx methods
  1223. HRESULT STDMETHODCALLTYPE CWbemDispatchMgr::GetDispID(
  1224. /* [in] */ BSTR bstrName,
  1225. /* [in] */ DWORD grfdex,
  1226. /* [out] */ DISPID __RPC_FAR *pid)
  1227. {
  1228. return GetIDsOfNames(IID_NULL, &((OLECHAR *)bstrName), 1, ENGLISH_LOCALE, pid);
  1229. }
  1230. //***************************************************************************
  1231. //
  1232. // SCODE CWbemSchemaIDCache::~CWbemSchemaIDCache
  1233. //
  1234. // DESCRIPTION:
  1235. //
  1236. // Destructor
  1237. //
  1238. //***************************************************************************
  1239. CWbemSchemaIDCache::~CWbemSchemaIDCache ()
  1240. {
  1241. DispIDNameMap::iterator next;
  1242. while ((next = m_cache.begin ()) != m_cache.end ())
  1243. next = m_cache.erase (next);
  1244. }
  1245. //***************************************************************************
  1246. //
  1247. // SCODE CWbemSchemaIDCache::GetDispID
  1248. //
  1249. // DESCRIPTION:
  1250. //
  1251. // Attempts to resolves a set of names to DISP IDs based on WMI schema.
  1252. //
  1253. // PARAMETERS:
  1254. //
  1255. // rgszNames Array of names
  1256. // cNames Length of above array
  1257. // rgdispid Pointer to array to hold resolved DISPIDs
  1258. //
  1259. // RETURN VALUES:
  1260. //
  1261. //***************************************************************************
  1262. HRESULT CWbemSchemaIDCache::GetDispID (
  1263. LPWSTR* rgszNames,
  1264. unsigned int cNames,
  1265. DISPID* rgdispid
  1266. )
  1267. {
  1268. HRESULT hr = E_FAIL;
  1269. if (0 < cNames)
  1270. {
  1271. DispIDNameMap::iterator theIterator = m_cache.find (rgszNames [0]);
  1272. if (theIterator != m_cache.end ())
  1273. {
  1274. hr = S_OK;
  1275. rgdispid [0] = (*theIterator).second;
  1276. }
  1277. else
  1278. {
  1279. if ((1 == cNames) && FindPropertyName (rgszNames [0]))
  1280. {
  1281. // Get a new dispid and add it to the cache
  1282. CWbemDispID dispId;
  1283. if (dispId.SetAsSchemaID (++m_nextId))
  1284. {
  1285. rgdispid [0] = dispId;
  1286. m_cache.insert (DispIDNameMap::value_type (rgszNames [0],
  1287. dispId));
  1288. hr = S_OK;
  1289. }
  1290. }
  1291. else
  1292. {
  1293. //If no property name matches, go on to methods
  1294. SAFEARRAY *psaInParams = NULL; //array of in parameters names
  1295. SAFEARRAY *psaOutParams = NULL; //array of out parameter names
  1296. CComPtr<IWbemClassObject> pInParams;
  1297. CComPtr<IWbemClassObject> pOutParams;
  1298. bool bMethodFound = false;
  1299. long id = 0;
  1300. bool bUnknownParameterFound = false;
  1301. //Get the names of all method parameters (in and out)
  1302. if (GetMethod (rgszNames[0], &psaInParams, &psaOutParams,
  1303. pInParams, pOutParams))
  1304. {
  1305. bMethodFound = true;
  1306. unsigned long ulParamCount;
  1307. bool ok = true;
  1308. //For each named parameter, search for it in the method parameters
  1309. for (ulParamCount=1; ok && (ulParamCount < cNames); ulParamCount++)
  1310. {
  1311. //If we find this name in the "in" parameters list, attach the id and go on
  1312. if (psaInParams && FindMemberInArray(rgszNames[ulParamCount], psaInParams))
  1313. {
  1314. if (GetIdOfMethodParameter(rgszNames[ulParamCount], //param name
  1315. pInParams,
  1316. &id))
  1317. rgdispid[ulParamCount] = id;
  1318. else
  1319. ok = false;
  1320. }
  1321. //If it's not in the "in" parameters, check the "out" parameters list
  1322. else if (psaOutParams && FindMemberInArray(rgszNames[ulParamCount], psaOutParams))
  1323. {
  1324. if (GetIdOfMethodParameter(rgszNames[ulParamCount], //param name
  1325. pOutParams,
  1326. &id))
  1327. rgdispid[ulParamCount] = id;
  1328. else
  1329. ok = false;
  1330. }
  1331. //If it's not there either - we can't find it
  1332. else
  1333. {
  1334. rgdispid[ulParamCount] = DISPID_UNKNOWN;
  1335. bUnknownParameterFound = true;
  1336. }
  1337. } //walk parameters
  1338. if (!ok)
  1339. bMethodFound = false;
  1340. }
  1341. if (psaInParams)
  1342. SafeArrayDestroy(psaInParams);
  1343. if (psaOutParams)
  1344. SafeArrayDestroy(psaOutParams);
  1345. if (!bMethodFound)
  1346. hr = E_FAIL;
  1347. else if (bUnknownParameterFound)
  1348. hr = DISP_E_UNKNOWNNAME;
  1349. else
  1350. hr = S_OK;
  1351. // Finally, if this all worked add it to the cache as a method
  1352. if (SUCCEEDED(hr))
  1353. {
  1354. CWbemDispID dispId;
  1355. if (dispId.SetAsSchemaID (++m_nextId, false))
  1356. {
  1357. rgdispid [0] = dispId;
  1358. m_cache.insert (DispIDNameMap::value_type (rgszNames [0],
  1359. dispId));
  1360. }
  1361. else
  1362. hr = E_FAIL;
  1363. }
  1364. }
  1365. }
  1366. }
  1367. return hr;
  1368. }
  1369. //***************************************************************************
  1370. //
  1371. // bool CWbemSchemaIDCache::FindPropertyName
  1372. //
  1373. // DESCRIPTION:
  1374. //
  1375. // Determine whether the property exists for this object and is not
  1376. // a system property
  1377. //
  1378. // PARAMETERS:
  1379. //
  1380. // bsName - name of specified property
  1381. //
  1382. // RETURN VALUES:
  1383. //
  1384. //***************************************************************************
  1385. bool CWbemSchemaIDCache::FindPropertyName(
  1386. BSTR bsName
  1387. )
  1388. {
  1389. bool result = false;;
  1390. if (m_pDispatchMgr)
  1391. {
  1392. CComPtr<IWbemClassObject> pIWbemClassObject = m_pDispatchMgr->GetObject ();
  1393. if (pIWbemClassObject)
  1394. {
  1395. //Note : This limits the support to non-system properties only !!!
  1396. LONG lFlavor = 0;
  1397. if (SUCCEEDED(pIWbemClassObject->Get(bsName, 0, NULL, NULL, &lFlavor))
  1398. && !(WBEM_FLAVOR_ORIGIN_SYSTEM & lFlavor))
  1399. result = true;
  1400. }
  1401. }
  1402. return result;
  1403. }
  1404. //***************************************************************************
  1405. //
  1406. // bool CWbemSchemaIDCache::GetMethod
  1407. //
  1408. // DESCRIPTION:
  1409. //
  1410. // returns the parameter names of a method in two
  1411. // safearrays - one for in and one for out
  1412. //
  1413. // PARAMETERS:
  1414. //
  1415. // bstrMethodName - name of method requested
  1416. // ppsaInParams - pointer to safearray to return
  1417. // in parameters
  1418. // ppsaOutParams - pointer to safearray to return
  1419. // out parameters
  1420. //
  1421. // RETURN VALUES:
  1422. //
  1423. //***************************************************************************
  1424. bool CWbemSchemaIDCache::GetMethod(
  1425. BSTR bstrMethodName,
  1426. SAFEARRAY **ppsaInParams,
  1427. SAFEARRAY **ppsaOutParams,
  1428. CComPtr<IWbemClassObject> & pInParamsObject,
  1429. CComPtr<IWbemClassObject> & pOutParamsObject
  1430. )
  1431. {
  1432. bool result = false;
  1433. CComPtr<IWbemClassObject> pIWbemClassObject = m_pDispatchMgr->GetClassObject ();
  1434. if (pIWbemClassObject)
  1435. {
  1436. if (SUCCEEDED(pIWbemClassObject->GetMethod(bstrMethodName, 0, &pInParamsObject, &pOutParamsObject)))
  1437. {
  1438. *ppsaInParams = NULL;
  1439. *ppsaOutParams = NULL;
  1440. bool ok = true;
  1441. if (pInParamsObject)
  1442. {
  1443. if (FAILED(pInParamsObject->GetNames(NULL, 0, NULL, ppsaInParams)))
  1444. ok = false;
  1445. }
  1446. if (ok && pOutParamsObject)
  1447. {
  1448. if (FAILED(pOutParamsObject->GetNames(NULL, 0, NULL, ppsaOutParams)))
  1449. ok = false;
  1450. }
  1451. result = ok;
  1452. }
  1453. }
  1454. return result;
  1455. }
  1456. //***************************************************************************
  1457. //
  1458. // bool CWbemSchemaIDCache::GetIdOfMethodParameter
  1459. //
  1460. // DESCRIPTION:
  1461. //
  1462. // gets the id of a given parameter for a given method
  1463. // (this is a qualifier on the parameter property in the
  1464. // InParameters/OutParameters object)
  1465. //
  1466. // PARAMETERS:
  1467. //
  1468. // bstrParamName - parameter name
  1469. // pParams - IWbemClassObject containing parameters
  1470. // pId - pointer to long to receive the ID for this
  1471. // parameter of this method
  1472. //
  1473. // RETURN VALUES:
  1474. //
  1475. //***************************************************************************
  1476. bool CWbemSchemaIDCache::GetIdOfMethodParameter(
  1477. BSTR bstrParamName,
  1478. CComPtr<IWbemClassObject> &pParams,
  1479. long *pId
  1480. )
  1481. {
  1482. bool result = false;
  1483. if (pParams)
  1484. {
  1485. CComPtr<IWbemQualifierSet> pQualSet;
  1486. //Get qualifier set for the required parameter property
  1487. if (SUCCEEDED(pParams->GetPropertyQualifierSet(bstrParamName, &pQualSet)))
  1488. {
  1489. CComVariant vIdVal;
  1490. //Get the "id" qualifier value
  1491. if (SUCCEEDED(pQualSet->Get(L"id", 0, &vIdVal, NULL)))
  1492. {
  1493. result = true;
  1494. *pId = vIdVal.lVal;
  1495. }
  1496. }
  1497. }
  1498. return result;
  1499. }
  1500. //***************************************************************************
  1501. //
  1502. // bool CWbemSchemaIDCache::GetName
  1503. //
  1504. // DESCRIPTION:
  1505. //
  1506. // gets the name of the item given a DISPID
  1507. //
  1508. // PARAMETERS:
  1509. //
  1510. // dispId - id whose name we require
  1511. // bsName - the name (on successful return)
  1512. //
  1513. // RETURN VALUES:
  1514. //
  1515. //***************************************************************************
  1516. bool CWbemSchemaIDCache::GetName (
  1517. DISPID dispId,
  1518. CComBSTR & bsName
  1519. )
  1520. {
  1521. bool result = false;
  1522. DispIDNameMap::iterator theIterator = m_cache.begin ();
  1523. while (theIterator != m_cache.end ())
  1524. {
  1525. if (dispId == (*theIterator).second)
  1526. {
  1527. bsName = (*theIterator).first;
  1528. result = true;
  1529. break;
  1530. }
  1531. else
  1532. theIterator++;
  1533. }
  1534. return result;
  1535. }
  1536. //***************************************************************************
  1537. //
  1538. // bool CWbemSchemaIDCache::FindMemberInArray
  1539. //
  1540. // DESCRIPTION:
  1541. //
  1542. // determine whether a name is present in a SAFEARRAY
  1543. //
  1544. // PARAMETERS:
  1545. //
  1546. // bstrName - the name we're looking for
  1547. // psaNames - SAFEARRAY we're looking in
  1548. //
  1549. // RETURN VALUES:
  1550. // true if found, false o/w
  1551. //
  1552. //***************************************************************************
  1553. bool CWbemSchemaIDCache::FindMemberInArray(BSTR bstrName, SAFEARRAY *psaNames)
  1554. {
  1555. long lUBound;
  1556. long i;
  1557. //Walk the array and check if the requested name exists
  1558. SafeArrayGetUBound(psaNames, 1, &lUBound);
  1559. for (i=0; i <= lUBound; i++)
  1560. {
  1561. CComBSTR bstrMemberName;
  1562. SafeArrayGetElement(psaNames, &i, &bstrMemberName);
  1563. if (!_wcsicmp(bstrMemberName, bstrName)) //found the property
  1564. break;
  1565. }
  1566. return (i <= lUBound);
  1567. }