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.

5065 lines
115 KiB

  1. // extbase.cpp: implementation of the CEmbedForeignObj and CLinkForeignObj classes
  2. //
  3. // Copyright (c)1997-2001 Microsoft Corporation
  4. //
  5. // implement extension model's base classes
  6. //////////////////////////////////////////////////////////////////////
  7. #include "precomp.h"
  8. #include "sceprov.h"
  9. #include "extbase.h"
  10. #include "persistmgr.h"
  11. #include "requestobject.h"
  12. //
  13. // just some constants. Don't hardcode literals!
  14. //
  15. LPCWSTR pszMethodPrefix = L"Sce_";
  16. LPCWSTR pszMethodPostfix = L"_Method";
  17. LPCWSTR pszEquivalentPutInstance = L"Sce_MethodCall_PutInstance";
  18. LPCWSTR pszEquivalentDelInstance = L"Sce_MethodCall_DelInstance";
  19. LPCWSTR pszInParameterPrefix = L"Sce_Param_";
  20. LPCWSTR pszMemberParameterPrefix = L"Sce_Member_";
  21. LPCWSTR pszAreaAttachmentClasses = L"Attachment Classes";
  22. LPCWSTR pszForeignNamespace = L"ForeignNamespace";
  23. LPCWSTR pszForeignClassName = L"ForeignClassName";
  24. LPCWSTR pszDelInstance = L"DelInstance";
  25. LPCWSTR pszPutInstance = L"PutInstance";
  26. LPCWSTR pszPopInstance = L"PopInstance";
  27. //
  28. // The method encoding string only contains PutInstance call
  29. //
  30. const DWORD SCE_METHOD_ENCODE_PUT_ONLY = 0x00000001;
  31. //
  32. // The method encoding string only contains DelInstance call
  33. //
  34. const DWORD SCE_METHOD_ENCODE_DEL_ONLY = 0x00000002;
  35. //====================================================================
  36. //
  37. // implementation of CExtClasses
  38. // there will be a shared (global) instance of this class. That is why
  39. // we need protections against data by using a critical section.
  40. //
  41. /*
  42. Routine Description:
  43. Name:
  44. CExtClasses::CExtClasses
  45. Functionality:
  46. constructor.
  47. Virtual:
  48. No.
  49. Arguments:
  50. None.
  51. Return Value:
  52. none
  53. Notes:
  54. */
  55. CExtClasses::CExtClasses ()
  56. :
  57. m_bPopulated(false)
  58. {
  59. }
  60. /*
  61. Routine Description:
  62. Name:
  63. CExtClasses::~CExtClasses
  64. Functionality:
  65. Destructor. Cleaning up the map managed bstr names (first) and map managed
  66. CForeignClassInfo heap objects (second).
  67. Virtual:
  68. No.
  69. Arguments:
  70. None.
  71. Return Value:
  72. none
  73. Notes:
  74. */
  75. CExtClasses::~CExtClasses()
  76. {
  77. ExtClassIterator it = m_mapExtClasses.begin();
  78. ExtClassIterator itEnd = m_mapExtClasses.end();
  79. while(it != itEnd)
  80. {
  81. //
  82. // first is a bstr
  83. //
  84. ::SysFreeString((*it).first);
  85. //
  86. // second is a CForeignClassInfo. It knows how to delete.
  87. //
  88. delete (*it).second;
  89. it++;
  90. }
  91. m_mapExtClasses.clear();
  92. }
  93. /*
  94. Routine Description:
  95. Name:
  96. CExtClasses::PopulateExtensionClasses
  97. Functionality:
  98. Gather information for all embedding classes.
  99. Virtual:
  100. No.
  101. Arguments:
  102. pNamespace - The namespace.
  103. pCtx - something that WMI passes around. WMI may require it in the future.
  104. Return Value:
  105. Success : success code from CreateClassEnum.
  106. Failure: error code from CreateClassEnum.
  107. Notes:
  108. This is private helper. Only called by our GetForeignClassInfo function if it
  109. finds that we haven't populated ourselves. Since thread protection is done
  110. over there, we don't do it here any more. don't make it available to other classes
  111. unless you make necessary changes to protect the data.
  112. */
  113. HRESULT
  114. CExtClasses::PopulateExtensionClasses (
  115. IN IWbemServices * pNamespace,
  116. IN IWbemContext * pCtx
  117. )
  118. {
  119. if (pNamespace == NULL)
  120. {
  121. return WBEM_E_INVALID_PARAMETER;
  122. }
  123. HRESULT hr = WBEM_NO_ERROR;
  124. if (!m_bPopulated)
  125. {
  126. CComPtr<IEnumWbemClassObject> srpEnum;
  127. //
  128. // try to enumerate all embed classes
  129. //
  130. CComBSTR bstrEmbedSuperClass(SCEWMI_EMBED_BASE_CLASS);
  131. hr = pNamespace->CreateClassEnum(bstrEmbedSuperClass,
  132. WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY,
  133. pCtx,
  134. &srpEnum
  135. );
  136. if (SUCCEEDED(hr))
  137. {
  138. //
  139. // irgnore the result. It may or may not have any extension
  140. //
  141. GetSubclasses(pNamespace, pCtx, srpEnum, EXT_CLASS_TYPE_EMBED);
  142. }
  143. // now, let's enumerate all link classes
  144. //srpEnum.Release();
  145. //CComBSTR bstrLinkSuperClass(SCEWMI_LINK_BASE_CLASS);
  146. //hr = pNamespace->CreateClassEnum(bstrLinkSuperClass,
  147. // WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY,
  148. // pCtx,
  149. // &srpEnum
  150. // );
  151. //if (SUCCEEDED(hr))
  152. // GetSubclasses(pNamespace, pCtx, srpEnum, EXT_CLASS_TYPE_LINK); //irgnore the result. It may or may not have any extension
  153. m_bPopulated = true;
  154. }
  155. return hr;
  156. }
  157. /*
  158. Routine Description:
  159. Name:
  160. CExtClasses::PutExtendedClass
  161. Functionality:
  162. Put a foreign class information and its embedding class name into our map.
  163. Virtual:
  164. No.
  165. Arguments:
  166. bstrEmbedClassName - the embedding class's name.
  167. pFCI - the foreign class info of the embedding class.
  168. Return Value:
  169. Success :
  170. (1) WBEM_NO_ERROR if the parameters are taken by the map. The map owns the resource.
  171. (2) WBEM_S_FALSE if the embed class name has already in the map. The map doesn't own the resource.
  172. Failure: WBEM_E_INVALID_PARAMETER.
  173. Notes:
  174. (1) This is private helper.
  175. (2) Caller shouldn't delete the parameters in any fashion. Our map owns the resource
  176. that is passed into the function unless we return WBEM_S_FALSE.
  177. (3) Don't make it available to other classes unless you make necessary changes
  178. for resource management.
  179. */
  180. HRESULT
  181. CExtClasses::PutExtendedClass (
  182. IN BSTR bstrEmbedClassName,
  183. IN CForeignClassInfo * pFCI
  184. )
  185. {
  186. if (bstrEmbedClassName == NULL ||
  187. *bstrEmbedClassName == L'\0' ||
  188. pFCI == NULL ||
  189. pFCI->bstrNamespace == NULL ||
  190. pFCI->bstrClassName == NULL )
  191. {
  192. return WBEM_E_INVALID_PARAMETER;
  193. }
  194. HRESULT hr = WBEM_NO_ERROR;
  195. g_CS.Enter();
  196. if (m_mapExtClasses.find(bstrEmbedClassName) == m_mapExtClasses.end())
  197. {
  198. m_mapExtClasses.insert(MapExtClasses::value_type(bstrEmbedClassName, pFCI));
  199. }
  200. else
  201. {
  202. hr = WBEM_S_FALSE;
  203. }
  204. g_CS.Leave();
  205. return hr;
  206. }
  207. /*
  208. Routine Description:
  209. Name:
  210. CExtClasses::GetForeignClassInfo
  211. Functionality:
  212. Return the requested embedding class's foreign class information.
  213. Virtual:
  214. No.
  215. Arguments:
  216. pNamespace - The namespace.
  217. pCtx - something that WMI passes around. WMI may require it in the future.
  218. bstrEmbedClassName - the embedding class's name.
  219. Return Value:
  220. Success :
  221. Non Null.
  222. Failure:
  223. NULL.
  224. Notes:
  225. (1) Please respect the returned pointer. It's constant and caller is no business to change it
  226. or deleting it.
  227. */
  228. const CForeignClassInfo *
  229. CExtClasses::GetForeignClassInfo (
  230. IN IWbemServices * pNamespace,
  231. IN IWbemContext * pCtx,
  232. IN BSTR bstrEmbedClassName
  233. )
  234. {
  235. //
  236. // if we haven't populated, we need to do it so. That is why
  237. // we need to protect from multi-threads.
  238. //
  239. g_CS.Enter();
  240. if (!m_bPopulated)
  241. {
  242. PopulateExtensionClasses(pNamespace, pCtx);
  243. }
  244. CForeignClassInfo* pInfo = NULL;
  245. ExtClassIterator it = m_mapExtClasses.find(bstrEmbedClassName);
  246. if (it != m_mapExtClasses.end())
  247. {
  248. pInfo = (*it).second;
  249. }
  250. g_CS.Leave();
  251. return pInfo;
  252. }
  253. /*
  254. Routine Description:
  255. Name:
  256. CExtClasses::GetForeignClassInfo
  257. Functionality:
  258. Return the requested embedding class's foreign class information.
  259. Virtual:
  260. No.
  261. Arguments:
  262. pNamespace - The namespace.
  263. pCtx - something that WMI passes around. WMI may require it in the future.
  264. pEnumObj - class enumerator.
  265. dwClassType - what type of extension class. Currently, we only have one (embedding).
  266. It is thus not used.
  267. Return Value:
  268. Success :
  269. Non Null.
  270. Failure:
  271. NULL.
  272. Notes:
  273. (1) Please respect the returned pointer. It's constant and caller is no business to change it
  274. or deleting it.
  275. */
  276. HRESULT
  277. CExtClasses::GetSubclasses (
  278. IN IWbemServices * pNamespace,
  279. IN IWbemContext * pCtx,
  280. IN IEnumWbemClassObject * pEnumObj,
  281. IN EnumExtClassType dwClassType
  282. )
  283. {
  284. ULONG nEnum = 0;
  285. HRESULT hr = WBEM_NO_ERROR;
  286. //
  287. // CScePropertyMgr helps us to access WMI object's properties.
  288. //
  289. CScePropertyMgr ScePropMgr;
  290. //
  291. // as long as we continue to discover more classes, keep looping.
  292. //
  293. while (true)
  294. {
  295. CComPtr<IWbemClassObject> srpObj;
  296. hr = pEnumObj->Next(WBEM_INFINITE, 1, &srpObj, &nEnum);
  297. //
  298. // either not found or some other errors. Stop the enumeration.
  299. //
  300. if (FAILED(hr) || srpObj == NULL)
  301. {
  302. break;
  303. }
  304. if (SUCCEEDED(hr) && nEnum > 0 )
  305. {
  306. VARIANT varClass;
  307. hr = srpObj->Get(L"__CLASS", 0, &varClass, NULL, NULL);
  308. if (SUCCEEDED(hr) && varClass.vt == VT_BSTR)
  309. {
  310. //
  311. // attach a different the WMI object to the property mgr.
  312. // This will always succeed.
  313. //
  314. ScePropMgr.Attach(srpObj);
  315. //
  316. // get the foreign namespace property and foreign class name property.
  317. // Both are critical.
  318. //
  319. CComBSTR bstrNamespace, bstrClassName;
  320. hr = ScePropMgr.GetProperty(pszForeignNamespace, &bstrNamespace);
  321. if (SUCCEEDED(hr))
  322. {
  323. hr = ScePropMgr.GetProperty(pszForeignClassName, &bstrClassName);
  324. }
  325. if (SUCCEEDED(hr))
  326. {
  327. //
  328. // we are ready to create the foreign class info
  329. //
  330. CForeignClassInfo *pNewSubclass = new CForeignClassInfo;
  331. if (pNewSubclass != NULL)
  332. {
  333. //
  334. // give the foreign class info namespace and class name bstrs
  335. //
  336. pNewSubclass->bstrNamespace = bstrNamespace.Detach();
  337. pNewSubclass->bstrClassName = bstrClassName.Detach();
  338. pNewSubclass->dwClassType = dwClassType;
  339. //
  340. // we need to know the key property names
  341. //
  342. hr = PopulateKeyPropertyNames(pNamespace, pCtx, varClass.bstrVal, pNewSubclass);
  343. if (SUCCEEDED(hr))
  344. {
  345. //
  346. // let the map owns everything
  347. //
  348. hr = PutExtendedClass(varClass.bstrVal, pNewSubclass);
  349. }
  350. if (WBEM_NO_ERROR == hr)
  351. {
  352. //
  353. // ownership taken
  354. //
  355. varClass.vt = VT_EMPTY;
  356. varClass.bstrVal = NULL;
  357. pNewSubclass = NULL;
  358. }
  359. else
  360. {
  361. ::VariantClear(&varClass);
  362. delete pNewSubclass;
  363. }
  364. }
  365. else
  366. {
  367. hr = WBEM_E_OUT_OF_MEMORY;
  368. break;
  369. }
  370. }
  371. else
  372. {
  373. //
  374. // somehow, can't get the class name or namespace, something is wrong with this class
  375. // but will try to continue for other classes?
  376. //
  377. ::VariantClear(&varClass);
  378. }
  379. }
  380. }
  381. }
  382. return hr;
  383. }
  384. /*
  385. Routine Description:
  386. Name:
  387. CExtClasses::PopulateKeyPropertyNames
  388. Functionality:
  389. Private helper. Will create the new CForeignClassInfo's key
  390. property name vector.
  391. Virtual:
  392. No.
  393. Arguments:
  394. pNamespace - The namespace.
  395. pCtx - something that WMI passes around. WMI may require it in the future.
  396. bstrClassName - class name.
  397. pNewSubclass - The new foreign class info object. Its m_pVecNames member must be NULL
  398. entering this function.
  399. Return Value:
  400. Success : WBEM_NO_ERROR.
  401. Failure: various error codes.
  402. Notes:
  403. */
  404. HRESULT
  405. CExtClasses::PopulateKeyPropertyNames (
  406. IN IWbemServices * pNamespace,
  407. IN IWbemContext * pCtx,
  408. IN BSTR bstrClassName,
  409. IN OUT CForeignClassInfo * pNewSubclass
  410. )
  411. {
  412. if (pNamespace == NULL ||
  413. pNewSubclass == NULL ||
  414. pNewSubclass->m_pVecKeyPropNames != NULL )
  415. {
  416. return WBEM_E_INVALID_PARAMETER;
  417. }
  418. //
  419. // get the class definition.
  420. //
  421. CComPtr<IWbemClassObject> srpObj;
  422. HRESULT hr = pNamespace->GetObject(bstrClassName, 0, pCtx, &srpObj, NULL);
  423. if (SUCCEEDED(hr))
  424. {
  425. //
  426. // create the key property names vector
  427. //
  428. pNewSubclass->m_pVecKeyPropNames = new std::vector<BSTR>;
  429. if (pNewSubclass->m_pVecKeyPropNames != NULL)
  430. {
  431. //
  432. // flag to indicate if there is any key properties
  433. //
  434. bool bHasKeyProperty = false;
  435. //
  436. // let's get the key properties. WBEM_FLAG_LOCAL_ONLY flag
  437. // indicates that we are not interested in base class's members.
  438. // Base class members are for embedding only and we know those.
  439. //
  440. hr = srpObj->BeginEnumeration(WBEM_FLAG_KEYS_ONLY | WBEM_FLAG_LOCAL_ONLY);
  441. while (SUCCEEDED(hr))
  442. {
  443. CComBSTR bstrName;
  444. hr = srpObj->Next(0, &bstrName, NULL, NULL, NULL);
  445. if (FAILED(hr) || WBEM_S_NO_MORE_DATA == hr)
  446. {
  447. break;
  448. }
  449. //
  450. // let the m_pVecKeyPropNames own the bstr.
  451. //
  452. pNewSubclass->m_pVecKeyPropNames->push_back(bstrName.Detach());
  453. bHasKeyProperty = true;
  454. }
  455. srpObj->EndEnumeration();
  456. //
  457. // don't find any key property name, ask it clean up the m_pVecKeyPropNames member.
  458. //
  459. if (!bHasKeyProperty)
  460. {
  461. pNewSubclass->CleanNames();
  462. }
  463. }
  464. else
  465. {
  466. hr = WBEM_E_OUT_OF_MEMORY;
  467. }
  468. }
  469. if (SUCCEEDED(hr))
  470. {
  471. hr = WBEM_NO_ERROR;
  472. }
  473. return hr;
  474. }
  475. //===================================================================
  476. //******** implementation of CSceExtBaseObject************************
  477. /*
  478. Routine Description:
  479. Name:
  480. CSceExtBaseObject::CSceExtBaseObject
  481. Functionality:
  482. Constructor
  483. Virtual:
  484. No.
  485. Arguments:
  486. None.
  487. Return Value:
  488. None.
  489. Notes:
  490. */
  491. CSceExtBaseObject::CSceExtBaseObject ()
  492. :
  493. m_pClsInfo(NULL)
  494. {
  495. }
  496. /*
  497. Routine Description:
  498. Name:
  499. CSceExtBaseObject::~CSceExtBaseObject
  500. Functionality:
  501. Destructor. Do a clean up.
  502. Virtual:
  503. No.
  504. Arguments:
  505. None.
  506. Return Value:
  507. None.
  508. Notes:
  509. Consider moving your extra clean up work in CleanUp function.
  510. */
  511. CSceExtBaseObject::~CSceExtBaseObject ()
  512. {
  513. CleanUp();
  514. }
  515. /*
  516. Routine Description:
  517. Name:
  518. CSceExtBaseObject::GetPersistPath
  519. Functionality:
  520. Return the store path of the embedding object.
  521. Virtual:
  522. Yes.
  523. Arguments:
  524. pbstrPath - Receives the store path.
  525. Return Value:
  526. Success:
  527. success codes.
  528. Failure:
  529. (1) E_UNEXPECTED if this object has no wbem object attached to it successfully.
  530. (2) WBEM_E_NOT_AVAILABLE if the store path can't be returned.
  531. (3) Other errors.
  532. Notes:
  533. */
  534. STDMETHODIMP
  535. CSceExtBaseObject::GetPersistPath (
  536. OUT BSTR* pbstrPath
  537. )
  538. {
  539. if (pbstrPath == NULL)
  540. {
  541. return WBEM_E_INVALID_PARAMETER;
  542. }
  543. HRESULT hr = WBEM_E_NOT_FOUND;
  544. if (m_srpWbemObject)
  545. {
  546. CComVariant varVal;
  547. hr = m_srpWbemObject->Get(pStorePath, 0, &varVal, NULL, NULL);
  548. if (SUCCEEDED(hr) && varVal.vt == VT_BSTR)
  549. {
  550. *pbstrPath = varVal.bstrVal;
  551. varVal.vt = VT_EMPTY;
  552. varVal.bstrVal = 0;
  553. }
  554. else
  555. {
  556. hr = WBEM_E_NOT_AVAILABLE;
  557. }
  558. }
  559. else
  560. {
  561. hr = E_UNEXPECTED;
  562. }
  563. return hr;
  564. }
  565. /*
  566. Routine Description:
  567. Name:
  568. CSceExtBaseObject::GetPersistPath
  569. Functionality:
  570. Return the embedding class name.
  571. Virtual:
  572. Yes.
  573. Arguments:
  574. pbstrClassName - Receive the embedding class name.
  575. Return Value:
  576. Success:
  577. WBEM_NO_ERROR.
  578. Failure:
  579. (1) WBEM_E_NOT_AVAILABLE if the store path can't be returned.
  580. (2) Other errors.
  581. Notes:
  582. */
  583. STDMETHODIMP
  584. CSceExtBaseObject::GetClassName (
  585. OUT BSTR* pbstrClassName
  586. )
  587. {
  588. if (pbstrClassName == NULL)
  589. {
  590. return WBEM_E_INVALID_PARAMETER;
  591. }
  592. *pbstrClassName = NULL;
  593. if ((LPCWSTR)m_bstrClassName != NULL)
  594. {
  595. *pbstrClassName = ::SysAllocString(m_bstrClassName);
  596. }
  597. else
  598. {
  599. return WBEM_E_NOT_AVAILABLE;
  600. }
  601. return (*pbstrClassName == NULL) ? WBEM_E_OUT_OF_MEMORY : WBEM_NO_ERROR;
  602. }
  603. /*
  604. Routine Description:
  605. Name:
  606. CSceExtBaseObject::GetLogPath
  607. Functionality:
  608. Return the log file path.
  609. Virtual:
  610. Yes.
  611. Arguments:
  612. pbstrClassName - Receive the embedding class name.
  613. Return Value:
  614. Success:
  615. WBEM_NO_ERROR.
  616. Failure:
  617. (1) WBEM_E_NOT_AVAILABLE if the store path can't be returned.
  618. (2) Other errors.
  619. Notes:
  620. */
  621. STDMETHODIMP
  622. CSceExtBaseObject::GetLogPath (
  623. OUT BSTR* pbstrPath
  624. )
  625. {
  626. if (pbstrPath == NULL)
  627. {
  628. return WBEM_E_INVALID_PARAMETER;
  629. }
  630. if ((LPCWSTR)m_bstrLogPath != NULL)
  631. {
  632. *pbstrPath = ::SysAllocString(m_bstrLogPath);
  633. }
  634. else
  635. {
  636. return WBEM_E_NOT_AVAILABLE;
  637. }
  638. return (*pbstrPath == NULL) ? WBEM_E_OUT_OF_MEMORY : WBEM_NO_ERROR;
  639. }
  640. /*
  641. Routine Description:
  642. Name:
  643. CSceExtBaseObject::Validate
  644. Functionality:
  645. Validate the object. Currently, there is no validation. This can change at any time.
  646. For example, if we decide to use XML, we might be able to validate using the DTD.
  647. Virtual:
  648. Yes.
  649. Arguments:
  650. None.
  651. Return Value:
  652. Success:
  653. WBEM_NO_ERROR.
  654. Notes:
  655. */
  656. STDMETHODIMP
  657. CSceExtBaseObject::Validate ()
  658. {
  659. return WBEM_NO_ERROR;
  660. }
  661. /*
  662. Routine Description:
  663. Name:
  664. CSceExtBaseObject::GetProperty
  665. Functionality:
  666. Return the given property's value.
  667. Virtual:
  668. Yes.
  669. Arguments:
  670. pszPropName - Name of the property.
  671. pValue - Receives teh value in variant type.
  672. Return Value:
  673. Success:
  674. Various success codes.
  675. Failure:
  676. various errors.
  677. Notes:
  678. */
  679. STDMETHODIMP
  680. CSceExtBaseObject::GetProperty (
  681. IN LPCWSTR pszPropName,
  682. OUT VARIANT * pValue
  683. )
  684. {
  685. if (pszPropName == NULL || *pszPropName == L'\0' || pValue == NULL)
  686. {
  687. return WBEM_E_INVALID_PARAMETER;
  688. }
  689. //
  690. // we use index to access the property values.
  691. // Try keys first.
  692. //
  693. int iIndex = GetIndex(pszPropName, GIF_Keys);
  694. HRESULT hr = WBEM_E_NOT_FOUND;
  695. if (iIndex >= 0)
  696. {
  697. hr = ::VariantCopy(pValue, m_vecKeyValues[iIndex]);
  698. }
  699. else
  700. {
  701. //
  702. // it doesn't recognize as a key, so, try it as non-key property
  703. //
  704. iIndex = GetIndex(pszPropName, GIF_NonKeys);
  705. if (iIndex >= 0 && m_vecPropValues[iIndex] && m_vecPropValues[iIndex]->vt != VT_NULL)
  706. {
  707. hr = ::VariantCopy(pValue, m_vecPropValues[iIndex]);
  708. }
  709. else if (m_srpWbemObject)
  710. {
  711. hr = m_srpWbemObject->Get(pszPropName, 0, pValue, NULL, NULL);
  712. }
  713. }
  714. return hr;
  715. }
  716. /*
  717. Routine Description:
  718. Name:
  719. CSceExtBaseObject::GetProperty
  720. Functionality:
  721. Return the given type property count of the embedding class.
  722. Virtual:
  723. Yes.
  724. Arguments:
  725. type - Type of the property.
  726. pCount - Receives the given type property count.
  727. Return Value:
  728. Success:
  729. WBEM_NO_ERROR
  730. Failure:
  731. WBEM_E_INVALID_PARAMETER
  732. Notes:
  733. */
  734. STDMETHODIMP
  735. CSceExtBaseObject::GetPropertyCount (
  736. IN SceObjectPropertyType type,
  737. OUT DWORD * pCount
  738. )
  739. {
  740. if (type == SceProperty_Invalid || pCount == NULL)
  741. {
  742. return WBEM_E_INVALID_PARAMETER;
  743. }
  744. *pCount = 0;
  745. if (type == SceProperty_Key)
  746. {
  747. *pCount = (DWORD)m_vecKeyProps.size();
  748. }
  749. else
  750. {
  751. *pCount = (DWORD)m_vecNonKeyProps.size();
  752. }
  753. return WBEM_NO_ERROR;
  754. }
  755. /*
  756. Routine Description:
  757. Name:
  758. CSceExtBaseObject::GetPropertyValue
  759. Functionality:
  760. Return the given property's name and, if requested, also its value.
  761. Virtual:
  762. Yes.
  763. Arguments:
  764. type - Type of the property.
  765. dwIndex - Receives the given type property count.
  766. pbstrPropName - The property's name.
  767. pValue - Receives the property's value in variant. It the caller is not interested
  768. in receive the value, it can pass in NULL.
  769. Return Value:
  770. Success:
  771. WBEM_NO_ERROR if everything is retrieved correctly.
  772. WBEM_S_FALSE if the property value can't be retrieved.
  773. Failure:
  774. various error codes.
  775. Notes:
  776. If you request value (pValue != NULL) and we can't find it for you, then we won't supply
  777. the name either.
  778. But if you only request the name, as long as the index is correct (and has memory), we will
  779. give it back, regardless the value.
  780. */
  781. STDMETHODIMP
  782. CSceExtBaseObject::GetPropertyValue (
  783. IN SceObjectPropertyType type,
  784. IN DWORD dwIndex,
  785. OUT BSTR * pbstrPropName,
  786. OUT VARIANT * pValue OPTIONAL
  787. )
  788. {
  789. if (type == SceProperty_Invalid || pbstrPropName == NULL)
  790. {
  791. return WBEM_E_INVALID_PARAMETER;
  792. }
  793. *pbstrPropName = NULL;
  794. if (pValue)
  795. {
  796. ::VariantInit(pValue);
  797. }
  798. HRESULT hr = WBEM_NO_ERROR;
  799. CComBSTR bstrName;
  800. //
  801. // if it is asking for key property info
  802. //
  803. if (type == SceProperty_Key)
  804. {
  805. if (dwIndex >= m_vecKeyValues.size())
  806. {
  807. return WBEM_E_VALUE_OUT_OF_RANGE;
  808. }
  809. else
  810. {
  811. //
  812. // this is the name
  813. //
  814. bstrName = m_vecKeyProps[dwIndex];
  815. //
  816. // has a valid name
  817. //
  818. if (bstrName.Length() > 0)
  819. {
  820. //
  821. // only tried to supply the value if requested
  822. //
  823. if (pValue)
  824. {
  825. //
  826. // has value in its array. Any recently updated values will stay
  827. // in the array.
  828. //
  829. if (m_vecKeyValues[dwIndex])
  830. {
  831. hr = ::VariantCopy(pValue, m_vecKeyValues[dwIndex]);
  832. }
  833. else if (m_srpWbemObject)
  834. {
  835. //
  836. // otherwise, the value has not been updated, so
  837. // go ask the object itself
  838. //
  839. hr = m_srpWbemObject->Get(bstrName, 0, pValue, NULL, NULL);
  840. }
  841. if (pValue->vt == VT_NULL || pValue->vt == VT_EMPTY)
  842. {
  843. //
  844. // if the object doesn't have that value, try the key chain
  845. //
  846. hr = m_srpKeyChain->GetKeyPropertyValue(bstrName, pValue);
  847. //
  848. // m_srpKeyChain->GetKeyPropertyValue returns WBEM_S_FALSE if it can't be found
  849. //
  850. }
  851. }
  852. }
  853. else
  854. {
  855. hr = WBEM_E_OUT_OF_MEMORY;
  856. }
  857. }
  858. }
  859. else if (type == SceProperty_NonKey)
  860. {
  861. //
  862. // it is requesting non-key value
  863. //
  864. if (dwIndex >= m_vecPropValues.size())
  865. {
  866. return WBEM_E_VALUE_OUT_OF_RANGE;
  867. }
  868. else
  869. {
  870. //
  871. // this is the name
  872. //
  873. bstrName = m_vecNonKeyProps[dwIndex];
  874. if (bstrName.Length() > 0)
  875. {
  876. //
  877. // only tried to supply the value if requested
  878. //
  879. if (pValue)
  880. {
  881. //
  882. // has value in its array. Any recently updated values will stay
  883. // in the array.
  884. //
  885. if (m_vecPropValues[dwIndex])
  886. {
  887. hr = ::VariantCopy(pValue, m_vecPropValues[dwIndex]);
  888. }
  889. else if (m_srpWbemObject)
  890. {
  891. //
  892. // otherwise, the value has not been updated, so
  893. // go ask the object itself
  894. //
  895. hr = m_srpWbemObject->Get(bstrName, 0, pValue, NULL, NULL);
  896. }
  897. }
  898. }
  899. else
  900. {
  901. hr = WBEM_E_OUT_OF_MEMORY;
  902. }
  903. }
  904. }
  905. else
  906. {
  907. hr = WBEM_E_INVALID_PARAMETER;
  908. }
  909. if (SUCCEEDED(hr))
  910. {
  911. //
  912. // we give the name only if we have successfully grabbed the value (when requested).
  913. //
  914. *pbstrPropName = bstrName.Detach();
  915. hr = WBEM_NO_ERROR;
  916. }
  917. return hr;
  918. }
  919. /*
  920. Routine Description:
  921. Name:
  922. CSceExtBaseObject::Attach
  923. Functionality:
  924. Attach a wbem object to this object.
  925. Virtual:
  926. Yes.
  927. Arguments:
  928. pInst - the wbem object to be attached.
  929. Return Value:
  930. Success:
  931. WBEM_NO_ERROR
  932. Failure:
  933. WBEM_E_INVALID_PARAMETER.
  934. Notes:
  935. You can call this repeatedly. However, passing a different kind of class object
  936. will lead to undefined behavior because all property names are not updated here.
  937. */
  938. STDMETHODIMP
  939. CSceExtBaseObject::Attach (
  940. IN IWbemClassObject * pInst
  941. )
  942. {
  943. if (pInst == NULL)
  944. {
  945. return WBEM_E_INVALID_PARAMETER;
  946. }
  947. //
  948. // this opertor::= will release the previous object and assign the new one.
  949. // all ref count is donw automatically
  950. //
  951. m_srpWbemObject = pInst;
  952. return WBEM_NO_ERROR;
  953. }
  954. /*
  955. Routine Description:
  956. Name:
  957. CSceExtBaseObject::GetClassObject
  958. Functionality:
  959. Attach a wbem object to this object.
  960. Virtual:
  961. Yes.
  962. Arguments:
  963. ppInst - Receives the attached wbem object.
  964. Return Value:
  965. Success:
  966. S_OK
  967. Failure:
  968. (1) E_UNEXPECTED if no attachment has succeeded.
  969. Notes:
  970. Be aware, don't blindly simplify
  971. m_srpWbemObject->QueryInterface(...);
  972. to assignment:
  973. *ppInst = m_srpWbemObject;
  974. Two reasons:
  975. (1) We may change what is being cached to something else in the future.
  976. (2) Out-bound interface pointer must be AddRef'ed.
  977. */
  978. STDMETHODIMP
  979. CSceExtBaseObject::GetClassObject (
  980. OUT IWbemClassObject ** ppInst
  981. )
  982. {
  983. if (m_srpWbemObject == NULL)
  984. {
  985. return E_UNEXPECTED;
  986. }
  987. else
  988. {
  989. return m_srpWbemObject->QueryInterface(IID_IWbemClassObject, (void**)ppInst);
  990. }
  991. }
  992. /*
  993. Routine Description:
  994. Name:
  995. CSceExtBaseObject::CleanUp
  996. Functionality:
  997. Clean up itself.
  998. Virtual:
  999. No.
  1000. Arguments:
  1001. None.
  1002. Return Value:
  1003. None
  1004. Notes:
  1005. (1) Make sure that you empty the vectors! Cleanup its contents is not enough because
  1006. this function may be called elsewhere.
  1007. */
  1008. void CSceExtBaseObject::CleanUp()
  1009. {
  1010. //
  1011. // m_vecKeyProps and m_vecNonKeyProps just keeps bstrs
  1012. //
  1013. std::vector<BSTR>::iterator itBSTR;
  1014. for (itBSTR = m_vecKeyProps.begin(); itBSTR != m_vecKeyProps.end(); itBSTR++)
  1015. {
  1016. ::SysFreeString(*itBSTR);
  1017. }
  1018. m_vecKeyProps.empty();
  1019. for (itBSTR = m_vecNonKeyProps.begin(); itBSTR != m_vecNonKeyProps.end(); itBSTR++)
  1020. {
  1021. ::SysFreeString(*itBSTR);
  1022. }
  1023. m_vecNonKeyProps.empty();
  1024. //
  1025. // m_vecKeyValues and m_vecPropValues just keeps variant pointers.
  1026. // So, you need to clear the variant, and delete the pointers.
  1027. //
  1028. std::vector<VARIANT*>::iterator itVar;
  1029. for (itVar = m_vecKeyValues.begin(); itVar != m_vecKeyValues.end(); itVar++)
  1030. {
  1031. if (*itVar != NULL)
  1032. {
  1033. ::VariantClear(*itVar);
  1034. delete (*itVar);
  1035. }
  1036. }
  1037. m_vecKeyValues.empty();
  1038. for (itVar = m_vecPropValues.begin(); itVar != m_vecPropValues.end(); itVar++)
  1039. {
  1040. if (*itVar != NULL)
  1041. {
  1042. ::VariantClear(*itVar);
  1043. delete (*itVar);
  1044. }
  1045. }
  1046. m_vecPropValues.empty();
  1047. }
  1048. /*
  1049. Routine Description:
  1050. Name:
  1051. CSceExtBaseObject::PopulateProperties
  1052. Functionality:
  1053. This function is what populates our vectors. We discover the key properties
  1054. and non-key properties at this stage.
  1055. Will use the key chain to populate the key properties.
  1056. But we will also set the non-key properties to empty values.
  1057. Virtual:
  1058. No.
  1059. Arguments:
  1060. pKeyChain - The key chain that contains the key information.
  1061. pNamespace - the namespace.
  1062. pCtx - the context pointer passing around for WMI API's.
  1063. pClsInfo - The foreign class info.
  1064. Return Value:
  1065. Success:
  1066. various success codes.
  1067. Failure:
  1068. various error codes.
  1069. Notes:
  1070. */
  1071. HRESULT
  1072. CSceExtBaseObject::PopulateProperties (
  1073. IN ISceKeyChain * pKeyChain,
  1074. IN IWbemServices * pNamespace,
  1075. IN IWbemContext * pCtx,
  1076. IN const CForeignClassInfo * pClsInfo
  1077. )
  1078. {
  1079. //
  1080. // cache these critical information for later use.
  1081. //
  1082. m_srpKeyChain = pKeyChain;
  1083. m_srpNamespace = pNamespace;
  1084. m_srpCtx = pCtx;
  1085. m_pClsInfo = pClsInfo;
  1086. //
  1087. // get the class's defintion
  1088. //
  1089. //
  1090. // clean up the stale pointer
  1091. //
  1092. m_srpWbemObject.Release();
  1093. m_bstrClassName.Empty();
  1094. HRESULT hr = m_srpKeyChain->GetClassName(&m_bstrClassName);
  1095. if (SUCCEEDED(hr))
  1096. {
  1097. hr = m_srpNamespace->GetObject(m_bstrClassName, 0, m_srpCtx, &m_srpWbemObject, NULL);
  1098. if (SUCCEEDED(hr))
  1099. {
  1100. //
  1101. // let's get the key properties.
  1102. // WBEM_FLAG_LOCAL_ONLY means that we don't care about base class members.
  1103. //
  1104. hr = m_srpWbemObject->BeginEnumeration(WBEM_FLAG_KEYS_ONLY | WBEM_FLAG_LOCAL_ONLY);
  1105. while (SUCCEEDED(hr))
  1106. {
  1107. //
  1108. // get the current key property name
  1109. //
  1110. CComBSTR bstrName;
  1111. hr = m_srpWbemObject->Next(0, &bstrName, NULL, NULL, NULL);
  1112. if (FAILED(hr) || WBEM_S_NO_MORE_DATA == hr)
  1113. {
  1114. break;
  1115. }
  1116. //
  1117. // prevent duplication. Push the newly discovered key to the vectors.
  1118. // We won't pull down the values.
  1119. //
  1120. if (GetIndex(bstrName, GIF_Keys) < 0)
  1121. {
  1122. m_vecKeyProps.push_back(bstrName.Detach());
  1123. m_vecKeyValues.push_back(NULL);
  1124. }
  1125. }
  1126. m_srpWbemObject->EndEnumeration();
  1127. if (FAILED(hr))
  1128. {
  1129. return hr;
  1130. }
  1131. //
  1132. // now get non-key properties. The absence of WBEM_FLAG_KEYS_ONLY means non-key.
  1133. // WBEM_FLAG_LOCAL_ONLY means that we don't care about base class members.
  1134. //
  1135. hr = m_srpWbemObject->BeginEnumeration(WBEM_FLAG_LOCAL_ONLY);
  1136. while (SUCCEEDED(hr) && WBEM_S_NO_MORE_DATA != hr)
  1137. {
  1138. //
  1139. // get the current non-key property name
  1140. //
  1141. CComBSTR bstrName;
  1142. hr = m_srpWbemObject->Next(0, &bstrName, NULL, NULL, NULL);
  1143. if (FAILED(hr) || WBEM_S_NO_MORE_DATA == hr)
  1144. {
  1145. break;
  1146. }
  1147. //
  1148. // prevent duplicate the non-key properties
  1149. // We won't pull down the values.
  1150. //
  1151. if (GetIndex(bstrName, GIF_Both) < 0)
  1152. {
  1153. m_vecNonKeyProps.push_back(bstrName.Detach());
  1154. m_vecPropValues.push_back(NULL);
  1155. }
  1156. }
  1157. m_srpWbemObject->EndEnumeration();
  1158. }
  1159. }
  1160. return hr;
  1161. }
  1162. /*
  1163. Routine Description:
  1164. Name:
  1165. CSceExtBaseObject::GetIndex
  1166. Functionality:
  1167. Get the index of the property.
  1168. Virtual:
  1169. No.
  1170. Arguments:
  1171. pszPropName - The property's name.
  1172. fKey - Flag for get index. You can OR the flags (GIF_Both) for looking
  1173. up in both key and non-key names.
  1174. Return Value:
  1175. Success:
  1176. index of the property.
  1177. Failure:
  1178. -1 if not found.
  1179. Notes:
  1180. $consider: We should consider using maps for quick lookup.
  1181. */
  1182. int
  1183. CSceExtBaseObject::GetIndex (
  1184. IN LPCWSTR pszPropName,
  1185. IN GetIndexFlags fKey
  1186. )
  1187. {
  1188. if (pszPropName == NULL || *pszPropName == L'\0')
  1189. {
  1190. return -1;
  1191. }
  1192. std::vector<BSTR>::iterator it;
  1193. int iIndex = 0;
  1194. if (fKey & GIF_Keys)
  1195. {
  1196. for (it = m_vecKeyProps.begin(); it != m_vecKeyProps.end(); it++, iIndex++)
  1197. {
  1198. if (_wcsicmp(*it, pszPropName) == 0)
  1199. {
  1200. return iIndex;
  1201. }
  1202. }
  1203. }
  1204. if (fKey & GIF_NonKeys)
  1205. {
  1206. for (it = m_vecNonKeyProps.begin(); it != m_vecNonKeyProps.end(); it++, iIndex++)
  1207. {
  1208. if (_wcsicmp(*it, pszPropName) == 0)
  1209. {
  1210. return iIndex;
  1211. }
  1212. }
  1213. }
  1214. return -1;
  1215. }
  1216. //=============================================================================
  1217. //******** implementation of CEmbedForeignObj**********************************
  1218. // this class implements the embedding model for SCE provider. A foreign
  1219. // object can be embedded into SCE namespace by declaring a class derived from
  1220. // Sce_EmbedFO (embed foreign object) in a MOF file. This design allows post
  1221. // release integration of foreign objects into SCE namespace.
  1222. //=============================================================================
  1223. /*
  1224. Routine Description:
  1225. Name:
  1226. CEmbedForeignObj::CEmbedForeignObj
  1227. Functionality:
  1228. Constructor. Passing the parameters to base constructor, plus initializing
  1229. the foreign class info pointer.
  1230. Virtual:
  1231. No.
  1232. Arguments:
  1233. pKeyChain - The key chain.
  1234. pNamespace - Namespace
  1235. pCtx - The context pointer passing around for WMI API's.
  1236. pClsInfo - The foreign class info.
  1237. Return Value:
  1238. None.
  1239. Notes:
  1240. */
  1241. CEmbedForeignObj::CEmbedForeignObj (
  1242. IN ISceKeyChain * pKeyChain,
  1243. IN IWbemServices * pNamespace,
  1244. IN IWbemContext * pCtx,
  1245. IN const CForeignClassInfo * pClsInfo
  1246. )
  1247. :
  1248. CGenericClass(pKeyChain, pNamespace, pCtx),
  1249. m_pClsInfo(pClsInfo)
  1250. {
  1251. }
  1252. /*
  1253. Routine Description:
  1254. Name:
  1255. CEmbedForeignObj::~CEmbedForeignObj
  1256. Functionality:
  1257. Destructor. Clean up.
  1258. Virtual:
  1259. Yes.
  1260. Arguments:
  1261. None.
  1262. Return Value:
  1263. None.
  1264. Notes:
  1265. */
  1266. CEmbedForeignObj::~CEmbedForeignObj ()
  1267. {
  1268. CleanUp();
  1269. }
  1270. /*
  1271. Routine Description:
  1272. Name:
  1273. CEmbedForeignObj::PutInst
  1274. Functionality:
  1275. Put an instance as instructed by WMI. Since this class implements Sce_EmbedFO's subclasses,
  1276. which is persistence oriented, this will cause the embedding class object's properties
  1277. to be saved in our store.
  1278. Virtual:
  1279. Yes.
  1280. Arguments:
  1281. pInst - COM interface pointer to the WMI class (Sce_PasswordPolicy) object.
  1282. pHandler - COM interface pointer for notifying WMI of any events.
  1283. pCtx - COM interface pointer. This interface is just something we pass around.
  1284. WMI may mandate it (not now) in the future. But we never construct
  1285. such an interface and so, we just pass around for various WMI API's
  1286. Return Value:
  1287. Success: it must return success code (use SUCCEEDED to test). It is
  1288. not guaranteed to return WBEM_NO_ERROR.
  1289. Failure: Various errors may occurs. Any such error should indicate the failure of persisting
  1290. the instance.
  1291. Notes:
  1292. */
  1293. HRESULT
  1294. CEmbedForeignObj::PutInst (
  1295. IN IWbemClassObject * pInst,
  1296. IN IWbemObjectSink * pHandler,
  1297. IN IWbemContext * pCtx
  1298. )
  1299. {
  1300. //
  1301. // Look how trivial it is for us to save!
  1302. //
  1303. CComPtr<IScePersistMgr> srpScePersistMgr;
  1304. HRESULT hr = CreateScePersistMgr(pInst, &srpScePersistMgr);
  1305. if (SUCCEEDED(hr))
  1306. {
  1307. hr = srpScePersistMgr->Save();
  1308. }
  1309. return hr;
  1310. }
  1311. /*
  1312. Routine Description:
  1313. Name:
  1314. CEmbedForeignObj::CreateObject
  1315. Functionality:
  1316. Create WMI objects representing embedding classes (subclass of Sce_EmbedFO).
  1317. Depending on parameter atAction, this creation may mean:
  1318. (a) Get a single instance (atAction == ACTIONTYPE_GET)
  1319. (b) Get several instances satisfying some criteria (atAction == ACTIONTYPE_QUERY)
  1320. (c) Delete an instance (atAction == ACTIONTYPE_DELETE)
  1321. Virtual:
  1322. Yes.
  1323. Arguments:
  1324. pHandler - COM interface pointer for notifying WMI for creation result.
  1325. atAction - Get single instance ACTIONTYPE_GET
  1326. Get several instances ACTIONTYPE_QUERY
  1327. Delete a single instance ACTIONTYPE_DELETE
  1328. Return Value:
  1329. Success: it must return success code (use SUCCEEDED to test). It is
  1330. not guaranteed to return WBEM_NO_ERROR. The returned objects are indicated to WMI,
  1331. not directly passed back via parameters.
  1332. Failure: Various errors may occurs. Except WBEM_E_NOT_FOUND, any such error should indicate
  1333. the failure of getting the wanted instance. If WBEM_E_NOT_FOUND is returned in querying
  1334. situations, this may not be an error depending on caller's intention.
  1335. Notes:
  1336. */
  1337. HRESULT
  1338. CEmbedForeignObj::CreateObject (
  1339. IN IWbemObjectSink * pHandler,
  1340. IN ACTIONTYPE atAction
  1341. )
  1342. {
  1343. //
  1344. // we know how to:
  1345. // Get single instance ACTIONTYPE_GET
  1346. // Delete a single instance ACTIONTYPE_DELETE
  1347. // Get several instances ACTIONTYPE_QUERY
  1348. //
  1349. if ( ACTIONTYPE_GET != atAction &&
  1350. ACTIONTYPE_DELETE != atAction &&
  1351. ACTIONTYPE_QUERY != atAction )
  1352. {
  1353. return WBEM_E_NOT_SUPPORTED;
  1354. }
  1355. //
  1356. // We must have the pStorePath property because that is where
  1357. // our instance is stored.
  1358. // m_srpKeyChain->GetKeyPropertyValue WBEM_S_FALSE if the key is not recognized
  1359. // So, we need to test against WBEM_S_FALSE if the property is mandatory
  1360. //
  1361. CComVariant varPath;
  1362. HRESULT hr = m_srpKeyChain->GetKeyPropertyValue(pStorePath, &varPath);
  1363. if (FAILED(hr))
  1364. {
  1365. return hr;
  1366. }
  1367. else if (WBEM_S_FALSE == hr)
  1368. {
  1369. return WBEM_E_NOT_AVAILABLE;
  1370. }
  1371. //
  1372. // Now, this is embedding class loading.
  1373. // We let our persistence manager handle everything.
  1374. //
  1375. CComPtr<IScePersistMgr> srpScePersistMgr;
  1376. hr = CreateScePersistMgr(NULL, &srpScePersistMgr);
  1377. if (SUCCEEDED(hr))
  1378. {
  1379. if (atAction == ACTIONTYPE_GET || atAction == ACTIONTYPE_QUERY)
  1380. {
  1381. hr = srpScePersistMgr->Load(varPath.bstrVal, pHandler);
  1382. }
  1383. else if (atAction == ACTIONTYPE_DELETE)
  1384. {
  1385. hr = srpScePersistMgr->Delete(varPath.bstrVal, pHandler);
  1386. }
  1387. }
  1388. return hr;
  1389. }
  1390. /*
  1391. Routine Description:
  1392. Name:
  1393. CEmbedForeignObj::ExecMethod
  1394. Functionality:
  1395. This is perhaps the most important function. It executes a method on a foreign class/object.
  1396. Our embedding model is to allow us to persist foreign class information in our store. This
  1397. function is to use that stored information and goes to execute a method on the foreign class/object.
  1398. Each embedding class has a method encoding string. That string encodes the information as what we
  1399. should do on the foreign class/object when the embedding object is asked to execute a particular method.
  1400. The heavy duty work is done in CExtClassMethodCaller::ExecuteForeignMethod function.
  1401. Virtual:
  1402. Yes.
  1403. Arguments:
  1404. bstrPath - Template's path (file name).
  1405. bstrMethod - method's name.
  1406. bIsInstance - if this is an instance, should always be false.
  1407. pInParams - Input parameter from WMI to the method execution.
  1408. pHandler - sink that informs WMI of execution results.
  1409. pCtx - the usual context that passes around to make WMI happy.
  1410. Return Value:
  1411. Success: many different success code (use SUCCEEDED(hr) to test)
  1412. Failure: various errors code.
  1413. Notes:
  1414. Consider logging your result if you need to add more functionality.
  1415. */
  1416. HRESULT
  1417. CEmbedForeignObj::ExecMethod (
  1418. IN BSTR bstrPath,
  1419. IN BSTR bstrMethod,
  1420. IN bool bIsInstance,
  1421. IN IWbemClassObject * pInParams,
  1422. IN IWbemObjectSink * pHandler,
  1423. IN IWbemContext * pCtx
  1424. )
  1425. {
  1426. //
  1427. // this ISceClassObject provides us the access to the embeded class
  1428. //
  1429. CComPtr<ISceClassObject> srpSceObj;
  1430. HRESULT hr = CreateBaseObject(&srpSceObj);
  1431. if (SUCCEEDED(hr))
  1432. {
  1433. //
  1434. // get the object
  1435. //
  1436. CComPtr<IWbemClassObject> srpInst;
  1437. hr = m_srpNamespace->GetObject(bstrPath, 0, pCtx, &srpInst, NULL);
  1438. if (SUCCEEDED(hr))
  1439. {
  1440. srpSceObj->Attach(srpInst);
  1441. //
  1442. // we will use CExtClassMethodCaller to help us
  1443. //
  1444. CExtClassMethodCaller clsMethodCaller(srpSceObj, m_pClsInfo);
  1445. //
  1446. // CExtClassMethodCaller needs a result logging object
  1447. //
  1448. CMethodResultRecorder clsResLog;
  1449. //
  1450. // result log needs class name and log path. Don't let go these two variables
  1451. // since CMethodResultRecorder don't cache them
  1452. //
  1453. CComBSTR bstrClassName;
  1454. hr = m_srpKeyChain->GetClassName(&bstrClassName);
  1455. if (FAILED(hr))
  1456. {
  1457. return hr; // can't even log
  1458. }
  1459. // find the LogFilePath [in] parameter
  1460. CComVariant varVal;
  1461. hr = pInParams->Get(pLogFilePath, 0, &varVal, NULL, NULL);
  1462. //
  1463. // initialize the CMethodResultRecorder object
  1464. //
  1465. if (SUCCEEDED(hr) && varVal.vt == VT_BSTR && varVal.bstrVal)
  1466. {
  1467. hr = clsResLog.Initialize(varVal.bstrVal, bstrClassName, m_srpNamespace, pCtx);
  1468. }
  1469. else
  1470. {
  1471. //
  1472. // no LogFilePath, we will log it, but allow the method execution to continue
  1473. // because the logging will go to the default log file.
  1474. //
  1475. hr = clsResLog.Initialize(NULL, bstrClassName, m_srpNamespace, pCtx);
  1476. HRESULT hrLog = clsResLog.LogResult(WBEM_E_INVALID_PARAMETER, NULL, pInParams, NULL, bstrMethod, L"GetLogFilePath", IDS_GET_LOGFILEPATH, NULL);
  1477. if (FAILED(hrLog))
  1478. {
  1479. hr = hrLog;
  1480. }
  1481. }
  1482. //
  1483. // set up the CExtClassMethodCaller object
  1484. //
  1485. hr = clsMethodCaller.Initialize(&clsResLog);
  1486. if (SUCCEEDED(hr))
  1487. {
  1488. //
  1489. // now, call the method!
  1490. //
  1491. CComPtr<IWbemClassObject> srpOut;
  1492. hr = clsMethodCaller.ExecuteForeignMethod(bstrMethod, pInParams, pHandler, pCtx, &srpOut);
  1493. //
  1494. // let's allow verbose logging to log the embedded object. Will ignore the return result
  1495. //
  1496. clsResLog.LogResult(hr, srpInst, NULL, NULL, bstrMethod, L"ExecutedForeignMethods", IDS_EXE_FOREIGN_METHOD, NULL);
  1497. }
  1498. }
  1499. }
  1500. return hr;
  1501. }
  1502. /*
  1503. Routine Description:
  1504. Name:
  1505. CEmbedForeignObj::CreateBaseObject
  1506. Functionality:
  1507. Private helper to create the ISceClassObject object to represent ourselves in front
  1508. of CScePersistMgr.
  1509. Virtual:
  1510. No.
  1511. Arguments:
  1512. ppObj - receives the ISceClassObject on behalf of this embedding class.
  1513. Return Value:
  1514. Success: many different success code (use SUCCEEDED(hr) to test)
  1515. Failure: various errors code.
  1516. Notes:
  1517. */
  1518. HRESULT
  1519. CEmbedForeignObj::CreateBaseObject (
  1520. OUT ISceClassObject ** ppObj
  1521. )
  1522. {
  1523. CComObject<CSceExtBaseObject> *pExtBaseObj = NULL;
  1524. HRESULT hr = CComObject<CSceExtBaseObject>::CreateInstance(&pExtBaseObj);
  1525. if (SUCCEEDED(hr))
  1526. {
  1527. //
  1528. // if you wonder why we need this pair of AddRef and Release (just several lines below),
  1529. // just remember this rule: you can't use a CComObject<xxx> until you have AddRef'ed.
  1530. // Of course, this AddRef must have a matching Release.
  1531. //
  1532. pExtBaseObj->AddRef();
  1533. //
  1534. // This populates the object
  1535. //
  1536. hr = pExtBaseObj->PopulateProperties(m_srpKeyChain, m_srpNamespace, m_srpCtx, m_pClsInfo);
  1537. if (SUCCEEDED(hr))
  1538. {
  1539. hr = pExtBaseObj->QueryInterface(IID_ISceClassObject, (void**)ppObj);
  1540. }
  1541. pExtBaseObj->Release();
  1542. }
  1543. return hr;
  1544. }
  1545. /*
  1546. Routine Description:
  1547. Name:
  1548. CEmbedForeignObj::CreateScePersistMgr
  1549. Functionality:
  1550. Private helper to create the CScePersistMgr.
  1551. Virtual:
  1552. No.
  1553. Arguments:
  1554. pInst - The ultimate wbem object this CScePersistMgr will represent. In this impelmentation
  1555. this is what our ISceClassObject object will attach to.
  1556. ppPersistMgr - Receives the CScePersistMgr object.
  1557. Return Value:
  1558. Success: many different success code (use SUCCEEDED(hr) to test)
  1559. Failure: various errors code.
  1560. Notes:
  1561. */
  1562. HRESULT
  1563. CEmbedForeignObj::CreateScePersistMgr (
  1564. IN IWbemClassObject * pInst,
  1565. OUT IScePersistMgr ** ppPersistMgr
  1566. )
  1567. {
  1568. //
  1569. // create a ISceClassObject that the CScePersistMgr object needs
  1570. //
  1571. CComPtr<ISceClassObject> srpSceObj;
  1572. HRESULT hr = CreateBaseObject(&srpSceObj);
  1573. if (SUCCEEDED(hr))
  1574. {
  1575. if (pInst)
  1576. {
  1577. srpSceObj->Attach(pInst);
  1578. }
  1579. CComPtr<IScePersistMgr> srpScePersistMgr;
  1580. //
  1581. // now, create the CScePersistMgr object.
  1582. //
  1583. CComObject<CScePersistMgr> *pMgr = NULL;
  1584. hr = CComObject<CScePersistMgr>::CreateInstance(&pMgr);
  1585. if (SUCCEEDED(hr))
  1586. {
  1587. pMgr->AddRef();
  1588. hr = pMgr->QueryInterface(IID_IScePersistMgr, (void**)&srpScePersistMgr);
  1589. pMgr->Release();
  1590. if (SUCCEEDED(hr))
  1591. {
  1592. //
  1593. // this IScePersistMgr is for our newly created ISceClassObject
  1594. //
  1595. hr = srpScePersistMgr->Attach(IID_ISceClassObject, srpSceObj);
  1596. if (SUCCEEDED(hr))
  1597. {
  1598. //
  1599. // everything is fine. Hand it over the the out-bound parameter.
  1600. // This detach effectively transfers the srpScePersistMgr AddRef'ed
  1601. // interface pointer to the receiving *ppPersistMgr.
  1602. //
  1603. *ppPersistMgr = srpScePersistMgr.Detach();
  1604. }
  1605. }
  1606. }
  1607. }
  1608. return hr;
  1609. }
  1610. //===========================================================================
  1611. // CExtClassMethodCaller implementation
  1612. //===========================================================================
  1613. /*
  1614. Routine Description:
  1615. Name:
  1616. CExtClassMethodCaller::CExtClassMethodCaller
  1617. Functionality:
  1618. Constructor.
  1619. Virtual:
  1620. No.
  1621. Arguments:
  1622. pSceObj - Our custom object for each embedding class.
  1623. pClsInfo - The foreign class info.
  1624. Return Value:
  1625. None.
  1626. Notes:
  1627. */
  1628. CExtClassMethodCaller::CExtClassMethodCaller (
  1629. ISceClassObject * pSceObj,
  1630. const CForeignClassInfo * pClsInfo
  1631. )
  1632. :
  1633. m_srpSceObject(pSceObj),
  1634. m_pClsInfo(pClsInfo),
  1635. m_bStaticCall(true)
  1636. {
  1637. }
  1638. /*
  1639. Routine Description:
  1640. Name:
  1641. CExtClassMethodCaller::~CExtClassMethodCaller
  1642. Functionality:
  1643. Destructor.
  1644. Virtual:
  1645. No.
  1646. Arguments:
  1647. None.
  1648. Return Value:
  1649. None.
  1650. Notes:
  1651. */
  1652. CExtClassMethodCaller::~CExtClassMethodCaller()
  1653. {
  1654. }
  1655. /*
  1656. Routine Description:
  1657. Name:
  1658. CExtClassMethodCaller::Initialize
  1659. Functionality:
  1660. Initialize the object:
  1661. (1) First, it tries to find the foreign provider.
  1662. (2) Secondly, it asks the foreign provider if it recognizes the class.
  1663. Virtual:
  1664. No.
  1665. Arguments:
  1666. pLog - the object that does the logging. Can't be NULL
  1667. Return Value:
  1668. Success:
  1669. Various success code.
  1670. Failure:
  1671. (1) WBEM_E_INVALID_OBJECT if the object is not ready. It must be that the constructor
  1672. is not properly called.
  1673. (2) WBEM_E_INVALID_PARAMETER if pLog is NULL;
  1674. (3) Other error codes indicating other errors.
  1675. Notes:
  1676. */
  1677. HRESULT
  1678. CExtClassMethodCaller::Initialize (
  1679. IN CMethodResultRecorder * pLog
  1680. )
  1681. {
  1682. if (m_srpSceObject == NULL || m_pClsInfo == NULL)
  1683. {
  1684. return WBEM_E_INVALID_OBJECT;
  1685. }
  1686. else if (pLog == NULL)
  1687. {
  1688. return WBEM_E_INVALID_PARAMETER;
  1689. }
  1690. m_pLogRecord = pLog;
  1691. //
  1692. // try to find the foreign provider
  1693. //
  1694. CComPtr<IWbemLocator> srpLocator;
  1695. HRESULT hr = ::CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER,
  1696. IID_IWbemLocator, (LPVOID *) &srpLocator);
  1697. if (FAILED(hr))
  1698. {
  1699. return hr;
  1700. }
  1701. //
  1702. // try to get the foreign namespace of the foreign provider.
  1703. // Our foreign class info pointer has namespace information.
  1704. //
  1705. hr = srpLocator->ConnectServer(m_pClsInfo->bstrNamespace, NULL, NULL, NULL, 0, NULL, NULL, &m_srpForeignNamespace);
  1706. if (SUCCEEDED(hr))
  1707. {
  1708. //
  1709. // does the foreign provider really know this class?
  1710. //
  1711. hr = m_srpForeignNamespace->GetObject(m_pClsInfo->bstrClassName, 0, NULL, &m_srpClass, NULL);
  1712. //
  1713. // if it doesn't, this foreign provider is useless. Let it go.
  1714. //
  1715. if (FAILED(hr))
  1716. {
  1717. m_srpForeignNamespace.Release();
  1718. }
  1719. }
  1720. return hr;
  1721. }
  1722. /*
  1723. Routine Description:
  1724. Name:
  1725. CExtClassMethodCaller::ExecuteForeignMethod
  1726. Functionality:
  1727. This is the function that truly executes the method on the foreign class/object.
  1728. In order to accomplish this, we need to do many preparations:
  1729. (1) Phase 1. Find the method encoding string, and decipher what it means. We call this
  1730. the blockthe method call context preparation.
  1731. (2) Phase 2. Depending on the context, we go into the foreign class/object preparation phase.
  1732. If the encoding is so simple as to simply PutInstance/DelInstance, pretty much we are done.
  1733. (3) Phase 3: parameter preparation and individual method execution.
  1734. Virtual:
  1735. No.
  1736. Arguments:
  1737. pszMethod - The method name.
  1738. pInParams - the in parameter of the method.
  1739. pHandler - what we use to notify WMI.
  1740. pCtx - used to various WMI API's
  1741. ppOut - the out parameter.
  1742. Return Value:
  1743. Success:
  1744. Various success code.
  1745. Failure:
  1746. various error codes
  1747. Notes:
  1748. If you need to add more functionality, consider logging your results, regardless success or
  1749. failure. It's up to the logging options to determine if a success or failure will be logged.
  1750. */
  1751. HRESULT
  1752. CExtClassMethodCaller::ExecuteForeignMethod (
  1753. IN LPCWSTR pszMethod,
  1754. IN IWbemClassObject * pInParams,
  1755. IN IWbemObjectSink * pHandler,
  1756. IN IWbemContext * pCtx,
  1757. OUT IWbemClassObject ** ppOut
  1758. )
  1759. {
  1760. //
  1761. // get the class definition
  1762. //
  1763. CComPtr<IWbemClassObject> srpWbemObj;
  1764. HRESULT hr = m_srpSceObject->GetClassObject(&srpWbemObj);
  1765. CComVariant varForeignObjPath;
  1766. DWORD dwContext = 0;
  1767. HRESULT hrLog = WBEM_NO_ERROR;
  1768. //
  1769. // Phase 1. Method call context preparation
  1770. //
  1771. if (SUCCEEDED(hr))
  1772. {
  1773. //
  1774. // first, let us get the method encoding string
  1775. //
  1776. CComVariant varVal;
  1777. //
  1778. // try to see if there is a encoding string
  1779. //
  1780. //
  1781. // build the method encoding string property's name
  1782. //
  1783. LPWSTR pszEncodeStrName = new WCHAR[wcslen(pszMethodPrefix) + wcslen(pszMethod) + wcslen(pszMethodPostfix) + 1];
  1784. if (pszEncodeStrName == NULL)
  1785. {
  1786. hrLog = m_pLogRecord->LogResult(WBEM_E_OUT_OF_MEMORY, srpWbemObj, pInParams, NULL, pszMethod, L"GetMethodEncodingString", IDS_E_NAME_TOO_LONG, NULL);
  1787. return WBEM_E_OUT_OF_MEMORY;
  1788. }
  1789. wsprintf(pszEncodeStrName, L"%s%s%s", pszMethodPrefix, pszMethod, pszMethodPostfix);
  1790. //
  1791. // get the class's method encoding string
  1792. //
  1793. hr = srpWbemObj->Get(pszEncodeStrName, 0, &varVal, NULL, NULL);
  1794. //
  1795. // we are done with the encoding string property's name
  1796. //
  1797. delete [] pszEncodeStrName;
  1798. pszEncodeStrName = NULL;
  1799. //
  1800. // parse the encoding string to figure out the context, i.e.,
  1801. // how many methods there are, in what order, what are their parameters, etc.
  1802. //
  1803. if (SUCCEEDED(hr) && varVal.vt == VT_BSTR)
  1804. {
  1805. CComBSTR bstrError;
  1806. hr = ParseMethodEncodingString(varVal.bstrVal, &dwContext, &bstrError);
  1807. //
  1808. // if failed, we definitely want to log.
  1809. //
  1810. if (FAILED(hr))
  1811. {
  1812. hrLog = m_pLogRecord->LogResult(hr, srpWbemObj, pInParams, NULL, pszMethod, L"ParseEncodeString", IDS_E_ENCODE_ERROR, bstrError);
  1813. return hr;
  1814. }
  1815. }
  1816. else
  1817. {
  1818. //
  1819. // this method is not supported
  1820. //
  1821. hrLog = m_pLogRecord->LogResult(WBEM_E_NOT_SUPPORTED, srpWbemObj, pInParams, NULL, pszMethod, L"GetMethodEncodingString", IDS_GET_EMBED_METHOD, NULL);
  1822. //
  1823. // considered as a success
  1824. //
  1825. return WBEM_S_FALSE;
  1826. }
  1827. }
  1828. else
  1829. {
  1830. //
  1831. // fails to get the class definition
  1832. //
  1833. hrLog = m_pLogRecord->LogResult(hr, srpWbemObj, pInParams, NULL, pszMethod, L"GetClassObject", IDS_GET_SCE_CLASS_OBJECT, NULL);
  1834. return hr;
  1835. }
  1836. //
  1837. // Phase 1. Method call context preparation finishes.
  1838. //
  1839. //
  1840. // Phase 2. foreign class/object preparation
  1841. //
  1842. CComPtr<IWbemClassObject> srpForeignObj;
  1843. //
  1844. // now m_vecMethodContext is fully populated, we need the foreign instance.
  1845. //
  1846. hr = m_srpClass->SpawnInstance(0, &srpForeignObj);
  1847. if (FAILED(hr))
  1848. {
  1849. hrLog = m_pLogRecord->LogResult(hr, srpWbemObj, pInParams, NULL, pszMethod, L"SpawnInstance", IDS_SPAWN_INSTANCE, NULL);
  1850. return hr;
  1851. }
  1852. //
  1853. // Our m_srpSceObject has all the property values,
  1854. // populate the foreign object using our ISceClassObject
  1855. //
  1856. hr = PopulateForeignObject(srpForeignObj, m_srpSceObject, m_pLogRecord);
  1857. if (FAILED(hr))
  1858. {
  1859. hrLog = m_pLogRecord->LogResult(hr, srpWbemObj, pInParams, NULL, pszMethod, L"PopulateForeignObject", IDS_POPULATE_FO, NULL);
  1860. return hr;
  1861. }
  1862. //
  1863. // see if this foreign object has a path or not. It shouldn't fail.
  1864. //
  1865. hr = srpForeignObj->Get(L"__Relpath", 0, &varForeignObjPath, NULL, NULL);
  1866. if (FAILED(hr))
  1867. {
  1868. hrLog = m_pLogRecord->LogResult(hr, srpForeignObj, pInParams, NULL, pszMethod, L"GetPath", IDS_GET_FULLPATH, NULL);
  1869. return hr;
  1870. }
  1871. else if (SUCCEEDED(hr) && varForeignObjPath.vt == VT_NULL || varForeignObjPath.vt == VT_EMPTY)
  1872. {
  1873. //
  1874. // we will assume that the caller wants to make static calls.
  1875. // we will allow to continue if the methods are all static ones.
  1876. // m_bStaticCall is properly set during ParseMethodEncodingString.
  1877. //
  1878. //
  1879. // if not static call, this can't be done.
  1880. //
  1881. if (!m_bStaticCall)
  1882. {
  1883. hr = WBEM_E_INVALID_OBJECT;
  1884. hrLog = m_pLogRecord->LogResult(hr, srpForeignObj, pInParams, NULL, pszMethod, L"GetPath", IDS_NON_STATIC_CALL, NULL);
  1885. return hr;
  1886. }
  1887. else
  1888. {
  1889. //
  1890. // we only needs the class name as the path for static calls.
  1891. //
  1892. varForeignObjPath = m_pClsInfo->bstrClassName;
  1893. }
  1894. }
  1895. //
  1896. // give WMI the foreign object
  1897. //
  1898. //
  1899. // does the foreign object exist?
  1900. //
  1901. CComPtr<IWbemClassObject> srpObject;
  1902. hr = m_srpForeignNamespace->GetObject(varForeignObjPath.bstrVal, 0, NULL, &srpObject, NULL);
  1903. if (FAILED(hr))
  1904. {
  1905. //
  1906. // the object doesn't exist, we need to put first.
  1907. //
  1908. if (!m_bStaticCall)
  1909. {
  1910. hr = m_srpForeignNamespace->PutInstance(srpForeignObj, 0, pCtx, NULL);
  1911. //
  1912. // from this point on, srpObject is the foreign object
  1913. //
  1914. srpObject = srpForeignObj;
  1915. }
  1916. //
  1917. // failed to put instance but the methods is really just delete, we will consider it not an error
  1918. //
  1919. if (FAILED(hr) && (dwContext & SCE_METHOD_ENCODE_DEL_ONLY))
  1920. {
  1921. hr = WBEM_NO_ERROR;
  1922. hrLog = m_pLogRecord->LogResult(hr, srpObject, pInParams, NULL, pszMethod, pszDelInstance, IDS_DELETE_INSTANCE, NULL);
  1923. return hr;
  1924. }
  1925. else if (FAILED(hr) || (dwContext & SCE_METHOD_ENCODE_PUT_ONLY))
  1926. {
  1927. //
  1928. // fails to put or the methods are put only, then we are done.
  1929. //
  1930. hrLog = m_pLogRecord->LogResult(hr, srpObject, pInParams, NULL, pszMethod, pszPutInstance, IDS_PUT_INSTANCE, NULL);
  1931. return hr;
  1932. }
  1933. }
  1934. else
  1935. {
  1936. //
  1937. // Foreign object already exists, then we need to update the foreign object's properties
  1938. //
  1939. hr = PopulateForeignObject(srpObject, m_srpSceObject, m_pLogRecord);
  1940. if (FAILED(hr))
  1941. {
  1942. hrLog = m_pLogRecord->LogResult(hr, srpObject, pInParams, NULL, pszMethod, pszPopInstance, IDS_POPULATE_FO, NULL);
  1943. return hr;
  1944. }
  1945. //
  1946. // unless we are making a static call, we must re-put to reflect our property updates
  1947. //
  1948. if (!m_bStaticCall)
  1949. {
  1950. hr = m_srpForeignNamespace->PutInstance(srpObject, 0, pCtx, NULL);
  1951. }
  1952. //
  1953. // failed to put instance or it's put only, we are done.
  1954. //
  1955. if (FAILED(hr) || (dwContext & SCE_METHOD_ENCODE_PUT_ONLY))
  1956. {
  1957. hrLog = m_pLogRecord->LogResult(hr, srpObject, pInParams, NULL, pszMethod, pszPutInstance, IDS_PUT_INSTANCE, NULL);
  1958. return hr;
  1959. }
  1960. }
  1961. //
  1962. // Phase 2. foreign class/object preparation finishes
  1963. //
  1964. //
  1965. // Phase 3. parameter preparation and individual method execution.
  1966. //
  1967. //
  1968. // loop through each method and call it against the foreign object
  1969. //
  1970. for (MCIterator it = m_vecMethodContext.begin(); it != m_vecMethodContext.end(); ++it)
  1971. {
  1972. //
  1973. // fill in the parameters
  1974. //
  1975. if (*it == NULL)
  1976. {
  1977. hr = WBEM_E_FAILED;
  1978. hrLog = m_pLogRecord->LogResult(hr, srpForeignObj, pInParams, NULL, pszMethod, NULL, IDS_INVALID_METHOD_CONTEXT, NULL);
  1979. break;
  1980. }
  1981. CMethodContext* pMContext = *it;
  1982. //
  1983. // special cases
  1984. //
  1985. if (!m_bStaticCall && _wcsicmp(pMContext->m_pszMethodName, pszEquivalentPutInstance) == 0)
  1986. {
  1987. //
  1988. // the current method is a Put. But we have already done a put
  1989. //
  1990. hr = WBEM_NO_ERROR;
  1991. hrLog = m_pLogRecord->LogResult(hr, srpForeignObj, pInParams, NULL, pszMethod, pszPutInstance, IDS_PUT_INSTANCE, NULL);
  1992. }
  1993. else if (!m_bStaticCall && _wcsicmp(pMContext->m_pszMethodName, pszEquivalentDelInstance) == 0)
  1994. {
  1995. //
  1996. // the current method is a Delete.
  1997. //
  1998. hr = m_srpForeignNamespace->DeleteInstance(varForeignObjPath.bstrVal, 0, pCtx, NULL);
  1999. hrLog = m_pLogRecord->LogResult(hr, srpForeignObj, pInParams, NULL, pszMethod, pszDelInstance, IDS_DELETE_INSTANCE, NULL);
  2000. }
  2001. else
  2002. {
  2003. //
  2004. // will truly call the method on the foreign object
  2005. //
  2006. CComPtr<IWbemClassObject> srpInClass;
  2007. CComPtr<IWbemClassObject> srpInInst;
  2008. //
  2009. // create in paramter. We know for sure that this method is supported during parsing method context
  2010. //
  2011. hr = m_srpClass->GetMethod(pMContext->m_pszMethodName, 0, &srpInClass, NULL);
  2012. if (FAILED(hr))
  2013. {
  2014. hrLog = m_pLogRecord->LogResult(hr, srpForeignObj, pInParams, NULL, pszMethod, L"GetParameter", IDS_E_OUT_OF_MEMROY, NULL);
  2015. break;
  2016. }
  2017. //
  2018. // make sure that we take the lesser of the pramater names and values.
  2019. //
  2020. int iParamCount = pMContext->m_vecParamValues.size();
  2021. if (iParamCount > pMContext->m_vecParamNames.size())
  2022. {
  2023. iParamCount = pMContext->m_vecParamNames.size();
  2024. }
  2025. if (srpInClass == NULL && iParamCount > 0)
  2026. {
  2027. //
  2028. // if can't get in parameter but we say we have parameter
  2029. //
  2030. hrLog = m_pLogRecord->LogResult(WBEM_E_INVALID_SYNTAX, srpForeignObj, pInParams, NULL, pszMethod, L"GetParameter", IDS_PUT_IN_PARAMETER, NULL);
  2031. iParamCount = 0; // no parameter to put
  2032. }
  2033. else if (srpInClass)
  2034. {
  2035. //
  2036. // prepare an input parameter that we can fill in values
  2037. //
  2038. hr = srpInClass->SpawnInstance(0, &srpInInst);
  2039. if (FAILED(hr))
  2040. {
  2041. hrLog = m_pLogRecord->LogResult(hr, srpObject, pInParams, NULL, pszMethod, L"SpawnParameterObject", IDS_SPAWN_INSTANCE, NULL);
  2042. break;
  2043. }
  2044. }
  2045. //
  2046. // fill in parameter values:
  2047. //
  2048. //
  2049. // if the parameter name is prefixed by pszInParameterPrefix (Sce_Param_), then we need
  2050. // to pull the value from the in parameter (whose name is the parameter name without the prefix)
  2051. //
  2052. //
  2053. // if the parameter name is prefixed by pszMemberParameterPrefix (Sce_Member_), then we need
  2054. // to pull the value from our member (whose name is the parameter name without the prefix).
  2055. //
  2056. //
  2057. // In both cases, the target parameter name is encoded as the string value of this parameter
  2058. //
  2059. for (int i = 0; i < iParamCount; ++i)
  2060. {
  2061. //
  2062. // if a memeber is the parameter
  2063. //
  2064. if (IsMemberParameter(pMContext->m_vecParamNames[i]))
  2065. {
  2066. //
  2067. // get the member value from our object.
  2068. // Taking away the prefix becomes the property name!
  2069. //
  2070. CComVariant varVal;
  2071. hr = m_srpSceObject->GetProperty(pMContext->m_vecParamNames[i]+ wcslen(pszMemberParameterPrefix), &varVal);
  2072. if (SUCCEEDED(hr))
  2073. {
  2074. //
  2075. // Fill in the parameter value
  2076. //
  2077. hr = srpInInst->Put(pMContext->m_vecParamValues[i]->bstrVal, 0, &varVal, 0);
  2078. }
  2079. }
  2080. else if (IsInComingParameter(pMContext->m_vecParamNames[i]))
  2081. {
  2082. //
  2083. // is an in-bound parameter
  2084. //
  2085. CComVariant varVal;
  2086. //
  2087. // the parameter value is inside the in parameter
  2088. //
  2089. if (pInParams)
  2090. {
  2091. //
  2092. // Take away the prefix is the in-coming parameter name
  2093. //
  2094. LPCWSTR pszParamName = pMContext->m_vecParamNames[i] + wcslen(pszInParameterPrefix);
  2095. //
  2096. // get the value from the in-paramter
  2097. //
  2098. hr = pInParams->Get(pszParamName, 0, &varVal, NULL, NULL);
  2099. if (SUCCEEDED(hr))
  2100. {
  2101. //
  2102. // Fill in the parameter value
  2103. //
  2104. hr = srpInInst->Put(pMContext->m_vecParamValues[i]->bstrVal, 0, &varVal, 0);
  2105. }
  2106. }
  2107. }
  2108. else
  2109. {
  2110. //
  2111. // hard coded parameter value inside the encoding string
  2112. //
  2113. hr = srpInInst->Put(pMContext->m_vecParamNames[i], 0, pMContext->m_vecParamValues[i], 0);
  2114. }
  2115. if (FAILED(hr))
  2116. {
  2117. //
  2118. // will ignore log result's return value.
  2119. // execution stops
  2120. //
  2121. hrLog = m_pLogRecord->LogResult(hr, srpObject, pInParams, NULL, pszMethod, L"PutParameter", IDS_PUT_IN_PARAMETER, pMContext->m_vecParamNames[i]);
  2122. break;
  2123. }
  2124. }
  2125. //
  2126. // Wow, it's a lot of work to prepare the method execution.
  2127. // But we are finally ready.
  2128. //
  2129. if (SUCCEEDED(hr))
  2130. {
  2131. //
  2132. // issue the method execution command!
  2133. //
  2134. hr = m_srpForeignNamespace->ExecMethod(varForeignObjPath.bstrVal, pMContext->m_pszMethodName, 0, NULL, srpInInst, ppOut, NULL);
  2135. //
  2136. // if method failed, then we don't continue with the rest of methods any further
  2137. //
  2138. if (FAILED(hr))
  2139. {
  2140. //
  2141. // will ignore log result's return value
  2142. //
  2143. hrLog = m_pLogRecord->LogResult(hr, srpObject, pInParams, *ppOut, pszMethod, pMContext->m_pszMethodName, IDS_E_METHOD_FAIL, NULL);
  2144. break;
  2145. }
  2146. else
  2147. {
  2148. //
  2149. // will ignore log result's return value (whether that really happens is up to the log options.
  2150. //
  2151. hrLog = m_pLogRecord->LogResult(hr, srpObject, pInParams, *ppOut, pszMethod, pMContext->m_pszMethodName, IDS_SUCCESS, NULL);
  2152. }
  2153. }
  2154. else
  2155. {
  2156. //
  2157. // any failure causes us to stop executing the rest of the methods in the encoding string
  2158. //
  2159. break;
  2160. }
  2161. }
  2162. }
  2163. return hr;
  2164. }
  2165. /*
  2166. Routine Description:
  2167. Name:
  2168. CExtClassMethodCaller::PopulateForeignObject
  2169. Functionality:
  2170. Use our embedding object's properties to populate foreign object.
  2171. Virtual:
  2172. No.
  2173. Arguments:
  2174. pForeignObj - The foreign object.
  2175. pSceObject - Our embedding object that holds properties and other information
  2176. pLogRecord - Error logger.
  2177. Return Value:
  2178. Success:
  2179. various success codes.
  2180. Failure:
  2181. various error codes.
  2182. Notes:
  2183. If you need to add more functionality, consider logging your results, regardless success or
  2184. failure. It's up to the logging options to determine if a success or failure will be logged.
  2185. */
  2186. HRESULT
  2187. CExtClassMethodCaller::PopulateForeignObject (
  2188. IN IWbemClassObject * pForeignObj,
  2189. IN ISceClassObject * pSceObject,
  2190. IN CMethodResultRecorder * pLogRecord OPTIONAL
  2191. )const
  2192. {
  2193. if (m_bStaticCall)
  2194. {
  2195. return WBEM_S_FALSE;
  2196. }
  2197. DWORD dwCount = 0;
  2198. //
  2199. // populate the key property values
  2200. //
  2201. HRESULT hr = pSceObject->GetPropertyCount(SceProperty_Key, &dwCount);
  2202. if (SUCCEEDED(hr) && dwCount > 0)
  2203. {
  2204. for (DWORD dwIndex = 0; dwIndex < dwCount; ++dwIndex)
  2205. {
  2206. CComBSTR bstrName;
  2207. CComVariant varValue;
  2208. hr = pSceObject->GetPropertyValue(SceProperty_Key, dwIndex, &bstrName, &varValue);
  2209. //
  2210. // we will log and quit if missing key property
  2211. //
  2212. if (FAILED(hr))
  2213. {
  2214. if (pLogRecord)
  2215. {
  2216. pLogRecord->LogResult(hr, pForeignObj, NULL, 0, L"PopulateForeignObject", L"GetKeyProperty", IDS_GET_KEY_PROPERTY, NULL);
  2217. }
  2218. return hr;
  2219. }
  2220. else if (varValue.vt != VT_NULL &&
  2221. varValue.vt != VT_EMPTY &&
  2222. !IsMemberParameter(bstrName))
  2223. {
  2224. //
  2225. // we will ignore the result. The reason is that our embedding
  2226. // class may have more key properties than the foreign object.
  2227. //
  2228. HRESULT hrIgnore = pForeignObj->Put(bstrName, 0, &varValue, 0);
  2229. }
  2230. }
  2231. }
  2232. //
  2233. // populate the nonkey property values
  2234. //
  2235. hr = pSceObject->GetPropertyCount(SceProperty_NonKey, &dwCount);
  2236. if (SUCCEEDED(hr) && dwCount > 0)
  2237. {
  2238. for (DWORD dwIndex = 0; dwIndex < dwCount; ++dwIndex)
  2239. {
  2240. CComBSTR bstrName;
  2241. CComVariant varValue;
  2242. HRESULT hrIgnore = pSceObject->GetPropertyValue(SceProperty_NonKey, dwIndex, &bstrName, &varValue);
  2243. //
  2244. // missing property information is acceptable, but we will log
  2245. //
  2246. if (FAILED(hrIgnore) && pLogRecord)
  2247. {
  2248. pLogRecord->LogResult(hrIgnore, pForeignObj, NULL, 0, L"PopulateForeignObject", L"GetNonKeyProperty", IDS_GET_NON_KEY_PROPERTY, NULL);
  2249. }
  2250. if (SUCCEEDED(hrIgnore) && varValue.vt != VT_NULL && varValue.vt != VT_EMPTY && !IsMemberParameter(bstrName))
  2251. {
  2252. //
  2253. // missing non-key property is acceptable
  2254. //
  2255. hrIgnore = pForeignObj->Put(bstrName, 0, &varValue, 0);
  2256. }
  2257. }
  2258. }
  2259. return hr;
  2260. }
  2261. /*
  2262. Routine Description:
  2263. Name:
  2264. CExtClassMethodCaller::IsInComingParameter
  2265. Functionality:
  2266. Test if the name is an in-coming parameter.
  2267. Virtual:
  2268. No.
  2269. Arguments:
  2270. szName - The name of to test.
  2271. Return Value:
  2272. true if and only if the name is considered a in-parameter.
  2273. Notes:
  2274. To specify that we should use an in parameter of the embedding object's method as
  2275. a parameter for the foreign class/object's parameter, we use a prefix "Sce_Param_"
  2276. to tell them apart. This is the test to see if the name contains this prefix or not.
  2277. For example, Sce_Param_Test<VT_BSTR : "Try"> means:
  2278. (1) use the embedding object's parameter called "Test" as the foreign object's paramter called "Try".
  2279. */
  2280. bool
  2281. CExtClassMethodCaller::IsInComingParameter (
  2282. IN LPCWSTR szName
  2283. )const
  2284. {
  2285. LPCWSTR pszPrefix = wcsstr(szName, pszInParameterPrefix);
  2286. return (pszPrefix - szName == 0);
  2287. }
  2288. /*
  2289. Routine Description:
  2290. Name:
  2291. CExtClassMethodCaller::IsMemberParameter
  2292. Functionality:
  2293. Test if the name is an member parameter. See notes for more explanation.
  2294. Virtual:
  2295. No.
  2296. Arguments:
  2297. szName - The name of to test.
  2298. Return Value:
  2299. true if and only the name is considered a member parameter.
  2300. Notes:
  2301. To specify that we should use a member property of the embedding object's as
  2302. a parameter for the foreign class/object's parameter, we use a prefix "Sce_Member_"
  2303. to tell them apart. This is the test to see if the name contains this prefix or not.
  2304. For example, Sce_Member_Test<VT_BSTR : "Try"> means:
  2305. (1) use the embedding object member property called "Test" as the foreign object's paramter called "Try".
  2306. */
  2307. bool CExtClassMethodCaller::IsMemberParameter (
  2308. IN LPCWSTR szName
  2309. )const
  2310. {
  2311. LPCWSTR pszPrefix = wcsstr(szName, pszMemberParameterPrefix);
  2312. return (pszPrefix - szName == 0);
  2313. }
  2314. /*
  2315. Routine Description:
  2316. Name:
  2317. CExtClassMethodCaller::IsStaticMethod
  2318. Functionality:
  2319. Test if the method is a static method on the foreign class.
  2320. Virtual:
  2321. No.
  2322. Arguments:
  2323. szName - The name of to test.
  2324. Return Value:
  2325. true if and only if the named method is verfied as a static method with the foreign class.
  2326. Notes:
  2327. In other words, if we can't determine for whatever reasons, we return false.
  2328. */
  2329. bool
  2330. CExtClassMethodCaller::IsStaticMethod (
  2331. IN LPCWSTR szMethodName
  2332. )const
  2333. {
  2334. //
  2335. // default answer is false
  2336. //
  2337. bool bIsStatic = false;
  2338. if (m_srpClass && szMethodName != NULL && *szMethodName != L'\0')
  2339. {
  2340. //
  2341. // IWbemQualifierSet can tell us whether the STATIC qualifier
  2342. // is specified in the schema
  2343. //
  2344. CComPtr<IWbemQualifierSet> srpQS;
  2345. HRESULT hr = m_srpClass->GetMethodQualifierSet(szMethodName, &srpQS);
  2346. if (SUCCEEDED(hr))
  2347. {
  2348. CComVariant var;
  2349. hr = srpQS->Get(L"STATIC", 0, &var, NULL);
  2350. if (SUCCEEDED(hr) && var.vt == VT_BOOL && var.boolVal == VARIANT_TRUE)
  2351. {
  2352. bIsStatic = true;
  2353. }
  2354. }
  2355. }
  2356. return bIsStatic;
  2357. }
  2358. /*
  2359. Routine Description:
  2360. Name:
  2361. CExtClassMethodCaller::FormatSyntaxError
  2362. Functionality:
  2363. A logging helper to format a string for syntax error.
  2364. Virtual:
  2365. No.
  2366. Arguments:
  2367. wchMissChar - The char that is missing.
  2368. dwMissCharIndex - the index where the missing char is expected.
  2369. pszString - Where the error happens.
  2370. pbstrError - Receives the output.
  2371. Return Value:
  2372. None.
  2373. Notes:
  2374. */
  2375. void
  2376. CExtClassMethodCaller::FormatSyntaxError (
  2377. IN WCHAR wchMissChar,
  2378. IN DWORD dwMissCharIndex,
  2379. IN LPCWSTR pszString,
  2380. OUT BSTR* pbstrError OPTIONAL
  2381. )
  2382. {
  2383. if (pbstrError)
  2384. {
  2385. *pbstrError = NULL;
  2386. CComBSTR bstrErrorFmtStr;
  2387. if (bstrErrorFmtStr.LoadString(IDS_MISSING_TOKEN))
  2388. {
  2389. const int MAX_INDEX_LENGTH = 32;
  2390. //
  2391. // 3 is for the SingleQuote + wchMissChar + SingleQuote
  2392. //
  2393. WCHAR wszMissing[] = {L'\'', wchMissChar, L'\''};
  2394. int iLen = wcslen(bstrErrorFmtStr) + wcslen(pszString) + 3 + MAX_INDEX_LENGTH + 1;
  2395. *pbstrError = ::SysAllocStringLen(NULL, iLen);
  2396. if (*pbstrError != NULL)
  2397. {
  2398. ::wsprintf(*pbstrError, (LPCWSTR)bstrErrorFmtStr, wszMissing, dwMissCharIndex, pszString);
  2399. }
  2400. }
  2401. }
  2402. }
  2403. /*
  2404. Routine Description:
  2405. Name:
  2406. CExtClassMethodCaller::ParseMethodEncodingString
  2407. Functionality:
  2408. Parsing the encoding string and populate its calling context.
  2409. Virtual:
  2410. No.
  2411. Arguments:
  2412. pszEncodeString - The encoding string.
  2413. pdwContext - Receives overall. Other than 0, it's either
  2414. SCE_METHOD_ENCODE_DEL_ONLY -- meaning the whole string just encodes a delete call
  2415. or
  2416. SCE_METHOD_ENCODE_PUT_ONLY -- meaning the whole string just encodes a put call
  2417. pbstrError - string about the error found. Caller is responsible for releasing it.
  2418. Return Value:
  2419. Success:
  2420. Various success codes.
  2421. Failure:
  2422. Various error codes. If error happens and if it's encoding error,
  2423. we will have error information string passed back to the caller.
  2424. Notes:
  2425. --------------------------------------------------------------------
  2426. methods are encoded in the following format:
  2427. method_1(parameter1, parameter2,,,);method_2();method_3(...)
  2428. where method_1, method_2 are names for the foreign object's methods
  2429. and parameter1 and parameter2 (etc.) are of the form
  2430. name<vt:value>
  2431. where name is the name of the parameter, and vt will be the
  2432. variant's vt for "value". If vt == VT_VARIANT, then
  2433. the "value" is the name for a memeber variable of the class
  2434. --------------------------------------------------------------------
  2435. ************************Warning***********************************
  2436. this method has a lost of consideration of heap allocation for
  2437. efficiency reasons. Unless the length needed for the token is longer
  2438. than MAX_PATH (which will be the case for 99% cases), we are just going
  2439. to use the stack varialbes. If you modify the routine, please don't
  2440. return at the middle unless you are sure that you have freed the memory
  2441. --------------------------------------------------------------------
  2442. */
  2443. HRESULT
  2444. CExtClassMethodCaller::ParseMethodEncodingString (
  2445. IN LPCWSTR pszEncodeString,
  2446. OUT DWORD * pdwContext,
  2447. OUT BSTR * pbstrError
  2448. )
  2449. {
  2450. if (pbstrError == NULL || pdwContext == NULL)
  2451. {
  2452. return WBEM_E_INVALID_PARAMETER;
  2453. }
  2454. //
  2455. // current parsing point
  2456. //
  2457. LPCWSTR pCur = pszEncodeString;
  2458. HRESULT hr = WBEM_NO_ERROR;
  2459. //
  2460. // determines if all is about delete
  2461. //
  2462. bool bIsDel = false;
  2463. //
  2464. // determines if all is about put
  2465. //
  2466. bool bIsPut = false;
  2467. DWORD dwCount = 0;
  2468. //
  2469. // in most cases, the method name will be held here, unless the name is too long
  2470. //
  2471. WCHAR szMethodName[MAX_PATH];
  2472. //
  2473. // in most cases, the value will be held here, unless the value is too long
  2474. //
  2475. WCHAR szParameterValue[MAX_PATH];
  2476. LPWSTR pszName = NULL;
  2477. LPWSTR pszValue = NULL;
  2478. //
  2479. // to avoid costly allocation/free, we will rely on most cases (if the length is
  2480. // not more than MAX_PATH) the stack variables to store the parsed method name.
  2481. //
  2482. LPWSTR pszHeapName = NULL;
  2483. LPWSTR pszHeapValue = NULL;
  2484. //
  2485. // current name string's length
  2486. //
  2487. int iCurNameLen = 0;
  2488. //
  2489. // current value's string length
  2490. //
  2491. int iCurValueLen = 0;
  2492. if (pbstrError)
  2493. {
  2494. *pbstrError = NULL;
  2495. }
  2496. //
  2497. // not used, but needed for the parsing routines
  2498. //
  2499. bool bEscaped;
  2500. while (true)
  2501. {
  2502. LPCWSTR pNext = pCur;
  2503. //
  2504. // get the method name, upto '('
  2505. //
  2506. while (*pNext != L'\0' && *pNext != wchMethodLeft)
  2507. {
  2508. ++pNext;
  2509. }
  2510. //
  2511. // must have '('
  2512. //
  2513. if (*pNext != wchMethodLeft)
  2514. {
  2515. FormatSyntaxError(wchMethodLeft, (pNext - pszEncodeString), pszEncodeString, pbstrError);
  2516. hr = WBEM_E_INVALID_SYNTAX;
  2517. break;
  2518. }
  2519. //
  2520. // from pCur to pNext is the name
  2521. //
  2522. int iTokenLen = pNext - pCur;
  2523. if (iTokenLen >= MAX_PATH)
  2524. {
  2525. //
  2526. // stack variable is not long enough, see if heap is long enough
  2527. //
  2528. if (iCurNameLen < iTokenLen + 1)
  2529. {
  2530. //
  2531. // release previously allocated memory and make it enough length for the current token.
  2532. //
  2533. delete [] pszHeapName;
  2534. iCurNameLen = iTokenLen + 1;
  2535. pszHeapName = new WCHAR[iCurNameLen];
  2536. if (pszHeapName == NULL)
  2537. {
  2538. hr = WBEM_E_OUT_OF_MEMORY;
  2539. break;
  2540. }
  2541. }
  2542. //
  2543. // this is where our name should be copied
  2544. //
  2545. pszName = pszHeapName;
  2546. }
  2547. else
  2548. {
  2549. //
  2550. // this is where our name should should be copied.
  2551. //
  2552. pszName = szMethodName;
  2553. }
  2554. //
  2555. // copy the name, no white space, please
  2556. //
  2557. ::TrimCopy(pszName, pCur, iTokenLen);
  2558. //
  2559. // don't worry, we are also keep tracking of the number of
  2560. // methods encoded. If that is 1, then we are going to
  2561. // use these two variables.
  2562. //
  2563. bIsPut = (_wcsicmp(pszName, pszEquivalentPutInstance) == 0);
  2564. bIsDel = (_wcsicmp(pszName, pszEquivalentDelInstance) == 0);
  2565. if (!bIsPut && !bIsDel)
  2566. {
  2567. //
  2568. // not put, nor delete
  2569. // validate that this method is supported
  2570. //
  2571. CComPtr<IWbemClassObject> srpInClass;
  2572. hr = m_srpClass->GetMethod(pszName, 0, &srpInClass, NULL);
  2573. if (FAILED(hr))
  2574. {
  2575. //
  2576. // method not supported/out of memory
  2577. //
  2578. if (hr == WBEM_E_NOT_FOUND)
  2579. {
  2580. CComBSTR bstrMsg;
  2581. bstrMsg.LoadString(IDS_METHOD_NOT_SUPPORTED);
  2582. bstrMsg += CComBSTR(pszName);
  2583. *pbstrError = bstrMsg.Detach();
  2584. }
  2585. break;
  2586. }
  2587. }
  2588. //
  2589. // now grab the parameter
  2590. //
  2591. pCur = ++pNext; // skip over the '('
  2592. DWORD dwMatchCount = 0;
  2593. bool bIsInQuote = false;
  2594. //
  2595. // seek to the enclosing ')' char (wchMethodRight)
  2596. // as long as it is inside an open '(', or inside quote, or not ')'
  2597. //
  2598. while (*pNext != L'\0' && (dwMatchCount > 0 || bIsInQuote || *pNext != wchMethodRight ))
  2599. {
  2600. if (!bIsInQuote)
  2601. {
  2602. //
  2603. // not inside quote
  2604. //
  2605. if (*pNext == wchMethodLeft)
  2606. {
  2607. dwMatchCount += 1;
  2608. }
  2609. else if (*pNext == wchMethodRight)
  2610. {
  2611. dwMatchCount -= 1;
  2612. }
  2613. }
  2614. if (*pNext == L'"')
  2615. {
  2616. bIsInQuote = !bIsInQuote;
  2617. }
  2618. ++pNext;
  2619. }
  2620. //
  2621. // must have ')'
  2622. //
  2623. if (*pNext != wchMethodRight)
  2624. {
  2625. FormatSyntaxError(wchMethodRight, (pNext - pszEncodeString), pszEncodeString, pbstrError);
  2626. hr = WBEM_E_INVALID_SYNTAX;
  2627. break;
  2628. }
  2629. //
  2630. // from pCur to pNext is the parameter list
  2631. //
  2632. iTokenLen = pNext - pCur;
  2633. if (iTokenLen >= MAX_PATH)
  2634. {
  2635. //
  2636. // stack variable is not long enough for the parameter value, see if heap is long enough
  2637. //
  2638. if (iCurValueLen < iTokenLen + 1)
  2639. {
  2640. //
  2641. // release previously allocated memory, and allocate enough for the new length
  2642. //
  2643. delete [] pszHeapValue;
  2644. iCurValueLen = iTokenLen + 1;
  2645. pszHeapValue = new WCHAR[iCurValueLen];
  2646. if (pszHeapValue == NULL)
  2647. {
  2648. hr = WBEM_E_OUT_OF_MEMORY;
  2649. break;
  2650. }
  2651. }
  2652. //
  2653. // this is where the value will be copied to
  2654. //
  2655. pszValue = pszHeapValue;
  2656. }
  2657. else
  2658. {
  2659. //
  2660. // this is where the value will be copied to
  2661. //
  2662. pszValue = szParameterValue;
  2663. }
  2664. //
  2665. // copy the value, no white space
  2666. //
  2667. ::TrimCopy(pszValue, pCur, iTokenLen);
  2668. //
  2669. // We got the name and the value,
  2670. // build the method and the parameter list
  2671. //
  2672. ++dwCount;
  2673. hr = BuildMethodContext(pszName, pszValue, pbstrError);
  2674. if (FAILED(hr))
  2675. {
  2676. break;
  2677. }
  2678. //
  2679. // as long as there is one method that is not static, it's not a static seqeunce.
  2680. //
  2681. if (!IsStaticMethod(pszName))
  2682. {
  2683. m_bStaticCall = false;
  2684. }
  2685. //
  2686. // skip the ')'
  2687. //
  2688. pCur = ++pNext;
  2689. //
  2690. // seek to ';'
  2691. //
  2692. while (*pNext != L'\0' && *pNext != wchMethodSep)
  2693. {
  2694. ++pNext;
  2695. }
  2696. if (*pNext != wchMethodSep)
  2697. {
  2698. //
  2699. // not seen ';'
  2700. //
  2701. break;
  2702. }
  2703. //
  2704. // skip the ';'
  2705. //
  2706. pCur = pNext + 1;
  2707. }
  2708. *pdwContext = 0;
  2709. if (SUCCEEDED(hr))
  2710. {
  2711. if (dwCount == 1 && bIsDel)
  2712. {
  2713. *pdwContext = SCE_METHOD_ENCODE_DEL_ONLY;
  2714. }
  2715. else if (dwCount == 1 && bIsPut)
  2716. {
  2717. *pdwContext = SCE_METHOD_ENCODE_PUT_ONLY;
  2718. }
  2719. }
  2720. delete [] pszHeapName;
  2721. delete [] pszHeapValue;
  2722. return hr;
  2723. }
  2724. /*
  2725. Routine Description:
  2726. Name:
  2727. CExtClassMethodCaller::BuildMethodContext
  2728. Functionality:
  2729. Given a method name and its parameter encoding string, build this method call's context.
  2730. Virtual:
  2731. No.
  2732. Arguments:
  2733. szMethodName - name of the method on foreign object.
  2734. szParameter - encoding string for the paramter. See Notes for sample.
  2735. pbstrError - string about the errors found. Caller is responsible for releasing it.
  2736. Return Value:
  2737. Success:
  2738. Various success codes.
  2739. Failure:
  2740. Various error codes. If error happens and if it's encoding error,
  2741. we will have error information string passed back to the caller.
  2742. Notes:
  2743. (1) this function is to parse the parameter list, which comes in the
  2744. following format (exclude parentheses)
  2745. (parameter1, parameter2,,,)
  2746. where parameter1 is in the following format
  2747. name<vt:value>
  2748. (2) ************************Warning***********************************
  2749. this method has a lost of consideration of heap allocation for
  2750. efficiency reasons. Unless the length needed for the token is longer
  2751. than MAX_PATH (which will be the case for 99% cases), we are just going
  2752. to use the stack varialbes. If you modify the routine, please don't
  2753. return at the middle unless you are sure that you have freed the memory
  2754. (3) Don't blindly return. We opt to use goto so that we can deal with memory
  2755. deallocation.
  2756. */
  2757. HRESULT
  2758. CExtClassMethodCaller::BuildMethodContext (
  2759. IN LPCWSTR szMethodName,
  2760. IN LPCWSTR szParameter,
  2761. OUT BSTR * pbstrError
  2762. )
  2763. {
  2764. //
  2765. // current parsing point
  2766. //
  2767. LPCWSTR pCur = szParameter;
  2768. HRESULT hr = WBEM_NO_ERROR;
  2769. LPWSTR pszParamName = NULL;
  2770. LPWSTR pszValue = NULL;
  2771. //
  2772. // normally, the value goes to szParameterValue unless it's too long.
  2773. //
  2774. WCHAR szParameterValue[MAX_PATH];
  2775. LPWSTR pszHeapValue = NULL;
  2776. int iCurValueLen = 0;
  2777. VARIANT* pVar = NULL;
  2778. int iTokenLen = 0;
  2779. //
  2780. // the moving point of parsing
  2781. //
  2782. LPCWSTR pNext = pCur;
  2783. //
  2784. // only needed for parsing routines
  2785. //
  2786. bool bEscaped = false;
  2787. //
  2788. // we will build one context
  2789. //
  2790. CMethodContext *pNewContext = new CMethodContext;
  2791. if (pNewContext == NULL)
  2792. {
  2793. hr = WBEM_E_OUT_OF_MEMORY;
  2794. goto Error;
  2795. }
  2796. //
  2797. // need to copy the method
  2798. //
  2799. pNewContext->m_pszMethodName = new WCHAR[wcslen(szMethodName) + 1];
  2800. if (pNewContext->m_pszMethodName == NULL)
  2801. {
  2802. hr = WBEM_E_OUT_OF_MEMORY;
  2803. goto Error;
  2804. }
  2805. wcscpy(pNewContext->m_pszMethodName, szMethodName);
  2806. //
  2807. // now, scan through the parameter encoding string to find the parameter name and its value
  2808. //
  2809. while (*pCur != L'\0')
  2810. {
  2811. //
  2812. // get the parameter name, upto '<'.
  2813. // Last parameter == true means moving to end if not found
  2814. //
  2815. pNext = ::EscSeekToChar(pCur, wchTypeValLeft, &bEscaped, true);
  2816. if (*pNext != wchTypeValLeft)
  2817. {
  2818. //
  2819. // don't see one, then syntax error
  2820. //
  2821. FormatSyntaxError(wchTypeValLeft, (pNext - szParameter), szParameter, pbstrError);
  2822. hr = WBEM_E_INVALID_SYNTAX;
  2823. goto Error;
  2824. }
  2825. //
  2826. // from pCur to pNext is the parameter name
  2827. //
  2828. iTokenLen = pNext - pCur;
  2829. pszParamName = new WCHAR[iTokenLen + 1];
  2830. if (pszParamName == NULL)
  2831. {
  2832. hr = WBEM_E_OUT_OF_MEMORY;
  2833. goto Error;
  2834. }
  2835. //
  2836. // get the name, but no white space.
  2837. //
  2838. ::TrimCopy(pszParamName, pCur, iTokenLen);
  2839. //
  2840. // add the name to the name list, the context is responsible to manage the memory
  2841. //
  2842. pNewContext->m_vecParamNames.push_back(pszParamName);
  2843. //
  2844. // pCur is at '<'
  2845. //
  2846. pCur = pNext;
  2847. //
  2848. // move to '>'.
  2849. // Last parameter == true means moving to end if not found
  2850. //
  2851. pNext = ::EscSeekToChar(pCur, wchTypeValRight, &bEscaped, true);
  2852. if (*pNext != wchTypeValRight)
  2853. {
  2854. //
  2855. // must have '>'
  2856. //
  2857. FormatSyntaxError(wchTypeValRight, (pNext - szParameter), szParameter, pbstrError);
  2858. hr = WBEM_E_INVALID_SYNTAX;
  2859. goto Error;
  2860. }
  2861. //
  2862. // skip over '>'
  2863. //
  2864. ++pNext;
  2865. //
  2866. // from pCur to pNext is the <vt:value>, copy it into szParValue
  2867. //
  2868. iTokenLen = pNext - pCur;
  2869. if (iTokenLen >= MAX_PATH)
  2870. {
  2871. //
  2872. // stack variable is not long enough for the parameter value, see if heap is long enough
  2873. //
  2874. if (iCurValueLen < iTokenLen + 1)
  2875. {
  2876. //
  2877. // release previously allocated memory and give a longer buffer
  2878. //
  2879. delete [] pszHeapValue;
  2880. iCurValueLen = iTokenLen + 1;
  2881. pszHeapValue = new WCHAR[iCurValueLen];
  2882. if (pszHeapValue == NULL)
  2883. {
  2884. hr = WBEM_E_OUT_OF_MEMORY;
  2885. goto Error;
  2886. }
  2887. }
  2888. //
  2889. // this is where the value will be written
  2890. //
  2891. pszValue = pszHeapValue;
  2892. }
  2893. else
  2894. {
  2895. //
  2896. // this is where the value will be written
  2897. //
  2898. pszValue = szParameterValue;
  2899. }
  2900. //
  2901. // get the value string, no white space
  2902. //
  2903. ::TrimCopy(pszValue, pCur, iTokenLen);
  2904. //
  2905. // translate the string into a value
  2906. //
  2907. pVar = new VARIANT;
  2908. if (pVar == NULL)
  2909. {
  2910. hr = WBEM_E_OUT_OF_MEMORY;
  2911. goto Error;
  2912. }
  2913. hr = ::VariantFromFormattedString(pszValue, pVar);
  2914. if (FAILED(hr))
  2915. {
  2916. *pbstrError = ::SysAllocString(pszValue);
  2917. goto Error;
  2918. }
  2919. //
  2920. // add this parameter into the list. It owns the variant!
  2921. //
  2922. pNewContext->m_vecParamValues.push_back(pVar);
  2923. pVar = NULL;
  2924. //
  2925. // skip while spaces
  2926. //
  2927. while (*pNext != L'\0' && iswspace(*pNext))
  2928. {
  2929. ++pNext;
  2930. }
  2931. //
  2932. // if *pNext == ',', need to work further
  2933. //
  2934. if (*pNext == wchParamSep)
  2935. {
  2936. //
  2937. // skip ','
  2938. //
  2939. ++pNext;
  2940. }
  2941. else if (*pNext == L'\0')
  2942. {
  2943. break;
  2944. }
  2945. else
  2946. {
  2947. //
  2948. // syntax errors
  2949. //
  2950. FormatSyntaxError(wchParamSep, (pNext - szParameter), szParameter, pbstrError);
  2951. hr = WBEM_E_INVALID_SYNTAX;
  2952. goto Error;
  2953. }
  2954. //
  2955. // for next loop.
  2956. //
  2957. pCur = pNext;
  2958. }
  2959. //
  2960. // everything is fine, push the context to our vector. It owns the context from this point on.
  2961. //
  2962. m_vecMethodContext.push_back(pNewContext);
  2963. delete [] pszHeapValue;
  2964. return hr;
  2965. Error:
  2966. //
  2967. // CMethodContext knows how to delete itself cleanly
  2968. //
  2969. delete pNewContext;
  2970. if (pVar)
  2971. {
  2972. ::VariantClear(pVar);
  2973. }
  2974. delete pVar;
  2975. delete [] pszHeapValue;
  2976. return hr;
  2977. }
  2978. //=========================================================================
  2979. // CExtClassMethodCaller::CMethodContext impelementation
  2980. /*
  2981. Routine Description:
  2982. Name:
  2983. CExtClassMethodCaller::CMethodContext::CMethodContext
  2984. Functionality:
  2985. This is the constructor. trivial.
  2986. Virtual:
  2987. No
  2988. Arguments:
  2989. None.
  2990. Return Value:
  2991. None as any constructor
  2992. Notes:
  2993. if you create any local members, think about initialize them here
  2994. */
  2995. CExtClassMethodCaller::CMethodContext::CMethodContext()
  2996. :
  2997. m_pszMethodName(NULL)
  2998. {
  2999. }
  3000. /*
  3001. Routine Description:
  3002. Name:
  3003. CExtClassMethodCaller::CMethodContext::~CMethodContext
  3004. Functionality:
  3005. This is the Destructor. Just do clean up of all the resources managed by the context.
  3006. Virtual:
  3007. No
  3008. Arguments:
  3009. None.
  3010. Return Value:
  3011. None as any destructor
  3012. Notes:
  3013. if you create any local members, think about clean them up here.
  3014. */
  3015. CExtClassMethodCaller::CMethodContext::~CMethodContext ()
  3016. {
  3017. delete [] m_pszMethodName;
  3018. int iCount = m_vecParamValues.size();
  3019. //
  3020. // m_vecParamValues is a vector of heap allocated variant*
  3021. //
  3022. for (int i = 0; i < iCount; ++i)
  3023. {
  3024. //
  3025. // need to release the variant and then delete the variant
  3026. //
  3027. ::VariantClear(m_vecParamValues[i]);
  3028. delete m_vecParamValues[i];
  3029. }
  3030. m_vecParamValues.clear();
  3031. //
  3032. // m_vecParamNames is just a vector of strings
  3033. //
  3034. iCount = m_vecParamNames.size();
  3035. for (int i = 0; i < iCount; ++i)
  3036. {
  3037. delete [] m_vecParamNames[i];
  3038. }
  3039. m_vecParamNames.clear();
  3040. }
  3041. //========================================================================
  3042. // implementation CMethodResultRecorder
  3043. /*
  3044. Routine Description:
  3045. Name:
  3046. CMethodResultRecorder::CMethodResultRecorder
  3047. Functionality:
  3048. This is the Constructor. Trivial.
  3049. Virtual:
  3050. No
  3051. Arguments:
  3052. None.
  3053. Return Value:
  3054. None as any constructor
  3055. Notes:
  3056. if you create any local members, think about initializing them here.
  3057. */
  3058. CMethodResultRecorder::CMethodResultRecorder ()
  3059. {
  3060. }
  3061. /*
  3062. Routine Description:
  3063. Name:
  3064. CMethodResultRecorder::Initialize
  3065. Functionality:
  3066. Initializes itself.
  3067. Virtual:
  3068. No
  3069. Arguments:
  3070. pszLogFilePath - log file's path.
  3071. pszClassName - The class name.
  3072. pNativeNS - SCE namespace.
  3073. pCtx - what WMI API's need.
  3074. Return Value:
  3075. Success:
  3076. Various success codes.
  3077. Failure:
  3078. Various error codes.
  3079. Notes:
  3080. */
  3081. HRESULT
  3082. CMethodResultRecorder::Initialize (
  3083. IN LPCWSTR pszLogFilePath,
  3084. IN LPCWSTR pszClassName,
  3085. IN IWbemServices * pNativeNS,
  3086. IN IWbemContext * pCtx
  3087. )
  3088. {
  3089. if (pszClassName == NULL || pNativeNS == NULL)
  3090. {
  3091. return WBEM_E_INVALID_PARAMETER;
  3092. }
  3093. HRESULT hr = WBEM_NO_ERROR;
  3094. if (pszLogFilePath != NULL && *pszLogFilePath != L'\0')
  3095. {
  3096. m_bstrLogFilePath = pszLogFilePath;
  3097. }
  3098. else
  3099. {
  3100. //
  3101. // no log file? we will log to the default log file.
  3102. //
  3103. //
  3104. // protect the global variable
  3105. //
  3106. g_CS.Enter();
  3107. m_bstrLogFilePath = ::SysAllocString(g_bstrDefLogFilePath);
  3108. g_CS.Leave();
  3109. }
  3110. m_bstrClassName = pszClassName;
  3111. m_srpNativeNS = pNativeNS;
  3112. m_srpCtx = pCtx;
  3113. return hr;
  3114. }
  3115. /*
  3116. Routine Description:
  3117. Name:
  3118. CMethodResultRecorder::LogResult
  3119. Functionality:
  3120. Do all the dirty work to log!.
  3121. Virtual:
  3122. No
  3123. Arguments:
  3124. hrResult - the RESULT value.
  3125. pObj - The embedding object.
  3126. pParam - the in parameter.
  3127. pParam - the out parameter.
  3128. pszMethod - method name.
  3129. pszForeignAction - action on the foreign object.
  3130. uMsgResID - resource string id.
  3131. pszExtraInfo - Other information in string.
  3132. Return Value:
  3133. Success:
  3134. Various success codes.
  3135. Failure:
  3136. Various error codes.
  3137. Notes:
  3138. (1) we will generate such a string to log:
  3139. <ClassName>.<pszMethod>[pszForeignAction],
  3140. Failure Cause=xxx.
  3141. Object detail=xxx,
  3142. Parameter detail=xxx
  3143. whereas
  3144. Failure Cause=xxx only present with errors
  3145. Object detail=xxx only present if logging verbosely
  3146. Parameter detail=xxx only present if logging verbosely
  3147. */
  3148. HRESULT
  3149. CMethodResultRecorder::LogResult (
  3150. IN HRESULT hrResult,
  3151. IN IWbemClassObject * pObj,
  3152. IN IWbemClassObject * pParam,
  3153. IN IWbemClassObject * pOutParam,
  3154. IN LPCWSTR pszMethod,
  3155. IN LPCWSTR pszForeignAction,
  3156. IN UINT uMsgResID,
  3157. IN LPCWSTR pszExtraInfo
  3158. )const
  3159. {
  3160. //
  3161. // Logging only happens when we execute a method on Sce_Operation CSceOperation::ExecMethod
  3162. // We block reentrance to that function if there is a thread executing that function. This
  3163. // eliminates the need to protect this global variable
  3164. //
  3165. //
  3166. // get the logging option
  3167. //
  3168. SCE_LOG_OPTION status = g_LogOption.GetLogOption();
  3169. if (status == Sce_log_None)
  3170. {
  3171. return WBEM_NO_ERROR;
  3172. }
  3173. else if ( (status & Sce_log_Success) == 0 && SUCCEEDED(hrResult))
  3174. {
  3175. //
  3176. // not to log success code
  3177. //
  3178. return WBEM_NO_ERROR;
  3179. }
  3180. else if ( (status & Sce_log_Error) == 0 && FAILED(hrResult))
  3181. {
  3182. //
  3183. // not to log error code
  3184. //
  3185. return WBEM_NO_ERROR;
  3186. }
  3187. if (pszMethod == NULL)
  3188. {
  3189. return WBEM_E_INVALID_PARAMETER;
  3190. }
  3191. else if ( m_srpNativeNS == NULL ||
  3192. (LPCWSTR)m_bstrLogFilePath == NULL ||
  3193. (LPCWSTR)m_bstrClassName == NULL )
  3194. {
  3195. return WBEM_E_INVALID_OBJECT;
  3196. }
  3197. //
  3198. // create each property of the log record object
  3199. //
  3200. DWORD dwLength;
  3201. CComBSTR bstrAction, bstrErrorCause, bstrObjDetail, bstrParamDetail;
  3202. if (pszForeignAction)
  3203. {
  3204. //
  3205. // creating something like this:
  3206. //
  3207. // ClassName.Method[ForeignMethod]
  3208. //
  3209. dwLength = wcslen(m_bstrClassName) + 1 + wcslen(pszMethod) + 1 + wcslen(pszForeignAction) + 1 + 1;
  3210. bstrAction.m_str = ::SysAllocStringLen(NULL, dwLength);
  3211. if (bstrAction.m_str != NULL)
  3212. {
  3213. ::_snwprintf(bstrAction.m_str, dwLength, L"%s.%s[%s]", (LPCWSTR)m_bstrClassName, pszMethod, pszForeignAction);
  3214. }
  3215. else
  3216. {
  3217. return WBEM_E_OUT_OF_MEMORY;
  3218. }
  3219. }
  3220. else
  3221. {
  3222. //
  3223. // creating something like this:
  3224. //
  3225. // ClassName.Method
  3226. //
  3227. dwLength = wcslen(m_bstrClassName) + 1 + wcslen(pszMethod) + 1;
  3228. bstrAction.m_str = ::SysAllocStringLen(NULL, dwLength);
  3229. if (bstrAction.m_str != NULL)
  3230. {
  3231. ::_snwprintf(bstrAction.m_str, dwLength, L"%s.%s", (LPCWSTR)m_bstrClassName, pszMethod);
  3232. }
  3233. else
  3234. {
  3235. return WBEM_E_OUT_OF_MEMORY;
  3236. }
  3237. }
  3238. if (FAILED(hrResult))
  3239. {
  3240. //
  3241. // in case of error, the error cause will be like:
  3242. //
  3243. // ErrorMsg: [extra info]
  3244. //
  3245. // if no extra info, then the msg will be the only one we can use
  3246. //
  3247. bstrErrorCause.LoadString(uMsgResID);
  3248. if (pszExtraInfo != NULL)
  3249. {
  3250. CComBSTR bstrMsg;
  3251. bstrMsg.m_str = bstrErrorCause.Detach();
  3252. dwLength = wcslen(bstrMsg) + 1 + 1 + 1 + wcslen(pszExtraInfo) + 1 + 1;
  3253. bstrErrorCause.m_str = ::SysAllocStringLen(NULL, dwLength);
  3254. if (bstrErrorCause.m_str != NULL)
  3255. {
  3256. ::_snwprintf(bstrErrorCause.m_str, dwLength, L"%s: [%s]", (LPCWSTR)bstrMsg, pszExtraInfo);
  3257. }
  3258. else
  3259. {
  3260. return WBEM_E_OUT_OF_MEMORY;
  3261. }
  3262. }
  3263. }
  3264. //
  3265. // log verbosely if so set. Verbose pretty much means that we are going to log the objects.
  3266. //
  3267. if (Sce_log_Verbose & status)
  3268. {
  3269. //
  3270. // format object, will ignore the return result
  3271. //
  3272. FormatVerboseMsg(pObj, &bstrObjDetail);
  3273. //
  3274. // format in parameter
  3275. //
  3276. CComBSTR bstrIn;
  3277. FormatVerboseMsg(pParam, &bstrIn);
  3278. //
  3279. // format out parameter
  3280. //
  3281. CComBSTR bstrOut;
  3282. FormatVerboseMsg(pOutParam, &bstrOut);
  3283. CComBSTR bstrInLabel;
  3284. bstrInLabel.LoadString(IDS_IN_PARAMETER);
  3285. CComBSTR bstrOutLabel;
  3286. bstrOutLabel.LoadString(IDS_OUT_PARAMETER);
  3287. //
  3288. // now create the in and out parameter verbose message
  3289. //
  3290. if (NULL != (LPCWSTR)bstrIn && NULL != (LPCWSTR)bstrOut)
  3291. {
  3292. //
  3293. // <bstrInLabel>=<bstrIn>; <bstrOutLabel>=<bstrOut>
  3294. //
  3295. dwLength = wcslen(bstrInLabel) + 1 + wcslen(bstrIn) + 2 + wcslen(bstrOutLabel) + 1 + wcslen(bstrOut) + 1;
  3296. bstrParamDetail.m_str = ::SysAllocStringLen(NULL, dwLength);
  3297. if (bstrParamDetail.m_str != NULL)
  3298. {
  3299. ::_snwprintf(bstrParamDetail.m_str,
  3300. dwLength,
  3301. L"%s=%s; %s=%s",
  3302. (LPCWSTR)bstrInLabel,
  3303. (LPCWSTR)bstrIn,
  3304. (LPCWSTR)bstrOutLabel,
  3305. (LPCWSTR)bstrOut
  3306. );
  3307. }
  3308. else
  3309. {
  3310. return WBEM_E_OUT_OF_MEMORY;
  3311. }
  3312. }
  3313. else if (NULL != (LPCWSTR)bstrIn)
  3314. {
  3315. //
  3316. // <bstrInLabel>=<bstrIn>.
  3317. //
  3318. dwLength = wcslen(bstrInLabel) + 1 + wcslen(bstrIn) + 2;
  3319. bstrParamDetail.m_str = ::SysAllocStringLen(NULL, dwLength);
  3320. if (bstrParamDetail.m_str != NULL)
  3321. {
  3322. ::_snwprintf(bstrParamDetail.m_str,
  3323. dwLength,
  3324. L"%s=%s",
  3325. (LPCWSTR)bstrInLabel,
  3326. (LPCWSTR)bstrIn
  3327. );
  3328. }
  3329. else
  3330. {
  3331. return WBEM_E_OUT_OF_MEMORY;
  3332. }
  3333. }
  3334. else if (NULL != (LPCWSTR)bstrOut)
  3335. {
  3336. //
  3337. // <bstrOutLabel>=<bstrOut>.
  3338. //
  3339. dwLength = wcslen(bstrOutLabel) + 1 + wcslen(bstrOut) + 2;
  3340. bstrParamDetail.m_str = ::SysAllocStringLen(NULL, dwLength);
  3341. if (bstrParamDetail.m_str != NULL)
  3342. {
  3343. ::_snwprintf(bstrParamDetail.m_str,
  3344. dwLength,
  3345. L"%s=%s",
  3346. (LPCWSTR)bstrOutLabel,
  3347. (LPCWSTR)bstrOut
  3348. );
  3349. }
  3350. else
  3351. {
  3352. return WBEM_E_OUT_OF_MEMORY;
  3353. }
  3354. }
  3355. }
  3356. //
  3357. // now create a logging instance (Sce_ConfigurationLogRecord) and put it.
  3358. //
  3359. CComPtr<IWbemClassObject> srpObj;
  3360. HRESULT hr = m_srpNativeNS->GetObject(SCEWMI_LOG_CLASS, 0, NULL, &srpObj, NULL);
  3361. if (SUCCEEDED(hr))
  3362. {
  3363. CComPtr<IWbemClassObject> srpLogInst;
  3364. hr = srpObj->SpawnInstance(0, &srpLogInst);
  3365. //
  3366. // populate the log instance's properties
  3367. //
  3368. if (SUCCEEDED(hr))
  3369. {
  3370. //
  3371. // CScePropertyMgr helps us to access WMI object's properties
  3372. // create an instance and attach the WMI object to it.
  3373. // This will always succeed.
  3374. //
  3375. CScePropertyMgr ScePropMgr;
  3376. ScePropMgr.Attach(srpLogInst);
  3377. //
  3378. // need to add escape for backslash
  3379. //
  3380. CComBSTR bstrDblBackSlash;
  3381. hr = ::ConvertToDoubleBackSlashPath(m_bstrLogFilePath, L'\\', &bstrDblBackSlash);
  3382. //
  3383. // set all available members. If we can't set log file path, then we have to quit
  3384. // we will allow other properties to be missing
  3385. //
  3386. if (SUCCEEDED(hr))
  3387. {
  3388. hr = ScePropMgr.PutProperty(pLogFilePath, bstrDblBackSlash);
  3389. }
  3390. if (SUCCEEDED(hr))
  3391. {
  3392. hr = ScePropMgr.PutProperty(pLogArea, pszAreaAttachmentClasses);
  3393. }
  3394. if (SUCCEEDED(hr) && NULL != (LPCWSTR)bstrAction)
  3395. {
  3396. hr = ScePropMgr.PutProperty(pAction, bstrAction);
  3397. }
  3398. if (SUCCEEDED(hr) && NULL != (LPCWSTR)bstrErrorCause)
  3399. {
  3400. hr = ScePropMgr.PutProperty(pErrorCause, bstrErrorCause);
  3401. }
  3402. if (SUCCEEDED(hr) && NULL != (LPCWSTR)bstrObjDetail)
  3403. {
  3404. hr = ScePropMgr.PutProperty(pObjectDetail, bstrObjDetail);
  3405. }
  3406. if (SUCCEEDED(hr) && NULL != (LPCWSTR)bstrParamDetail)
  3407. {
  3408. hr = ScePropMgr.PutProperty(pParameterDetail, bstrParamDetail);
  3409. }
  3410. if (SUCCEEDED(hr))
  3411. {
  3412. hr = ScePropMgr.PutProperty(pLogErrorCode, (DWORD)hrResult);
  3413. }
  3414. //
  3415. // if all information is takenly, then we can put the instance
  3416. // whic will cause a log record.
  3417. //
  3418. if (SUCCEEDED(hr))
  3419. {
  3420. hr = m_srpNativeNS->PutInstance(srpLogInst, 0, m_srpCtx, NULL);
  3421. }
  3422. }
  3423. }
  3424. return hr;
  3425. }
  3426. /*
  3427. Routine Description:
  3428. Name:
  3429. CMethodResultRecorder::FormatVerboseMsg
  3430. Functionality:
  3431. Create a verbose message for a wbem object. Used for logging.
  3432. Virtual:
  3433. No
  3434. Arguments:
  3435. pObject - The wbem object.
  3436. pbstrMsg - receives the verbose message.
  3437. Return Value:
  3438. Success:
  3439. Various success codes.
  3440. Failure:
  3441. Various error codes.
  3442. Notes:
  3443. (1) we will generate such a string:
  3444. Object detail = xxxxxxxxxxxxxxxxxxx
  3445. (2) All values will share our common syntax that is used everywhere:
  3446. <VT_Type : xxxxxx >
  3447. */
  3448. HRESULT
  3449. CMethodResultRecorder::FormatVerboseMsg (
  3450. IN IWbemClassObject * pObject,
  3451. OUT BSTR * pbstrMsg
  3452. )const
  3453. {
  3454. HRESULT hr = WBEM_S_FALSE;
  3455. if (pbstrMsg == NULL || pObject == NULL)
  3456. {
  3457. return WBEM_E_INVALID_PARAMETER;
  3458. }
  3459. *pbstrMsg = NULL;
  3460. //
  3461. // vecNameData will hold each member's formatted string. This is more efficient than appending (n-square).
  3462. //
  3463. std::vector<LPWSTR> vecNameData;
  3464. DWORD dwTotalLength = 0;
  3465. //
  3466. // go through all of the class's properties (not those in base class)
  3467. //
  3468. hr = pObject->BeginEnumeration(WBEM_FLAG_LOCAL_ONLY);
  3469. while (SUCCEEDED(hr))
  3470. {
  3471. CComBSTR bstrName;
  3472. CComVariant varValue;
  3473. hr = pObject->Next(0, &bstrName, &varValue, NULL, NULL);
  3474. if (FAILED(hr) || WBEM_S_NO_MORE_DATA == hr)
  3475. {
  3476. break;
  3477. }
  3478. CComBSTR bstrData;
  3479. //
  3480. // in case the data is not present
  3481. //
  3482. if (varValue.vt == VT_EMPTY || varValue.vt == VT_NULL)
  3483. {
  3484. bstrData = L"<NULL>";
  3485. }
  3486. else
  3487. {
  3488. hr = ::FormatVariant(&varValue, &bstrData);
  3489. }
  3490. //
  3491. // format the (name, data) in the name = data fashion.
  3492. //
  3493. if (SUCCEEDED(hr))
  3494. {
  3495. //
  3496. // 1 for '=', and 1 for '\0'
  3497. //
  3498. DWORD dwSize = wcslen(bstrName) + 1 + wcslen(bstrData) + 1;
  3499. LPWSTR pszMsg = new WCHAR[dwSize];
  3500. if (pszMsg != NULL)
  3501. {
  3502. _snwprintf(pszMsg, dwSize, L"%s=%s", (LPCWSTR)bstrName, (LPCWSTR)bstrData);
  3503. //
  3504. // vector takes care of this memory
  3505. //
  3506. vecNameData.push_back(pszMsg);
  3507. //
  3508. // accumulating the total length
  3509. //
  3510. dwTotalLength += dwSize - 1;
  3511. }
  3512. else
  3513. {
  3514. hr = WBEM_E_OUT_OF_MEMORY;
  3515. }
  3516. }
  3517. }
  3518. pObject->EndEnumeration();
  3519. //
  3520. // put all those in the output bstr
  3521. //
  3522. DWORD dwSize = vecNameData.size();
  3523. if (dwSize > 0)
  3524. {
  3525. //
  3526. // each 2 for ", " between properties, 1 for the '\0'
  3527. //
  3528. *pbstrMsg = ::SysAllocStringLen(NULL, (2 * dwSize) + dwTotalLength + 1);
  3529. //
  3530. // running point for writing
  3531. //
  3532. LPWSTR pszCur = *pbstrMsg;
  3533. DWORD dwIndex = 0;
  3534. //
  3535. // for each item in the vector, we need to copy it to the running point for writing
  3536. //
  3537. if (*pbstrMsg != NULL)
  3538. {
  3539. for (dwIndex = 0; dwIndex < dwSize; ++dwIndex)
  3540. {
  3541. //
  3542. // put the name. Our buffer size makes sure that we won't overrun buffer.
  3543. //
  3544. wcscpy(pszCur, vecNameData[dwIndex]);
  3545. //
  3546. // moving the running point for writing
  3547. //
  3548. pszCur += wcslen(vecNameData[dwIndex]);
  3549. if (dwIndex < dwSize - 1)
  3550. {
  3551. wcscpy(pszCur, L", ");
  3552. pszCur += 2;
  3553. }
  3554. else if (dwIndex == dwSize - 1)
  3555. {
  3556. wcscpy(pszCur, L". ");
  3557. pszCur += 2;
  3558. }
  3559. }
  3560. //
  3561. // done. So 0 terminate it!
  3562. //
  3563. *pszCur = L'\0';
  3564. }
  3565. else
  3566. {
  3567. hr = WBEM_E_OUT_OF_MEMORY;
  3568. }
  3569. //
  3570. // now, clean up the memory
  3571. //
  3572. for (dwIndex = 0; dwIndex < dwSize; ++dwIndex)
  3573. {
  3574. delete [] vecNameData[dwIndex];
  3575. }
  3576. }
  3577. return (*pbstrMsg != NULL) ? WBEM_NO_ERROR : hr;
  3578. }