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.

1835 lines
50 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, CWbemAllocator<CWbemDispID> > 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;
  432. pService.Attach(m_pWbemServices->GetIWbemServices());
  433. if (pService)
  434. {
  435. // Need the RELPATH to specify the target class or instance
  436. VARIANT vObjectPathVal;
  437. VariantInit(&vObjectPathVal);
  438. if (SUCCEEDED (hr = m_pWbemObject->Get
  439. (WBEMS_SP_RELPATH, 0, &vObjectPathVal, NULL, NULL)))
  440. {
  441. /*
  442. * If a "keyless" object slips through the net its __RELPATH
  443. * value will be VT_NULL. At this point we should fail gracefully.
  444. */
  445. if (VT_BSTR == V_VT(&vObjectPathVal))
  446. {
  447. // Execute the CIMOM method
  448. CComPtr<IWbemClassObject> pOutParamsInstance;
  449. bool needToResetSecurity = false;
  450. HANDLE hThreadToken = NULL;
  451. CSWbemSecurity *pSecurityInfo = m_pWbemServices->GetSecurityInfo ();
  452. if (pSecurityInfo && pSecurityInfo->SetSecurity (needToResetSecurity, hThreadToken))
  453. {
  454. if (SUCCEEDED(hr = pService->ExecMethod(V_BSTR(&vObjectPathVal),
  455. bsMethodName, 0, NULL,
  456. pInParamsInstance, &pOutParamsInstance, NULL)))
  457. hr = MapOutParameters (pdispparams, pOutParameters,
  458. pOutParamsInstance, pvarResult);
  459. SetWbemError (m_pWbemServices);
  460. }
  461. if (pSecurityInfo)
  462. {
  463. // Restore original privileges on this thread
  464. if (needToResetSecurity)
  465. pSecurityInfo->ResetSecurity (hThreadToken);
  466. pSecurityInfo->Release ();
  467. }
  468. }
  469. else
  470. hr = WBEM_E_FAILED;
  471. }
  472. VariantClear (&vObjectPathVal);
  473. }
  474. }
  475. }
  476. }
  477. }
  478. return hr;
  479. }
  480. //***************************************************************************
  481. //
  482. // SCODE CWbemDispatchMgr::MapOutParameters
  483. //
  484. // DESCRIPTION:
  485. //
  486. // Invoke the method via direct access.
  487. //
  488. // PARAMETERS:
  489. //
  490. // dispparams Pointer to DISPPARAMS for this invocation
  491. // pOutParameters Class template for out parameters
  492. // pOutParamsInstance Addresses the IWbemClassObject to hold the
  493. // out parameters (if any) - may be NULL
  494. // pvarResult On successful return holds return value (if any)
  495. //
  496. // RETURN VALUES:
  497. //
  498. //***************************************************************************
  499. HRESULT CWbemDispatchMgr::MapOutParameters (
  500. DISPPARAMS FAR* pdispparams,
  501. IWbemClassObject *pOutParameters,
  502. IWbemClassObject *pOutParamsInstance,
  503. VARIANT FAR* pvarResult
  504. )
  505. {
  506. HRESULT hr = S_OK;
  507. //For each "out" parameter in the output parameters object (if there is one),
  508. //find it's id, then look for the parameter with this id in the arguments array
  509. //and set the return parameter value accordingly
  510. //----------------------------------------------------------------------------
  511. if (pOutParameters && pOutParamsInstance)
  512. {
  513. //Start an enumeration through the "out" parameters class template
  514. if (SUCCEEDED (hr = pOutParameters->BeginEnumeration(WBEM_FLAG_NONSYSTEM_ONLY)))
  515. {
  516. BSTR bstrId = SysAllocString(L"id");
  517. BSTR bstrParamName = NULL;
  518. /*
  519. * For each property in the outparams class template, get the [id]
  520. * to map the relevant posistional value in the pdispparams.
  521. */
  522. while (WBEM_S_NO_ERROR ==
  523. (hr != pOutParameters->Next(0, &bstrParamName, NULL, NULL, NULL)))
  524. {
  525. // Get the returned parameter value from the instance
  526. VARIANT vParamVal;
  527. VariantInit(&vParamVal);
  528. if (SUCCEEDED (pOutParamsInstance->Get (bstrParamName, 0, &vParamVal, NULL, NULL)))
  529. {
  530. //If this is the return value, set it separately
  531. if (!_wcsicmp(bstrParamName, L"ReturnValue"))
  532. {
  533. if (pvarResult)
  534. hr = MapReturnValue (pvarResult, &vParamVal);
  535. }
  536. //Otherwise - regular out parameter
  537. else
  538. {
  539. IWbemQualifierSet *pQualSet = NULL;
  540. //Get the id of this parameter (it's the "id" qualifier)
  541. if (SUCCEEDED (hr = pOutParameters->GetPropertyQualifierSet
  542. (bstrParamName, &pQualSet)))
  543. {
  544. VARIANT vIdVal;
  545. VariantInit(&vIdVal);
  546. if (SUCCEEDED (hr = pQualSet->Get(bstrId, 0, &vIdVal, NULL)))
  547. {
  548. //Calculate the position of this id in the arguments array
  549. long pos = (pdispparams->cArgs - 1) - V_I4(&vIdVal);
  550. // If its out of range, too bad
  551. if ((0 <= pos) && (pos < (long) pdispparams->cArgs))
  552. hr = MapOutParameter (&pdispparams->rgvarg[pos], &vParamVal);
  553. }
  554. VariantClear(&vIdVal);
  555. pQualSet->Release();
  556. }
  557. }
  558. }
  559. VariantClear (&vParamVal);
  560. SysFreeString (bstrParamName);
  561. bstrParamName = NULL;
  562. } //while
  563. SysFreeString (bstrId);
  564. }
  565. } //if pOutParameters
  566. return hr;
  567. }
  568. //***************************************************************************
  569. //
  570. // SCODE CWbemDispatchMgr::MapReturnValue
  571. //
  572. // DESCRIPTION:
  573. //
  574. // Map the method return value
  575. //
  576. // PARAMETERS:
  577. //
  578. // pDest On successful return holds return value (if any)
  579. // pSrc The variant value to map
  580. //
  581. //
  582. // RETURN VALUES:
  583. //
  584. //***************************************************************************
  585. HRESULT CWbemDispatchMgr::MapReturnValue (
  586. VARIANT FAR* pDest,
  587. VARIANT FAR* pSrc
  588. )
  589. {
  590. HRESULT hr = S_OK;
  591. //If the return value is a VT_UNKNOWN, we need to wrap into a
  592. //VT_DISPATCH before passing it back
  593. if (SUCCEEDED (hr = MapFromCIMOMObject(m_pWbemServices, pSrc)))
  594. {
  595. // Handle arrays correctly (must always be VT_ARRAY|VT_VARIANT)
  596. if(V_VT(pSrc) & VT_ARRAY)
  597. hr = ConvertArrayRev(pDest, pSrc);
  598. else
  599. hr = VariantCopy (pDest, pSrc);
  600. }
  601. return hr;
  602. }
  603. //***************************************************************************
  604. //
  605. // SCODE CWbemDispatchMgr::MapOutParameter
  606. //
  607. // DESCRIPTION:
  608. //
  609. // Map a (possibly by reference) out parameter
  610. //
  611. // PARAMETERS:
  612. //
  613. // pDest On successful return holds return value (if any)
  614. // pVal The variant value to map
  615. //
  616. //
  617. // RETURN VALUES:
  618. //
  619. //***************************************************************************
  620. HRESULT CWbemDispatchMgr::MapOutParameter (
  621. VARIANT FAR* pDest,
  622. VARIANT FAR* pSrc
  623. )
  624. {
  625. HRESULT hr = S_OK;
  626. //If the return value is a VT_UNKNOWN, we need to wrap into a
  627. //VT_DISPATCH before passing it back
  628. if (SUCCEEDED (hr = MapFromCIMOMObject(m_pWbemServices, pSrc)))
  629. {
  630. VARIANT tempVal;
  631. VariantInit (&tempVal);
  632. // Handle arrays correctly (must always be VT_ARRAY|VT_VARIANT)
  633. if(V_VT(pSrc) & VT_ARRAY)
  634. hr = ConvertArrayRev(&tempVal, pSrc);
  635. else
  636. hr = VariantCopy (&tempVal, pSrc);
  637. // Finally take care of ensuring we produce BYREFs if necessary
  638. if (SUCCEEDED (hr))
  639. hr = VariantChangeByValToByRef(pDest, &tempVal, V_VT(pDest));
  640. VariantClear (&tempVal);
  641. }
  642. return hr;
  643. }
  644. //***************************************************************************
  645. //
  646. // SCODE CWbemDispatchMgr::MapInParameters
  647. //
  648. // DESCRIPTION:
  649. //
  650. // Map the in parameters to a method
  651. //
  652. // PARAMETERS:
  653. //
  654. // pdispparams DISPPARAMS containing the in parameters
  655. // pInParameters Class template for method input parameters
  656. // ppInParamsInstance On successful return holds the mapped parameters
  657. //
  658. // RETURN VALUES:
  659. //
  660. //***************************************************************************
  661. HRESULT CWbemDispatchMgr::MapInParameters (
  662. DISPPARAMS FAR* pdispparams,
  663. IWbemClassObject *pInParameters,
  664. IWbemClassObject **ppInParamsInstance
  665. )
  666. {
  667. HRESULT hr = S_OK;
  668. *ppInParamsInstance = NULL;
  669. //Spawn an instance to fill in with values
  670. if (SUCCEEDED (hr = pInParameters->SpawnInstance(0, ppInParamsInstance)))
  671. {
  672. /*
  673. * Iterate through the "in" parameters object properties in the class to find the
  674. * ID positional qualifier. Note we do this in the InParams class rather than
  675. * the spawned instance to protect ourselves against the case where the [id]
  676. * qualifier has been declared without the "propagate to instance" flavor setting,
  677. */
  678. if (SUCCEEDED (hr = pInParameters->BeginEnumeration(WBEM_FLAG_NONSYSTEM_ONLY)))
  679. {
  680. BSTR bstrParamName = NULL;
  681. BSTR bstrId = SysAllocString(L"id");
  682. CIMTYPE lType;
  683. //For each property in the inparams object
  684. while (WBEM_S_NO_ERROR ==
  685. (hr = pInParameters->Next(0, &bstrParamName, NULL, &lType, NULL)))
  686. {
  687. IWbemQualifierSet *pQualSet = NULL;
  688. //Get the id of this parameter (it's the "id" qualifier)
  689. if (SUCCEEDED(hr =
  690. pInParameters->GetPropertyQualifierSet(bstrParamName, &pQualSet)))
  691. {
  692. VARIANT vIdVal;
  693. VariantInit(&vIdVal);
  694. if (SUCCEEDED(hr = pQualSet->Get(bstrId, 0, &vIdVal, NULL)))
  695. {
  696. //Calculate the position of this id in the arguments array
  697. long pos = (pdispparams->cArgs - 1) - V_I4(&vIdVal);
  698. // If no argument specified, we won't set it in ppInParamsInstance
  699. // and just assume it will be defaulted
  700. if ((0 <= pos) && (pos < (long) pdispparams->cArgs))
  701. {
  702. VARIANT vParamVal;
  703. VariantInit (&vParamVal);
  704. if (SUCCEEDED (hr = MapInParameter
  705. (&vParamVal, &pdispparams->rgvarg[pos], lType)))
  706. {
  707. // If we have a VT_ERROR with DISP_E_PARAMNOTFOUND this
  708. // is a "missing" parameter - we just fail to set it and
  709. // let it default in the instance
  710. if ((VT_ERROR == V_VT(&vParamVal)) && (DISP_E_PARAMNOTFOUND == vParamVal.scode))
  711. {
  712. // Let it default
  713. }
  714. else
  715. {
  716. //Copy the value for this parameter from the argument array
  717. //into the inparamsinstance object property
  718. hr = (*ppInParamsInstance)->Put(bstrParamName, 0, &vParamVal, NULL);
  719. }
  720. }
  721. VariantClear (&vParamVal);
  722. }
  723. }
  724. VariantClear(&vIdVal);
  725. pQualSet->Release();
  726. pQualSet = NULL;
  727. }
  728. SysFreeString (bstrParamName);
  729. bstrParamName = NULL;
  730. if (FAILED(hr))
  731. break;
  732. } //while
  733. SysFreeString (bstrId);
  734. }
  735. }
  736. return hr;
  737. }
  738. //***************************************************************************
  739. //
  740. // SCODE CWbemDispatchMgr::MapInParameter
  741. //
  742. // DESCRIPTION:
  743. //
  744. // Map a in parameter
  745. //
  746. // PARAMETERS:
  747. //
  748. // pDest On successful return holds return value
  749. // pVal The variant value to map
  750. // lType CIMTYPE of target property value
  751. //
  752. //
  753. // RETURN VALUES:
  754. //
  755. //***************************************************************************
  756. HRESULT CWbemDispatchMgr::MapInParameter (
  757. VARIANT FAR* pDest,
  758. VARIANT FAR* pSrc,
  759. CIMTYPE lType
  760. )
  761. {
  762. HRESULT hr = S_OK;
  763. if ((NULL == pSrc) || (VT_EMPTY == V_VT(pSrc))
  764. || (VT_NULL == V_VT(pSrc)))
  765. {
  766. // Map all of these to a VT_NULL
  767. pDest->vt = VT_NULL;
  768. }
  769. else if (((VT_ARRAY | VT_VARIANT) == V_VT(pSrc)) ||
  770. ((VT_ARRAY | VT_VARIANT | VT_BYREF) == V_VT(pSrc)))
  771. {
  772. // Arrays need to be mapped "down" to their raw form (and watch out
  773. // for embedded objects!)
  774. if (SUCCEEDED(hr = ConvertArray(pDest, pSrc)))
  775. hr = MapToCIMOMObject(pDest);
  776. }
  777. else if ((CIM_FLAG_ARRAY & lType) &&
  778. ((VT_DISPATCH == V_VT(pSrc))
  779. || ((VT_DISPATCH|VT_BYREF) == V_VT(pSrc))))
  780. {
  781. // Look for a JScript-style IDispatch that needs to be mapped to an array
  782. hr = ConvertDispatchToArray (pDest, pSrc, lType & ~CIM_FLAG_ARRAY);
  783. }
  784. else if ((VT_BYREF | VT_VARIANT) == V_VT(pSrc))
  785. {
  786. // May be used if the scripting language supports functions that can change
  787. // the type of a reference. CIMOM won't do this, wo we unwrap the
  788. // variant before proceeding
  789. hr = MapInParameter (pDest, pSrc->pvarVal, lType);
  790. }
  791. else
  792. {
  793. // A "straightforward" value - all we have to watch for is an embedded object
  794. // and a possible byRef
  795. if (SUCCEEDED(hr = VariantCopy (pDest, pSrc)))
  796. {
  797. hr = MapToCIMOMObject(pDest);
  798. // Is it byref - if so remove the indirection
  799. if (VT_BYREF & V_VT(pDest))
  800. hr = VariantChangeType(pDest, pDest, 0, V_VT(pDest) & ~VT_BYREF);
  801. }
  802. }
  803. return hr;
  804. }
  805. //-------------------------------------------------------------
  806. // CWbemDispatchMgr::RaiseException
  807. //
  808. // Description : signal exception to automation client
  809. //
  810. // Parameters : hr - HRESULT
  811. //-------------------------------------------------------------
  812. void CWbemDispatchMgr::RaiseException (HRESULT hr)
  813. {
  814. // Store the HRESULT for processing in the Invoke routine
  815. m_hResult = hr;
  816. // Set a WMI scripting error on this thread for the client
  817. ICreateErrorInfo *pCreateErrorInfo = NULL;
  818. if (SUCCEEDED (CreateErrorInfo (&pCreateErrorInfo)))
  819. {
  820. BSTR bsDescr = MapHresultToWmiDescription (hr);
  821. pCreateErrorInfo->SetDescription (bsDescr);
  822. SysFreeString (bsDescr);
  823. pCreateErrorInfo->SetGUID (IID_ISWbemObjectEx);
  824. pCreateErrorInfo->SetSource (L"SWbemObjectEx");
  825. IErrorInfo *pErrorInfo = NULL;
  826. if (SUCCEEDED (pCreateErrorInfo->QueryInterface(IID_IErrorInfo, (void**) &pErrorInfo)))
  827. {
  828. SetErrorInfo (0, pErrorInfo);
  829. pErrorInfo->Release ();
  830. }
  831. pCreateErrorInfo->Release ();
  832. }
  833. }
  834. //-------------------------------------------------------------
  835. // Name : assignArrayElementToVariant
  836. //
  837. // Description : According to the type of the array elements,
  838. // retrieves the requested element from the array
  839. // into a variant
  840. //
  841. // Parameters : psa - pointer to the SAFEARRAY
  842. // vt - vartype of array elements
  843. // inx - index of the element in the array
  844. // pvResult - resulting variant
  845. //-------------------------------------------------------------
  846. HRESULT assignArrayElementToVariant(SAFEARRAY *psa, VARTYPE vt, long inx, VARIANT *pvResult)
  847. {
  848. HRESULT hr = WBEM_S_NO_ERROR;
  849. switch (vt)
  850. {
  851. case VT_I2 :
  852. V_VT(pvResult) = VT_I2;
  853. hr = SafeArrayGetElement(psa, &inx, &V_I2(pvResult)); // Bug ID 566345
  854. break;
  855. case VT_I4 :
  856. V_VT(pvResult) = VT_I4;
  857. hr = SafeArrayGetElement(psa, &inx, &V_I4(pvResult)); // Bug ID 566345
  858. break;
  859. case VT_R4 :
  860. V_VT(pvResult) = VT_R4;
  861. hr = SafeArrayGetElement(psa, &inx, &V_R4(pvResult)); // Bug ID 566345
  862. break;
  863. case VT_R8 :
  864. V_VT(pvResult) = VT_R8;
  865. hr = SafeArrayGetElement(psa, &inx, &V_R8(pvResult)); // Bug ID 566345
  866. break;
  867. case VT_DATE :
  868. V_VT(pvResult) = VT_DATE;
  869. hr = SafeArrayGetElement(psa, &inx, &V_DATE(pvResult)); // Bug ID 566345
  870. break;
  871. case VT_BSTR :
  872. V_VT(pvResult) = VT_BSTR;
  873. hr = SafeArrayGetElement(psa, &inx, &V_BSTR(pvResult)); // Bug ID 566345
  874. break;
  875. case VT_DISPATCH :
  876. V_VT(pvResult) = VT_DISPATCH;
  877. hr = SafeArrayGetElement(psa, &inx, &V_DISPATCH(pvResult)); // Bug ID 566345
  878. break;
  879. case VT_UNKNOWN :
  880. V_VT(pvResult) = VT_UNKNOWN;
  881. hr = SafeArrayGetElement(psa, &inx, &V_UNKNOWN(pvResult)); // Bug ID 566345
  882. break;
  883. case VT_BOOL :
  884. V_VT(pvResult) = VT_BOOL;
  885. hr = SafeArrayGetElement(psa, &inx, &V_BOOL(pvResult)); // Bug ID 566345
  886. break;
  887. case VT_VARIANT :
  888. {
  889. V_VT(pvResult) = VT_BYREF | VT_VARIANT;
  890. VARIANT *pVar = new VARIANT;
  891. if (pVar)
  892. {
  893. VariantInit (pVar);
  894. hr = SafeArrayGetElement(psa, &inx, pVar); // Bug ID 566345
  895. V_VARIANTREF(pvResult) = pVar;
  896. }
  897. else
  898. hr = WBEM_E_OUT_OF_MEMORY;
  899. }
  900. break;
  901. case VT_UI1 :
  902. V_VT(pvResult) = VT_UI1;
  903. hr = SafeArrayGetElement(psa, &inx, &V_UI1(pvResult)); // Bug ID 566345
  904. break;
  905. default :
  906. V_VT(pvResult) = VT_ERROR;
  907. break;
  908. }
  909. return hr;
  910. }
  911. //-------------------------------------------------------------
  912. // Name : CheckArrayBounds
  913. //
  914. // Description : Check that index is within bounds and if not
  915. // Redim the array
  916. //
  917. // Parameters : psa - pointer to the SAFEARRAY
  918. // inx - putative index
  919. //-------------------------------------------------------------
  920. void CheckArrayBounds(SAFEARRAY *psa, long inx)
  921. {
  922. long lBound, uBound;
  923. lBound = uBound = 0;
  924. SafeArrayGetUBound (psa, 1, &uBound);
  925. SafeArrayGetLBound (psa, 1, &lBound);
  926. if ((inx < lBound) || (inx > uBound))
  927. {
  928. // Need to redim
  929. SAFEARRAYBOUND psaBound;
  930. psaBound.cElements = ((inx < lBound) ?
  931. (uBound + 1 - inx) : (inx + 1 - lBound));
  932. psaBound.lLbound = (inx < lBound) ? inx : lBound;
  933. SafeArrayRedim (psa, &psaBound);
  934. }
  935. }
  936. //-------------------------------------------------------------
  937. // Name : assignVariantToArrayElement
  938. //
  939. // Description : According to the type of the array elements,
  940. // puts the new value from the variant into the
  941. // requested element of the array
  942. //
  943. // Parameters : psa - pointer to the SAFEARRAY
  944. // vt - vartype of array elements
  945. // inx - index of the element in the array
  946. // pvNewVal - variant containing the new value
  947. //-------------------------------------------------------------
  948. void assignVariantToArrayElement(SAFEARRAY *psa, VARTYPE vt, long inx, VARIANT *pvNewVal)
  949. {
  950. HRESULT hr = E_FAIL;
  951. // Firstly check for out-of-bounds case and grow accordingly
  952. CheckArrayBounds (psa, inx);
  953. switch (vt)
  954. {
  955. case VT_I2 :
  956. hr = SafeArrayPutElement(psa, &inx, &V_I2(pvNewVal));
  957. break;
  958. case VT_I4 :
  959. hr = SafeArrayPutElement(psa, &inx, &V_I4(pvNewVal));
  960. break;
  961. case VT_R4 :
  962. hr = SafeArrayPutElement(psa, &inx, &V_R4(pvNewVal));
  963. break;
  964. case VT_R8 :
  965. hr = SafeArrayPutElement(psa, &inx, &V_R8(pvNewVal));
  966. break;
  967. case VT_DATE :
  968. hr = SafeArrayPutElement(psa, &inx, &V_DATE(pvNewVal));
  969. break;
  970. case VT_BSTR :
  971. hr = SafeArrayPutElement(psa, &inx, V_BSTR(pvNewVal));
  972. break;
  973. case VT_DISPATCH :
  974. hr = SafeArrayPutElement(psa, &inx, V_DISPATCH(pvNewVal));
  975. break;
  976. case VT_UNKNOWN:
  977. hr = SafeArrayPutElement(psa, &inx, V_UNKNOWN(pvNewVal));
  978. break;
  979. case VT_BOOL :
  980. hr = SafeArrayPutElement(psa, &inx, &V_BOOL(pvNewVal));
  981. break;
  982. case VT_VARIANT :
  983. hr = SafeArrayPutElement(psa, &inx, V_VARIANTREF(pvNewVal));
  984. break;
  985. case VT_UI1 :
  986. hr = SafeArrayPutElement(psa, &inx, &V_UI1(pvNewVal));
  987. break;
  988. default :
  989. //????????????
  990. break;
  991. } //switch
  992. }
  993. //-------------------------------------------------------------
  994. // Name : CimTypeToVtType
  995. //
  996. // Description : Returns the coresponding VARTYPE for
  997. // a given CIMTYPE
  998. // Parameters : lType - the CIMTYPE we want to convert
  999. //-------------------------------------------------------------
  1000. VARTYPE CimTypeToVtType(CIMTYPE lType)
  1001. {
  1002. VARTYPE ret = VT_EMPTY;
  1003. if (lType & CIM_FLAG_ARRAY)
  1004. ret = VT_ARRAY;
  1005. switch(lType & ~CIM_FLAG_ARRAY)
  1006. {
  1007. case CIM_EMPTY : ret = (ret | VT_EMPTY); break;
  1008. case CIM_SINT8 : ret = (ret | VT_I2); break;
  1009. case CIM_UINT8 : ret = (ret | VT_UI1); break;
  1010. case CIM_SINT16 : ret = (ret | VT_I2); break;
  1011. case CIM_UINT16 : ret = (ret | VT_I4); break;
  1012. case CIM_SINT32 : ret = (ret | VT_I4); break;
  1013. case CIM_UINT32 : ret = (ret | VT_I4); break;
  1014. case CIM_SINT64 : ret = (ret | VT_BSTR); break;
  1015. case CIM_UINT64 : ret = (ret | VT_BSTR); break;
  1016. case CIM_REAL32 : ret = (ret | VT_R4); break;
  1017. case CIM_REAL64 : ret = (ret | VT_R8); break;
  1018. case CIM_BOOLEAN : ret = (ret | VT_BOOL); break;
  1019. case CIM_STRING : ret = (ret | VT_BSTR); break;
  1020. case CIM_DATETIME : ret = (ret | VT_BSTR); break;
  1021. case CIM_REFERENCE :ret = (ret | VT_BSTR); break;
  1022. case CIM_CHAR16 : ret = (ret | VT_I2); break;
  1023. case CIM_OBJECT : ret = (ret | VT_UNKNOWN); break;
  1024. default : ret = VT_ERROR;
  1025. }
  1026. return ret;
  1027. }
  1028. //-------------------------------------------------------------
  1029. // Name : VariantChangeByValToByRef
  1030. //
  1031. // Description : Copies a variant, while converting a "byval" to a
  1032. // "byref" if the destination type requires it
  1033. //
  1034. // Parameters : dest - destination variant to hold the result
  1035. // source - source variant to be copied
  1036. // destType - the VARTYPE required for the result.
  1037. // when this type is a BY_REF, the appropriate
  1038. // conversion is made from the source.
  1039. //-------------------------------------------------------------
  1040. HRESULT VariantChangeByValToByRef(VARIANT *dest, VARIANT *source, VARTYPE destType)
  1041. {
  1042. HRESULT hr = S_OK;
  1043. if (!(destType & VT_BYREF)) //the destination is not by ref. we can do a straight copy
  1044. {
  1045. VariantInit(dest);
  1046. hr = VariantCopy(dest, source);
  1047. }
  1048. else
  1049. {
  1050. if ((destType & ~VT_BYREF) & VT_ARRAY)
  1051. {
  1052. // Fix for bug 732681
  1053. if(V_VT(source) == VT_NULL)
  1054. {
  1055. if(NULL != *(V_ARRAYREF(dest)))
  1056. {
  1057. SafeArrayDestroy(*(V_ARRAYREF(dest)));
  1058. *(V_ARRAYREF(dest)) = NULL;
  1059. }
  1060. }
  1061. else
  1062. {
  1063. hr = SafeArrayCopy(V_ARRAY(source), V_ARRAYREF(dest));
  1064. }
  1065. }
  1066. else
  1067. {
  1068. switch (destType & ~VT_BYREF)
  1069. {
  1070. case VT_UI1 : *V_UI1REF(dest) = V_UI1(source); break;
  1071. case VT_I2 : *V_I2REF(dest) = V_I2(source); break;
  1072. case VT_I4 : *V_I4REF(dest) = V_I4(source); break;
  1073. case VT_R4 : *V_R4REF(dest) = V_R4(source); break;
  1074. case VT_R8 : *V_R8REF(dest) = V_R8(source); break;
  1075. case VT_CY : *V_CYREF(dest) = V_CY(source); break;
  1076. case VT_BSTR : SysReAllocString(V_BSTRREF(dest), V_BSTR(source)); break;
  1077. case VT_BOOL : *V_BOOLREF(dest) = V_BOOL(source); break;
  1078. case VT_DATE : *V_DATEREF(dest) = V_DATE(source); break;
  1079. case VT_DISPATCH :
  1080. //I need to addref the object behind this interface so
  1081. //that it doesn't get released when we release the original VARIANT
  1082. //that's holding it
  1083. V_DISPATCH(source)->AddRef();
  1084. *V_DISPATCHREF(dest) = V_DISPATCH(source);
  1085. break;
  1086. case VT_UNKNOWN :
  1087. //Again, need to addref so that the object doesn't get released
  1088. V_UNKNOWN(source)->AddRef();
  1089. *V_UNKNOWNREF(dest) = V_UNKNOWN(source); break;
  1090. break;
  1091. case VT_VARIANT :
  1092. hr = VariantChangeByValToByRef(V_VARIANTREF(dest),source,V_VT(V_VARIANTREF(dest)) ); break;
  1093. default : hr = DISP_E_TYPEMISMATCH;
  1094. }
  1095. }
  1096. }
  1097. return hr;
  1098. }
  1099. //***************************************************************************
  1100. //
  1101. // void CWbemDispatchMgr::EnsureClassRetrieved
  1102. //
  1103. // DESCRIPTION:
  1104. //
  1105. // Make sure we have a class pointer
  1106. //
  1107. //***************************************************************************
  1108. void CWbemDispatchMgr::EnsureClassRetrieved ()
  1109. {
  1110. if (!m_pWbemClass)
  1111. {
  1112. CComVariant vGenusVal, vClassName;
  1113. bool bIsClass;
  1114. if (SUCCEEDED(m_pWbemObject->Get(WBEMS_SP_GENUS, 0, &vGenusVal, NULL, NULL)))
  1115. {
  1116. bIsClass = (WBEM_GENUS_CLASS == vGenusVal.lVal);
  1117. //If the object is a class, point the class pointer to it as well
  1118. if (bIsClass)
  1119. {
  1120. m_pWbemClass = m_pWbemObject;
  1121. m_pWbemClass->AddRef () ;
  1122. }
  1123. //Otherwise (it's an instance) we need to get the class
  1124. else
  1125. {
  1126. // Check we have an IWbemServices pointer
  1127. if (m_pWbemServices)
  1128. {
  1129. /*
  1130. * Note we must check that returned value is a BSTR - it could be a VT_NULL if
  1131. * the __CLASS property has not yet been set.
  1132. */
  1133. if (SUCCEEDED(m_pWbemObject->Get(WBEMS_SP_CLASS, 0, &vClassName, NULL, NULL))
  1134. && (VT_BSTR == V_VT(&vClassName)))
  1135. {
  1136. CComPtr<IWbemServices> pIWbemServices;
  1137. pIWbemServices.Attach( m_pWbemServices->GetIWbemServices ());
  1138. if (pIWbemServices)
  1139. {
  1140. CSWbemSecurity *pSecurity = m_pWbemServices->GetSecurityInfo ();
  1141. if (pSecurity)
  1142. {
  1143. bool needToResetSecurity = false;
  1144. HANDLE hThreadToken = NULL;
  1145. if (pSecurity->SetSecurity (needToResetSecurity, hThreadToken))
  1146. pIWbemServices->GetObject (vClassName.bstrVal, 0, NULL, &m_pWbemClass, NULL);
  1147. // Restore original privileges on this thread
  1148. if (needToResetSecurity)
  1149. pSecurity->ResetSecurity (hThreadToken);
  1150. pSecurity->Release ();
  1151. }
  1152. }
  1153. }
  1154. }
  1155. }
  1156. }
  1157. }
  1158. }
  1159. //***************************************************************************
  1160. //
  1161. // SCODE CWbemDispatchMgr::HandleError
  1162. //
  1163. // DESCRIPTION:
  1164. //
  1165. // Provide bespoke handling of error conditions in the bolierplate
  1166. // Dispatch implementation.
  1167. //
  1168. // PARAMETERS:
  1169. //
  1170. // dispidMember, wFlags,
  1171. // pdispparams, pvarResult,
  1172. // puArgErr, All passed directly from IDispatch::Invoke
  1173. // hr The return code from the bolierplate invoke
  1174. //
  1175. // RETURN VALUES:
  1176. // The new return code (to be ultimately returned from Invoke)
  1177. //
  1178. // WBEM_S_NO_ERROR success
  1179. // WBEM_E_INVALID_PARAMETER bad input parameters
  1180. // WBEM_E_FAILED otherwise
  1181. //
  1182. //***************************************************************************
  1183. HRESULT CWbemDispatchMgr::HandleError (
  1184. DISPID dispidMember,
  1185. unsigned short wFlags,
  1186. DISPPARAMS FAR* pdispparams,
  1187. VARIANT FAR* pvarResult,
  1188. UINT FAR* puArgErr,
  1189. HRESULT hr
  1190. )
  1191. {
  1192. /*
  1193. * We are looking for GET calls on the Derivation_ property which
  1194. * supplied an argument. Since this property returns a SAFEARRAY, this may
  1195. * be legal but undetectable by the standard Dispatch mechanism. It is meaningful
  1196. * to pass an index (the interpretation is that the index specifies an offset in
  1197. * the SAFEARRAY structure that represents the derivation value).
  1198. */
  1199. if ((dispidMember == WBEMS_DISPID_DERIVATION) && (DISP_E_NOTACOLLECTION == hr) && (1 == pdispparams->cArgs)
  1200. && (DISPATCH_PROPERTYGET & wFlags))
  1201. {
  1202. // Looks promising - get the __DERIVATION property to try and resolve this
  1203. if (m_pWbemObject)
  1204. {
  1205. VARIANT var;
  1206. VariantInit (&var);
  1207. if (WBEM_S_NO_ERROR == m_pWbemObject->Get (WBEMS_SP_DERIVATION, 0, &var, NULL, NULL))
  1208. {
  1209. /* The value should be a VT_BSTR|VT_ARRAY */
  1210. if (((VT_ARRAY | VT_BSTR) == var.vt) && (NULL != var.parray))
  1211. {
  1212. VARIANT indexVar;
  1213. VariantInit (&indexVar);
  1214. // Attempt to coerce the index argument into a value suitable for an array index
  1215. if (S_OK == VariantChangeType (&indexVar, &pdispparams->rgvarg[0], 0, VT_I4))
  1216. {
  1217. long lArrayPropInx = V_I4(&indexVar);
  1218. // We should have a VT_ARRAY|VT_BSTR value at this point; extract the
  1219. // BSTR and set it into the VARIANT
  1220. VariantInit (pvarResult);
  1221. BSTR nameValue = NULL;
  1222. if (SUCCEEDED(hr = SafeArrayGetElement (var.parray, &lArrayPropInx, &nameValue)))
  1223. {
  1224. VariantInit (pvarResult);
  1225. pvarResult->vt = VT_BSTR;
  1226. pvarResult->bstrVal = nameValue;
  1227. }
  1228. }
  1229. else
  1230. {
  1231. hr = DISP_E_TYPEMISMATCH;
  1232. if (puArgErr)
  1233. *puArgErr = 0;
  1234. }
  1235. VariantClear (&indexVar);
  1236. }
  1237. }
  1238. VariantClear (&var);
  1239. }
  1240. }
  1241. return hr;
  1242. }
  1243. // IDispatchEx methods
  1244. HRESULT STDMETHODCALLTYPE CWbemDispatchMgr::GetDispID(
  1245. /* [in] */ BSTR bstrName,
  1246. /* [in] */ DWORD grfdex,
  1247. /* [out] */ DISPID __RPC_FAR *pid)
  1248. {
  1249. return GetIDsOfNames(IID_NULL, &((OLECHAR *)bstrName), 1, ENGLISH_LOCALE, pid);
  1250. }
  1251. //***************************************************************************
  1252. //
  1253. // SCODE CWbemSchemaIDCache::~CWbemSchemaIDCache
  1254. //
  1255. // DESCRIPTION:
  1256. //
  1257. // Destructor
  1258. //
  1259. //***************************************************************************
  1260. CWbemSchemaIDCache::~CWbemSchemaIDCache ()
  1261. {
  1262. DispIDNameMap::iterator next;
  1263. while ((next = m_cache.begin ()) != m_cache.end ())
  1264. next = m_cache.erase (next);
  1265. }
  1266. //***************************************************************************
  1267. //
  1268. // SCODE CWbemSchemaIDCache::GetDispID
  1269. //
  1270. // DESCRIPTION:
  1271. //
  1272. // Attempts to resolves a set of names to DISP IDs based on WMI schema.
  1273. //
  1274. // PARAMETERS:
  1275. //
  1276. // rgszNames Array of names
  1277. // cNames Length of above array
  1278. // rgdispid Pointer to array to hold resolved DISPIDs
  1279. //
  1280. // RETURN VALUES:
  1281. //
  1282. //***************************************************************************
  1283. HRESULT CWbemSchemaIDCache::GetDispID (
  1284. LPWSTR* rgszNames,
  1285. unsigned int cNames,
  1286. DISPID* rgdispid
  1287. )
  1288. {
  1289. HRESULT hr = E_FAIL;
  1290. if (0 < cNames)
  1291. {
  1292. DispIDNameMap::iterator theIterator = m_cache.find (rgszNames [0]);
  1293. if (theIterator != m_cache.end ())
  1294. {
  1295. hr = S_OK;
  1296. rgdispid [0] = (*theIterator).second;
  1297. }
  1298. else
  1299. {
  1300. if ((1 == cNames) && FindPropertyName (rgszNames [0]))
  1301. {
  1302. // Get a new dispid and add it to the cache
  1303. CWbemDispID dispId;
  1304. if (dispId.SetAsSchemaID (++m_nextId))
  1305. {
  1306. rgdispid [0] = dispId;
  1307. m_cache.insert (DispIDNameMap::value_type (rgszNames [0],
  1308. dispId));
  1309. hr = S_OK;
  1310. }
  1311. }
  1312. else
  1313. {
  1314. //If no property name matches, go on to methods
  1315. SAFEARRAY *psaInParams = NULL; //array of in parameters names
  1316. SAFEARRAY *psaOutParams = NULL; //array of out parameter names
  1317. CComPtr<IWbemClassObject> pInParams;
  1318. CComPtr<IWbemClassObject> pOutParams;
  1319. bool bMethodFound = false;
  1320. long id = 0;
  1321. bool bUnknownParameterFound = false;
  1322. //Get the names of all method parameters (in and out)
  1323. if (GetMethod (rgszNames[0], &psaInParams, &psaOutParams,
  1324. pInParams, pOutParams))
  1325. {
  1326. bMethodFound = true;
  1327. unsigned long ulParamCount;
  1328. bool ok = true;
  1329. //For each named parameter, search for it in the method parameters
  1330. for (ulParamCount=1; ok && (ulParamCount < cNames); ulParamCount++)
  1331. {
  1332. //If we find this name in the "in" parameters list, attach the id and go on
  1333. if (psaInParams && FindMemberInArray(rgszNames[ulParamCount], psaInParams))
  1334. {
  1335. if (GetIdOfMethodParameter(rgszNames[ulParamCount], //param name
  1336. pInParams,
  1337. &id))
  1338. rgdispid[ulParamCount] = id;
  1339. else
  1340. ok = false;
  1341. }
  1342. //If it's not in the "in" parameters, check the "out" parameters list
  1343. else if (psaOutParams && FindMemberInArray(rgszNames[ulParamCount], psaOutParams))
  1344. {
  1345. if (GetIdOfMethodParameter(rgszNames[ulParamCount], //param name
  1346. pOutParams,
  1347. &id))
  1348. rgdispid[ulParamCount] = id;
  1349. else
  1350. ok = false;
  1351. }
  1352. //If it's not there either - we can't find it
  1353. else
  1354. {
  1355. rgdispid[ulParamCount] = DISPID_UNKNOWN;
  1356. bUnknownParameterFound = true;
  1357. }
  1358. } //walk parameters
  1359. if (!ok)
  1360. bMethodFound = false;
  1361. }
  1362. if (psaInParams)
  1363. SafeArrayDestroy(psaInParams);
  1364. if (psaOutParams)
  1365. SafeArrayDestroy(psaOutParams);
  1366. if (!bMethodFound)
  1367. hr = E_FAIL;
  1368. else if (bUnknownParameterFound)
  1369. hr = DISP_E_UNKNOWNNAME;
  1370. else
  1371. hr = S_OK;
  1372. // Finally, if this all worked add it to the cache as a method
  1373. if (SUCCEEDED(hr))
  1374. {
  1375. CWbemDispID dispId;
  1376. if (dispId.SetAsSchemaID (++m_nextId, false))
  1377. {
  1378. rgdispid [0] = dispId;
  1379. m_cache.insert (DispIDNameMap::value_type (rgszNames [0],
  1380. dispId));
  1381. }
  1382. else
  1383. hr = E_FAIL;
  1384. }
  1385. }
  1386. }
  1387. }
  1388. return hr;
  1389. }
  1390. //***************************************************************************
  1391. //
  1392. // bool CWbemSchemaIDCache::FindPropertyName
  1393. //
  1394. // DESCRIPTION:
  1395. //
  1396. // Determine whether the property exists for this object and is not
  1397. // a system property
  1398. //
  1399. // PARAMETERS:
  1400. //
  1401. // bsName - name of specified property
  1402. //
  1403. // RETURN VALUES:
  1404. //
  1405. //***************************************************************************
  1406. bool CWbemSchemaIDCache::FindPropertyName(
  1407. BSTR bsName
  1408. )
  1409. {
  1410. bool result = false;;
  1411. if (m_pDispatchMgr)
  1412. {
  1413. //
  1414. // beware that ->GetObject() DOES NOT Addref, so this one is OK
  1415. //
  1416. CComPtr<IWbemClassObject> pIWbemClassObject = m_pDispatchMgr->GetObject ();
  1417. if (pIWbemClassObject)
  1418. {
  1419. //Note : This limits the support to non-system properties only !!!
  1420. LONG lFlavor = 0;
  1421. if (SUCCEEDED(pIWbemClassObject->Get(bsName, 0, NULL, NULL, &lFlavor))
  1422. && !(WBEM_FLAVOR_ORIGIN_SYSTEM & lFlavor))
  1423. result = true;
  1424. }
  1425. }
  1426. return result;
  1427. }
  1428. //***************************************************************************
  1429. //
  1430. // bool CWbemSchemaIDCache::GetMethod
  1431. //
  1432. // DESCRIPTION:
  1433. //
  1434. // returns the parameter names of a method in two
  1435. // safearrays - one for in and one for out
  1436. //
  1437. // PARAMETERS:
  1438. //
  1439. // bstrMethodName - name of method requested
  1440. // ppsaInParams - pointer to safearray to return
  1441. // in parameters
  1442. // ppsaOutParams - pointer to safearray to return
  1443. // out parameters
  1444. //
  1445. // RETURN VALUES:
  1446. //
  1447. //***************************************************************************
  1448. bool CWbemSchemaIDCache::GetMethod(
  1449. BSTR bstrMethodName,
  1450. SAFEARRAY **ppsaInParams,
  1451. SAFEARRAY **ppsaOutParams,
  1452. CComPtr<IWbemClassObject> & pInParamsObject,
  1453. CComPtr<IWbemClassObject> & pOutParamsObject
  1454. )
  1455. {
  1456. bool result = false;
  1457. //
  1458. // Beware, GetClassObejct DOES NOT Addref, so this one is OK
  1459. //
  1460. CComPtr<IWbemClassObject> pIWbemClassObject = m_pDispatchMgr->GetClassObject ();
  1461. if (pIWbemClassObject)
  1462. {
  1463. if (SUCCEEDED(pIWbemClassObject->GetMethod(bstrMethodName, 0, &pInParamsObject, &pOutParamsObject)))
  1464. {
  1465. *ppsaInParams = NULL;
  1466. *ppsaOutParams = NULL;
  1467. bool ok = true;
  1468. if (pInParamsObject)
  1469. {
  1470. if (FAILED(pInParamsObject->GetNames(NULL, 0, NULL, ppsaInParams)))
  1471. ok = false;
  1472. }
  1473. if (ok && pOutParamsObject)
  1474. {
  1475. if (FAILED(pOutParamsObject->GetNames(NULL, 0, NULL, ppsaOutParams)))
  1476. ok = false;
  1477. }
  1478. result = ok;
  1479. }
  1480. }
  1481. return result;
  1482. }
  1483. //***************************************************************************
  1484. //
  1485. // bool CWbemSchemaIDCache::GetIdOfMethodParameter
  1486. //
  1487. // DESCRIPTION:
  1488. //
  1489. // gets the id of a given parameter for a given method
  1490. // (this is a qualifier on the parameter property in the
  1491. // InParameters/OutParameters object)
  1492. //
  1493. // PARAMETERS:
  1494. //
  1495. // bstrParamName - parameter name
  1496. // pParams - IWbemClassObject containing parameters
  1497. // pId - pointer to long to receive the ID for this
  1498. // parameter of this method
  1499. //
  1500. // RETURN VALUES:
  1501. //
  1502. //***************************************************************************
  1503. bool CWbemSchemaIDCache::GetIdOfMethodParameter(
  1504. BSTR bstrParamName,
  1505. CComPtr<IWbemClassObject> &pParams,
  1506. long *pId
  1507. )
  1508. {
  1509. bool result = false;
  1510. if (pParams)
  1511. {
  1512. CComPtr<IWbemQualifierSet> pQualSet;
  1513. //Get qualifier set for the required parameter property
  1514. if (SUCCEEDED(pParams->GetPropertyQualifierSet(bstrParamName, &pQualSet)))
  1515. {
  1516. CComVariant vIdVal;
  1517. //Get the "id" qualifier value
  1518. if (SUCCEEDED(pQualSet->Get(L"id", 0, &vIdVal, NULL)))
  1519. {
  1520. result = true;
  1521. *pId = vIdVal.lVal;
  1522. }
  1523. }
  1524. }
  1525. return result;
  1526. }
  1527. //***************************************************************************
  1528. //
  1529. // bool CWbemSchemaIDCache::GetName
  1530. //
  1531. // DESCRIPTION:
  1532. //
  1533. // gets the name of the item given a DISPID
  1534. //
  1535. // PARAMETERS:
  1536. //
  1537. // dispId - id whose name we require
  1538. // bsName - the name (on successful return)
  1539. //
  1540. // RETURN VALUES:
  1541. //
  1542. //***************************************************************************
  1543. bool CWbemSchemaIDCache::GetName (
  1544. DISPID dispId,
  1545. CComBSTR & bsName
  1546. )
  1547. {
  1548. bool result = false;
  1549. DispIDNameMap::iterator theIterator = m_cache.begin ();
  1550. while (theIterator != m_cache.end ())
  1551. {
  1552. if (dispId == (*theIterator).second)
  1553. {
  1554. bsName = (*theIterator).first;
  1555. result = true;
  1556. break;
  1557. }
  1558. else
  1559. theIterator++;
  1560. }
  1561. return result;
  1562. }
  1563. //***************************************************************************
  1564. //
  1565. // bool CWbemSchemaIDCache::FindMemberInArray
  1566. //
  1567. // DESCRIPTION:
  1568. //
  1569. // determine whether a name is present in a SAFEARRAY
  1570. //
  1571. // PARAMETERS:
  1572. //
  1573. // bstrName - the name we're looking for
  1574. // psaNames - SAFEARRAY we're looking in
  1575. //
  1576. // RETURN VALUES:
  1577. // true if found, false o/w
  1578. //
  1579. //***************************************************************************
  1580. bool CWbemSchemaIDCache::FindMemberInArray(BSTR bstrName, SAFEARRAY *psaNames)
  1581. {
  1582. long lUBound = -1;
  1583. long i;
  1584. //Walk the array and check if the requested name exists
  1585. SafeArrayGetUBound(psaNames, 1, &lUBound);
  1586. for (i=0; i <= lUBound; i++)
  1587. {
  1588. CComBSTR bstrMemberName;
  1589. if(SUCCEEDED(SafeArrayGetElement(psaNames, &i, &bstrMemberName))) // Bug ID 566345
  1590. {
  1591. if (!_wcsicmp(bstrMemberName, bstrName)) //found the property
  1592. break;
  1593. }
  1594. else
  1595. {
  1596. return false;
  1597. }
  1598. }
  1599. return (i <= lUBound);
  1600. }