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.

1567 lines
48 KiB

  1. // operation.cpp, implementation of CSceOperation class
  2. // Copyright (c)1997-1999 Microsoft Corporation
  3. //
  4. //////////////////////////////////////////////////////////////////////
  5. #include "precomp.h"
  6. #include "operation.h"
  7. #include "persistmgr.h"
  8. #include "requestobject.h"
  9. #include <io.h>
  10. #include "extbase.h"
  11. #include "sequence.h"
  12. #include "sceprov.h"
  13. #include "Tranx.h"
  14. /*
  15. Routine Description:
  16. Name:
  17. CSceOperation::CSceOperation
  18. Functionality:
  19. This is the constructor. Pass along the parameters to the base class
  20. Virtual:
  21. No (you know that, constructor won't be virtual!)
  22. Arguments:
  23. pKeyChain - Pointer to the ISceKeyChain COM interface which is prepared
  24. by the caller who constructs this instance.
  25. pNamespace - Pointer to WMI namespace of our provider (COM interface).
  26. Passed along by the caller. Must not be NULL.
  27. pCtx - Pointer to WMI context object (COM interface). Passed along
  28. by the caller. It's up to WMI whether this interface pointer is NULL or not.
  29. Return Value:
  30. None as any constructor
  31. Notes:
  32. if you create any local members, think about initialize them here
  33. */
  34. CSceOperation::CSceOperation (
  35. IN ISceKeyChain * pKeyChain,
  36. IN IWbemServices * pNamespace,
  37. IN IWbemContext * pCtx
  38. )
  39. :
  40. CGenericClass(pKeyChain, pNamespace, pCtx)
  41. {
  42. }
  43. /*
  44. Routine Description:
  45. Name:
  46. CSceOperation::ExecMethod
  47. Functionality:
  48. Called by CRequestObject to execute a method supported by Sce_Operation class.
  49. This function will also trigger the extension classes method execution. This is
  50. the entry point of all our Configure, Import/Export actitivities.
  51. Virtual:
  52. Yes.
  53. Arguments:
  54. bstrPath - Template's path (file name).
  55. bstrMethod - method's name.
  56. bIsInstance - if this is an instance, should always be false.
  57. pInParams - Input parameter from WMI to the method execution.
  58. pHandler - sink that informs WMI of execution results.
  59. pCtx - the usual context that passes around to make WMI happy.
  60. Return Value:
  61. Success: many different success code (use SUCCEEDED(hr) to test)
  62. Failure: various errors code.
  63. Notes:
  64. */
  65. HRESULT
  66. CSceOperation::ExecMethod (
  67. IN BSTR bstrPath,
  68. IN BSTR bstrMethod,
  69. IN bool bIsInstance,
  70. IN IWbemClassObject * pInParams,
  71. IN IWbemObjectSink * pHandler,
  72. IN IWbemContext * pCtx
  73. )
  74. {
  75. if ( pInParams == NULL || pHandler == NULL )
  76. {
  77. return WBEM_E_INVALID_PARAMETER;
  78. }
  79. HRESULT hr=WBEM_S_NO_ERROR;
  80. METHODTYPE mtAction;
  81. if ( !bIsInstance )
  82. {
  83. //
  84. //Static Methods
  85. //
  86. if(0 == _wcsicmp(bstrMethod, pwMethodImport))
  87. {
  88. mtAction = METHODTYPE_IMPORT;
  89. }
  90. else if(0 == _wcsicmp(bstrMethod, pwMethodExport))
  91. {
  92. mtAction = METHODTYPE_EXPORT;
  93. }
  94. else if(0 == _wcsicmp(bstrMethod, pwMethodApply))
  95. {
  96. mtAction = METHODTYPE_APPLY;
  97. }
  98. else
  99. {
  100. hr = WBEM_E_NOT_SUPPORTED;
  101. }
  102. }
  103. else
  104. {
  105. //
  106. //Non-Static Methods
  107. //
  108. hr = WBEM_E_NOT_SUPPORTED;
  109. }
  110. if ( FAILED(hr) )
  111. {
  112. return hr;
  113. }
  114. //
  115. // will cache various SCE operation's status return value
  116. //
  117. SCESTATUS rc;
  118. //
  119. // enum for recognizing various operations (methods)
  120. //
  121. DWORD Option;
  122. //
  123. // parse the input parameters
  124. //
  125. CComBSTR bstrDatabase;
  126. CComBSTR bstrTemplate;
  127. CComBSTR bstrLog;
  128. CComBSTR bstrCfg;
  129. UINT uiStatus = 0;
  130. CComBSTR bstrReturnValue(L"ReturnValue");
  131. CComPtr<IWbemClassObject> srpClass;
  132. CComPtr<IWbemClassObject> srpOutClass;
  133. CComPtr<IWbemClassObject> srpReturnValObj;
  134. //
  135. // attach a WMI object to the property mgr.
  136. // This will always succeed.
  137. //
  138. CScePropertyMgr SceInParam;
  139. SceInParam.Attach(pInParams);
  140. CComBSTR bstrClassName;
  141. m_srpKeyChain->GetClassName(&bstrClassName);
  142. //
  143. // to avoid reentrance to this function by different threads (which may cause
  144. // serious system consistency problems).
  145. // ***************************************************************************
  146. // *****don't blindly return. Allow us to leave the Critical section*****
  147. // ***************************************************************************
  148. //
  149. s_OperationCS.Enter();
  150. try
  151. {
  152. //
  153. // g_LogOption is global variable. Need protection.
  154. //
  155. g_CS.Enter();
  156. //
  157. // update the logging operations
  158. //
  159. g_LogOption.GetLogOptionsFromWbemObject(m_srpNamespace);
  160. g_CS.Leave();
  161. //
  162. // need to find out what methods this class really supports. For that purpose
  163. // we need a definition object of this class.
  164. //
  165. m_srpNamespace->GetObject(bstrClassName, 0, pCtx, &srpClass, NULL);
  166. if(SUCCEEDED(hr))
  167. {
  168. //
  169. // does it really supports this method?
  170. //
  171. if(SUCCEEDED(hr = srpClass->GetMethod(bstrMethod, 0, NULL, &srpOutClass)))
  172. {
  173. if(SUCCEEDED(hr = srpOutClass->SpawnInstance(0, &srpReturnValObj)))
  174. {
  175. //
  176. // execute a method is on a database template (even though our extension
  177. // classes are store neutral). This is due to the SCE engine side's implementation.
  178. // Get DatabaseName. No template name, no action can be taken.
  179. //
  180. BOOL bDB=FALSE;
  181. hr = SceInParam.GetExpandedPath(pDatabasePath, &bstrDatabase, &bDB);
  182. if (hr == WBEM_S_RESET_TO_DEFAULT)
  183. {
  184. hr = WBEM_E_INVALID_PARAMETER;
  185. }
  186. if(SUCCEEDED(hr))
  187. {
  188. //
  189. // Again, at this moment, SCE only supports configuring database.
  190. // however, that is not true for extension classes
  191. //
  192. BOOL bSCEConfigure = bDB;
  193. if ( SUCCEEDED(hr) )
  194. {
  195. //
  196. // get area mask, which determines which area the method will be applied.
  197. //
  198. DWORD dwAreas=0;
  199. hr = SceInParam.GetProperty(pAreaMask, &dwAreas);
  200. if ( hr == WBEM_S_RESET_TO_DEFAULT )
  201. {
  202. dwAreas = AREA_ALL;
  203. }
  204. bool bOverwrite=FALSE;
  205. switch ( mtAction )
  206. {
  207. case METHODTYPE_IMPORT:
  208. case METHODTYPE_EXPORT:
  209. //
  210. //Get TemplateName, not exist for the apply method
  211. //
  212. hr = SceInParam.GetExpandedPath(pTemplatePath, &bstrTemplate, &bDB);
  213. if ( hr == WBEM_S_RESET_TO_DEFAULT && bDB)
  214. {
  215. hr = WBEM_E_INVALID_METHOD_PARAMETERS;
  216. }
  217. if ( SUCCEEDED(hr) && mtAction == METHODTYPE_IMPORT )
  218. {
  219. //
  220. // get overwrite flag
  221. //
  222. hr = SceInParam.GetProperty(pOverwrite, &bOverwrite);
  223. }
  224. else
  225. {
  226. //
  227. // make sure the template name has only single back slash
  228. // import method doesn't need to do this because it takes
  229. // names in both single slash and double back slash
  230. //
  231. hr = MakeSingleBackSlashPath(bstrTemplate, L'\\', &bstrCfg);
  232. if (SUCCEEDED(hr))
  233. {
  234. bstrTemplate = bstrCfg;
  235. }
  236. }
  237. break;
  238. case METHODTYPE_APPLY:
  239. //
  240. // get LogName, optional
  241. //
  242. hr = SceInParam.GetExpandedPath(pLogFilePath, &bstrLog, &bDB);
  243. if ( SUCCEEDED(hr) && bDB )
  244. {
  245. //
  246. // can't log into a database
  247. //
  248. hr = WBEM_E_INVALID_METHOD_PARAMETERS;
  249. }
  250. break;
  251. default:
  252. hr = WBEM_E_INVALID_PARAMETER;
  253. break;
  254. }
  255. //
  256. // prepare a logger. It can log various execution results
  257. //
  258. hr = m_clsResLog.Initialize(bstrLog, SCEWMI_OPERATION_CLASS, m_srpNamespace, pCtx);
  259. if ( SUCCEEDED(hr) )
  260. {
  261. //
  262. // process options
  263. //
  264. if ( bOverwrite )
  265. {
  266. Option = SCE_OVERWRITE_DB;
  267. }
  268. else
  269. {
  270. Option = SCE_UPDATE_DB;
  271. }
  272. if ( (LPCWSTR)bstrLog == NULL || wcslen(bstrLog) == 0)
  273. {
  274. Option |= SCE_DISABLE_LOG;
  275. }
  276. else
  277. {
  278. Option |= SCE_VERBOSE_LOG;
  279. }
  280. HRESULT hrExe = WBEM_NO_ERROR;
  281. try
  282. {
  283. switch ( mtAction )
  284. {
  285. case METHODTYPE_IMPORT:
  286. Option |= SCE_NO_CONFIG;
  287. //
  288. // fall through
  289. //
  290. case METHODTYPE_APPLY:
  291. //
  292. //Call for import/configure
  293. //
  294. if (METHODTYPE_APPLY == mtAction)
  295. {
  296. CTranxID::BeginTransaction(bstrDatabase);
  297. }
  298. //
  299. // see comments where this variable is declared
  300. //
  301. if (bSCEConfigure)
  302. {
  303. rc = SceConfigureSystem(
  304. NULL,
  305. ((LPCWSTR)bstrTemplate == NULL) ? NULL : bstrTemplate,
  306. bstrDatabase,
  307. ((LPCWSTR)bstrLog == NULL) ? NULL : bstrLog,
  308. Option,
  309. (AREA_INFORMATION)dwAreas,
  310. NULL,
  311. NULL,
  312. NULL
  313. );
  314. //
  315. // SCE returned errors needs to be translated to HRESULT.
  316. //
  317. hr = ProvDosErrorToWbemError(ProvSceStatusToDosError(rc));
  318. //
  319. // Log the execution result.
  320. // will ignore the return result, see declaration of m_clsResLog for reasoning
  321. //
  322. if (mtAction == METHODTYPE_IMPORT)
  323. {
  324. m_clsResLog.LogResult(hr, NULL, pInParams, NULL, pwMethodImport, NULL, IDS_IMPORT_TEMPLATE, bstrDatabase);
  325. }
  326. else
  327. {
  328. m_clsResLog.LogResult(hr, NULL, pInParams, NULL, pwMethodApply, NULL, IDS_CONFIGURE_DB, bstrDatabase);
  329. }
  330. }
  331. if ( mtAction == METHODTYPE_APPLY )
  332. {
  333. //
  334. // for Sce_Pod
  335. //
  336. hrExe = ProcessAttachmentData(pCtx,
  337. bstrDatabase,
  338. ((LPCWSTR)bstrLog == NULL) ? NULL : bstrLog,
  339. pwMethodApply,
  340. Option,
  341. (DWORD *)&rc);
  342. //
  343. // track the first error
  344. //
  345. if (SUCCEEDED(hr))
  346. {
  347. hr = hrExe;
  348. }
  349. //
  350. // we will continue our execution even if hr has indicated failures
  351. //
  352. //
  353. // for Sce_EmbedFO, error will be loged inside embed class's method execution
  354. //
  355. hrExe = ExecMethodOnForeignObjects(pCtx,
  356. bstrDatabase,
  357. ((LPCWSTR)bstrLog == NULL) ? NULL : bstrLog,
  358. pwMethodApply,
  359. Option,
  360. (DWORD *)&rc);
  361. //
  362. // track the first error
  363. //
  364. if (SUCCEEDED(hr))
  365. {
  366. hr = hrExe;
  367. }
  368. // for Sce_LinkFO
  369. //hr = ExecMethodOnForeignObjects(pCtx,
  370. // bstrDatabase,
  371. // ((LPCWSTR)bstrLog == NULL) ? NULL : bstrLog,
  372. // SCEWMI_LINK_BASE_CLASS,
  373. // pwMethodApply,
  374. // Option,
  375. // (DWORD *)&rc);
  376. if ( SUCCEEDED(hr) && rc != ERROR_SUCCESS )
  377. {
  378. uiStatus = rc;
  379. }
  380. }
  381. if (METHODTYPE_APPLY == mtAction)
  382. {
  383. CTranxID::EndTransaction();
  384. }
  385. break;
  386. case METHODTYPE_EXPORT:
  387. uiStatus = SceSetupGenerateTemplate(
  388. NULL,
  389. bstrDatabase,
  390. FALSE,
  391. ((LPCWSTR)bstrTemplate == NULL) ? NULL : bstrTemplate,
  392. ((LPCWSTR)bstrLog == NULL) ? NULL : bstrLog,
  393. (AREA_INFORMATION)dwAreas
  394. );
  395. //
  396. // SCE returned errors needs to be translated to HRESULT.
  397. //
  398. hr = ProvDosErrorToWbemError(ProvSceStatusToDosError(uiStatus));
  399. //
  400. // will ignore the return result, see declaration of m_clsResLog for reasoning
  401. //
  402. m_clsResLog.LogResult(hr, NULL, pInParams, NULL, pwMethodExport, NULL, IDS_EXPORT_DB, bstrDatabase);
  403. break;
  404. default:
  405. //
  406. //hr = WBEM_E_NOT_SUPPORTED;
  407. //
  408. break;
  409. }
  410. }
  411. catch(...)
  412. {
  413. uiStatus = RPC_E_SERVERFAULT;
  414. }
  415. if ( SUCCEEDED(hr) )
  416. {
  417. //
  418. //Set up ReturnValue
  419. //
  420. VARIANT v;
  421. ::VariantInit(&v);
  422. V_VT(&v) = VT_I4;
  423. V_I4(&v) = uiStatus;
  424. if(SUCCEEDED(hr = srpReturnValObj->Put(bstrReturnValue, 0, &v, NULL)))
  425. {
  426. pHandler->Indicate(1, &srpReturnValObj);
  427. }
  428. ::VariantClear(&v);
  429. }
  430. }
  431. }
  432. }
  433. }
  434. }
  435. }
  436. }
  437. catch (...)
  438. {
  439. }
  440. s_OperationCS.Leave();
  441. return hr;
  442. }
  443. /*
  444. Routine Description:
  445. Name:
  446. CSceOperation::ProcessAttachmentData
  447. Functionality:
  448. Private helper. Called by CSceOperation::ExecMethod to execute a method supported by all
  449. Sce_Pod classes.
  450. Virtual:
  451. no.
  452. Arguments:
  453. pCtx - the usual context that passes around to make WMI happy.
  454. pszDatabase - Template's path (file name).
  455. pszLog - the log file's path.
  456. bstrMethod - method's name.
  457. Option - doesn't seem to be used any more.
  458. pdwStatus - the returned SCESTATUS value.
  459. Return Value:
  460. Success: many different success code (use SUCCEEDED(hr) to test)
  461. Failure: various errors codes. If for multiple instances, one of them return errors during
  462. execution of the methods, we will try to return to first such error.
  463. Notes:
  464. */
  465. HRESULT
  466. CSceOperation::ProcessAttachmentData (
  467. IN IWbemContext * pCtx,
  468. IN LPCWSTR pszDatabase,
  469. IN LPCWSTR pszLog OPTIONAL,
  470. IN LPCWSTR pszMethod,
  471. IN DWORD Option,
  472. OUT DWORD * pdwStatus
  473. )
  474. {
  475. if ( pszDatabase == NULL || pdwStatus == NULL )
  476. {
  477. return WBEM_E_INVALID_PARAMETER;
  478. }
  479. *pdwStatus = 0;
  480. HRESULT hr;
  481. //
  482. // get all inherited classes from pszExtBaseClass (currently, we have Sce_Pod, Sce_EmbedFO, Sce_LinkFO
  483. // one class per attachment
  484. //
  485. CComBSTR bstrSuperClass(SCEWMI_POD_CLASS);
  486. if ( (BSTR)bstrSuperClass == NULL )
  487. {
  488. return WBEM_E_OUT_OF_MEMORY;
  489. }
  490. CComPtr<IEnumWbemClassObject> srpEnum;
  491. ULONG n=0;
  492. hr = m_srpNamespace->CreateClassEnum(bstrSuperClass,
  493. WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY,
  494. pCtx,
  495. &srpEnum
  496. );
  497. if (FAILED(hr))
  498. {
  499. //
  500. // will ignore the return result, see declaration of m_clsResLog for reasoning
  501. //
  502. m_clsResLog.LogResult(hr, NULL, NULL, NULL, L"CSceOperation::ProcessAttachmentData", NULL, IDS_CREATE_CLASSENUM, bstrSuperClass);
  503. return hr;
  504. }
  505. HRESULT hrFirstError = WBEM_NO_ERROR;
  506. if (SUCCEEDED(hr))
  507. {
  508. CComBSTR bstrMethod(pszMethod);
  509. //
  510. // build the input parameters
  511. //
  512. //
  513. // each instance returned should represent one attachment
  514. //
  515. do {
  516. CComPtr<IWbemClassObject> srpObj;
  517. CComPtr<IWbemClassObject> srpInClass;
  518. hr = srpEnum->Next(WBEM_INFINITE, 1, &srpObj, &n);
  519. //
  520. // failed to enumerate or doesn't return anything, we are fine with that
  521. // since if the store doesn't contain any instances, we don't have to do anything
  522. // and it is not an error
  523. //
  524. if (FAILED(hr) || hr == WBEM_S_FALSE )
  525. {
  526. hr = WBEM_NO_ERROR;
  527. break;
  528. }
  529. if (SUCCEEDED(hr) && n>0 )
  530. {
  531. //
  532. // find one attachment class
  533. //
  534. CComVariant varClass;
  535. //
  536. // need this class's name
  537. //
  538. if(SUCCEEDED(hr=srpObj->Get(L"__CLASS", 0, &varClass, NULL, NULL)))
  539. {
  540. if (SUCCEEDED(hr))
  541. {
  542. if (varClass.vt != VT_BSTR)
  543. {
  544. break;
  545. }
  546. }
  547. if ( SUCCEEDED(hr) )
  548. {
  549. //
  550. // create input parameters
  551. //
  552. hr = srpObj->GetMethod(bstrMethod, 0, &srpInClass, NULL);
  553. }
  554. // everything is fine, we will then execute this pod's method
  555. if ( SUCCEEDED(hr) )
  556. {
  557. hr = ExecutePodMethod(pCtx, pszDatabase, pszLog, varClass.bstrVal, bstrMethod, srpInClass, pdwStatus);
  558. }
  559. }
  560. if (FAILED(hr) && SUCCEEDED(hrFirstError))
  561. {
  562. hrFirstError = hr;
  563. }
  564. }
  565. } while (true);
  566. }
  567. //
  568. // will report the first error
  569. //
  570. return SUCCEEDED(hrFirstError) ? hr : hrFirstError;
  571. }
  572. /*
  573. Routine Description:
  574. Name:
  575. CSceOperation::ExecMethodOnForeignObjects
  576. Functionality:
  577. Private helper. Called by CSceOperation::ExecMethod to execute a method supported by all
  578. extension classes.
  579. Virtual:
  580. no.
  581. Arguments:
  582. pCtx - the usual context that passes around to make WMI happy.
  583. pszDatabase - Template's path (file name).
  584. pszLog - the log file's path.
  585. bstrMethod - method's name.
  586. Option - Log options.
  587. pdwStatus - the returned SCESTATUS value.
  588. Return Value:
  589. Success: many different success code (use SUCCEEDED(hr) to test)
  590. Failure: various errors codes. If for multiple instances, one of them return errors during
  591. execution of the methods, we will try to return to first such error.
  592. Notes:
  593. (1) For each method, we may have a particular order for the classes to execute the method.
  594. Our CSequencer class knows how to create the order.
  595. (2) We will report any error, but at this point, we will continue to execute other instances'
  596. method even if the previous instance has an error.
  597. (3) We will always capture the first error and return it to the caller.
  598. (4) We should also log errors.
  599. */
  600. HRESULT
  601. CSceOperation::ExecMethodOnForeignObjects (
  602. IN IWbemContext * pCtx,
  603. IN LPCWSTR pszDatabase,
  604. IN LPCWSTR pszLog OPTIONAL,
  605. IN LPCWSTR pszMethod,
  606. IN DWORD Option,
  607. OUT DWORD * pdwStatus
  608. )
  609. {
  610. if ( pszDatabase == NULL || pdwStatus == NULL )
  611. {
  612. return WBEM_E_INVALID_PARAMETER;
  613. }
  614. *pdwStatus = 0;
  615. //
  616. // build the class sequence for the method
  617. // we need to build the sequence of classes for this method
  618. //
  619. CSequencer seq;
  620. HRESULT hr = seq.Create(m_srpNamespace, pszDatabase, pszMethod);
  621. if (FAILED(hr))
  622. {
  623. //
  624. // will ignore the return result, see declaration of m_clsResLog for reasoning
  625. //
  626. m_clsResLog.LogResult(hr, NULL, NULL, NULL, L"CSceOperation::ExecMethodOnForeignObjects", NULL, IDS_CREATE_SEQUENCER, pszDatabase);
  627. return hr;
  628. }
  629. //
  630. // this variable will cache all classes that have been called to execute
  631. //
  632. MapExecutedClasses mapExcuted;
  633. //
  634. // we will execute the method according this sequence first
  635. //
  636. HRESULT hrFirstError = WBEM_NO_ERROR;;
  637. const COrderNameList* pClsList = NULL;
  638. if (SUCCEEDED(seq.GetOrderList(&pClsList)) && pClsList)
  639. {
  640. DWORD dwEnumHandle = 0;
  641. //
  642. // pList must not be released here
  643. //
  644. const CNameList* pList = NULL;
  645. while (SUCCEEDED(pClsList->GetNext(&pList, &dwEnumHandle)) && pList)
  646. {
  647. //
  648. // we will report any error
  649. //
  650. for (int i = 0; i < pList->m_vList.size(); i++)
  651. {
  652. hr = ExeClassMethod(pCtx, pszDatabase, pszLog, pList->m_vList[i], pszMethod, Option, pdwStatus, &mapExcuted);
  653. //
  654. // catch the first error to return
  655. //
  656. if (FAILED(hr) && SUCCEEDED(hrFirstError))
  657. {
  658. hrFirstError = hr;
  659. }
  660. }
  661. //
  662. // reset its value for next loop
  663. //
  664. pList = NULL;
  665. }
  666. }
  667. //
  668. // now, we need to execute the rest of the embedded classes whose name doesn't
  669. // show up in the sequencer
  670. //
  671. //
  672. // try all inherited classes from SCEWMI_EMBED_BASE_CLASS
  673. //
  674. hr = ExeClassMethod(pCtx, pszDatabase, pszLog, SCEWMI_EMBED_BASE_CLASS, pszMethod, Option, pdwStatus, &mapExcuted);
  675. //
  676. // catch the first error to return
  677. //
  678. if (FAILED(hr) && SUCCEEDED(hrFirstError))
  679. {
  680. hrFirstError = hr;
  681. }
  682. //
  683. // now clean up the map that caches our already-executed classes map
  684. //
  685. MapExecutedClasses::iterator it = mapExcuted.begin();
  686. while (it != mapExcuted.end())
  687. {
  688. ::SysFreeString((*it).first);
  689. ++it;
  690. }
  691. return FAILED(hrFirstError) ? hrFirstError : hr;
  692. }
  693. /*
  694. Routine Description:
  695. Name:
  696. CSceOperation::ExeClassMethod
  697. Functionality:
  698. Private helper. Called to execute the method on a particular embedding class.
  699. Virtual:
  700. no.
  701. Arguments:
  702. pCtx - the usual context that passes around to make WMI happy.
  703. pszDatabase - Template's path (file name).
  704. pszClsName - individual class name.
  705. pszLog - the log file's path.
  706. bstrMethod - method's name.
  707. Option - Log options, not really used at this time. This is for SCE engine.
  708. pdwStatus - the returned SCESTATUS value.
  709. pExecuted - used to update the list of classes that are execute during this call.
  710. Return Value:
  711. Success: many different success code (use SUCCEEDED(hr) to test)
  712. Failure: various errors codes. If for multiple instances, one of them return errors during
  713. execution of the methods, we will try to return to first such error..
  714. Notes:
  715. */
  716. HRESULT
  717. CSceOperation::ExeClassMethod (
  718. IN IWbemContext * pCtx,
  719. IN LPCWSTR pszDatabase,
  720. IN LPCWSTR pszLog OPTIONAL,
  721. IN LPCWSTR pszClsName,
  722. IN LPCWSTR pszMethod,
  723. IN DWORD Option,
  724. OUT DWORD * pdwStatus,
  725. IN OUT MapExecutedClasses * pExecuted
  726. )
  727. {
  728. //
  729. // WMI needs bstr names
  730. //
  731. CComBSTR bstrClass(pszClsName);
  732. if ( (BSTR)bstrClass == NULL )
  733. {
  734. return WBEM_E_OUT_OF_MEMORY;
  735. }
  736. //
  737. // ask WMI for all those classes of the given name pszClsName
  738. // We need to enumerate because there might be sub-classes of this given name.
  739. //
  740. CComPtr<IEnumWbemClassObject> srpEnum;
  741. ULONG lRetrieved = 0;
  742. HRESULT hr = m_srpNamespace->CreateClassEnum(bstrClass,
  743. WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY,
  744. pCtx,
  745. &srpEnum
  746. );
  747. if (FAILED(hr))
  748. {
  749. //
  750. // will ignore the return result, see declaration of m_clsResLog for reasoning
  751. //
  752. m_clsResLog.LogResult(hr, NULL, NULL, NULL, L"CSceOperation::ExeClassMethod", NULL, IDS_CREATE_CLASSENUM, pszClsName);
  753. return hr;
  754. }
  755. //
  756. // determines if this class has any sub-classes or not
  757. //
  758. ULONG lTotlRetrieved = 0;
  759. //
  760. // catch the first error to return
  761. //
  762. HRESULT hrFirstError = WBEM_NO_ERROR;
  763. if (SUCCEEDED(hr))
  764. {
  765. CComBSTR bstrMethod(pszMethod);
  766. do {
  767. CComPtr<IWbemClassObject> srpObj;
  768. CComPtr<IWbemClassObject> srpInClass;
  769. //
  770. // get one class a time
  771. //
  772. hr = srpEnum->Next(WBEM_INFINITE, 1, &srpObj, &lRetrieved);
  773. lTotlRetrieved += lRetrieved;
  774. //
  775. // if the class has no subclass, then we need to try the class itself. We will allow this to fail,
  776. // meaning that we can't find any instance of this class
  777. //
  778. if ((FAILED(hr) || hr == WBEM_S_FALSE) )
  779. {
  780. //
  781. // if we have successfully gone through some sub-classes, then we can break
  782. // because it tells us that it doesn't have any more subs.
  783. //
  784. if (lTotlRetrieved > 0)
  785. {
  786. break;
  787. }
  788. //
  789. // try to get the definition of this class in case this is not an abstract one
  790. //
  791. else if (FAILED(m_srpNamespace->GetObject(bstrClass, 0, pCtx, &srpObj, NULL)))
  792. {
  793. m_clsResLog.LogResult(hr, NULL, NULL, NULL, L"CSceOperation::ExeClassMethod", NULL, IDS_GET_CLASS_INSTANCE, pszClsName);
  794. break;
  795. }
  796. }
  797. //
  798. // we truly have an object of this class
  799. //
  800. if (SUCCEEDED(hr) && srpObj)
  801. {
  802. //
  803. // get the class's name. Remember, we might be retrieving based on the base class's name
  804. // therefore, bstrClass may not be really the instance's class name
  805. //
  806. CComVariant varClass;
  807. if(SUCCEEDED(hr = srpObj->Get(L"__CLASS", 0, &varClass, NULL, NULL)))
  808. {
  809. if (SUCCEEDED(hr))
  810. {
  811. if (varClass.vt != VT_BSTR)
  812. {
  813. break;
  814. }
  815. }
  816. //
  817. // see if the class has been executed before
  818. //
  819. MapExecutedClasses::iterator it = pExecuted->find(varClass.bstrVal);
  820. //
  821. // if not yet executed, then of course, we need to execute it
  822. //
  823. if (it == pExecuted->end())
  824. {
  825. if ( SUCCEEDED(hr) )
  826. {
  827. hr = srpObj->GetMethod(bstrMethod, 0, &srpInClass, NULL);
  828. }
  829. if ( SUCCEEDED(hr) )
  830. {
  831. hr = ExecuteExtensionClassMethod(pCtx, pszDatabase, pszLog, varClass.bstrVal, bstrMethod, srpInClass, pdwStatus);
  832. }
  833. //
  834. // add it to the already-executed class map, the map takes the ownership of the bstr in the variant
  835. // and that is why we can't let the variant to go ahead destroying itself.
  836. //
  837. pExecuted->insert(MapExecutedClasses::value_type(varClass.bstrVal, 0));
  838. //
  839. // prevent the variant from self-destruction
  840. //
  841. varClass.bstrVal = NULL;
  842. varClass.vt = VT_EMPTY;
  843. }
  844. }
  845. else
  846. {
  847. m_clsResLog.LogResult(hr, NULL, NULL, NULL, L"CSceOperation::ExeClassMethod", NULL, IDS_GET_CLASS_DEFINITION, pszClsName);
  848. }
  849. }
  850. //
  851. // don't overwrite the first error
  852. //
  853. if (FAILED(hr) && SUCCEEDED(hrFirstError))
  854. {
  855. hrFirstError = hr;
  856. }
  857. //
  858. // don't loop if this is not a subclass enumeration
  859. //
  860. if (lRetrieved == 0)
  861. {
  862. break;
  863. }
  864. } while (true);
  865. }
  866. //
  867. // will report first error
  868. //
  869. return SUCCEEDED(hrFirstError) ? hr : hrFirstError;
  870. }
  871. /*
  872. Routine Description:
  873. Name:
  874. CSceOperation::ExecutePodMethod
  875. Functionality:
  876. Private helper. Called to execute each Pod's method.
  877. Virtual:
  878. no.
  879. Arguments:
  880. pCtx - the usual context that passes around to make WMI happy.
  881. pszDatabase - Template's path (file name).
  882. pszLog - the log file's path.
  883. bstrMethod - method's name.
  884. Option - doesn't seem to be used any more.
  885. pInClass - input parameter's spawning object.
  886. pdwStatus - the returned SCESTATUS value.
  887. Return Value:
  888. Success: many different success code (use SUCCEEDED(hr) to test)
  889. Failure: various errors codes. If for multiple instances, one of them return errors during
  890. execution of the methods, we will try to try to first such error.
  891. Notes:
  892. */
  893. HRESULT CSceOperation::ExecutePodMethod (
  894. IN IWbemContext * pCtx,
  895. IN LPCWSTR pszDatabase,
  896. IN LPCWSTR pszLog OPTIONAL,
  897. IN BSTR bstrClass,
  898. IN BSTR bstrMethod,
  899. IN IWbemClassObject * pInClass,
  900. OUT DWORD * pdwStatus
  901. )
  902. {
  903. //
  904. // get ready to fill in the input parameters. Without that, we can't make
  905. // a successful method call.
  906. //
  907. CComPtr<IWbemClassObject> srpInParams;
  908. HRESULT hr = pInClass->SpawnInstance(0, &srpInParams);
  909. if (FAILED(hr))
  910. {
  911. m_clsResLog.LogResult(hr, NULL, NULL, NULL, L"CSceOperation::ExecutePodMethod", NULL, IDS_SPAWN_INSTANCE, bstrClass);
  912. }
  913. if (SUCCEEDED(hr))
  914. {
  915. //
  916. // try to fill in in-bound parameter's properties
  917. //
  918. //
  919. // CScePropertyMgr helps us to access WMI object's properties
  920. // create an instance and attach the WMI object to it.
  921. // This will always succeed.
  922. //
  923. CScePropertyMgr ScePropMgr;
  924. ScePropMgr.Attach(srpInParams);
  925. //
  926. // fill in the in parameter
  927. //
  928. hr = ScePropMgr.PutProperty(pStorePath, pszDatabase);
  929. if (FAILED(hr))
  930. {
  931. //
  932. // indicating that the class's pStorePath key property can't be put
  933. //
  934. CComBSTR bstrExtraInfo = bstrClass;
  935. bstrExtraInfo += CComBSTR(L".");
  936. bstrExtraInfo += CComBSTR(pStorePath);
  937. m_clsResLog.LogResult(hr, NULL, NULL, NULL, L"CSceOperation::ExecutePodMethod", NULL, IDS_PUT_PROPERTY, bstrExtraInfo);
  938. return hr;
  939. }
  940. //
  941. // fill in the in parameter
  942. //
  943. hr = ScePropMgr.PutProperty(pLogFilePath, pszLog);
  944. if ( FAILED(hr) )
  945. {
  946. //
  947. // indicating that the class's pLogFilePath key property can't be put
  948. //
  949. CComBSTR bstrExtraInfo = bstrClass;
  950. bstrExtraInfo += CComBSTR(L".");
  951. bstrExtraInfo += CComBSTR(pLogFilePath);
  952. m_clsResLog.LogResult(hr, NULL, NULL, NULL, L"CSceOperation::ExecutePodMethod", NULL, IDS_PUT_PROPERTY, bstrExtraInfo);
  953. }
  954. else
  955. {
  956. //
  957. // create the out-bound parameter
  958. //
  959. CComPtr<IWbemClassObject> srpOutParams;
  960. //
  961. // make a call the the attachment provider
  962. // must be in synchronous mode
  963. //
  964. hr = m_srpNamespace->ExecMethod(bstrClass,
  965. bstrMethod,
  966. 0,
  967. pCtx,
  968. srpInParams,
  969. &srpOutParams,
  970. NULL
  971. );
  972. if ( SUCCEEDED(hr) && srpOutParams )
  973. {
  974. //
  975. // retrieve the return value
  976. //
  977. //
  978. // CScePropertyMgr helps us to access WMI object's properties
  979. // create an instance and attach the WMI object to it.
  980. // This will always succeed.
  981. //
  982. CScePropertyMgr SceOutReader;
  983. SceOutReader.Attach(srpOutParams);
  984. hr = SceOutReader.GetProperty(L"ReturnValue", pdwStatus);
  985. }
  986. //
  987. // ignore not found error
  988. // if there is no data for an attachment
  989. //
  990. if ( hr == WBEM_E_NOT_FOUND || hr == WBEM_E_INVALID_QUERY)
  991. {
  992. hr = WBEM_S_NO_ERROR;
  993. }
  994. }
  995. }
  996. return hr;
  997. }
  998. /*
  999. Routine Description:
  1000. Name:
  1001. CSceOperation::ExecuteExtensionClassMethod
  1002. Functionality:
  1003. Private helper. Called to execute the method on a particular embedding class instance.
  1004. Virtual:
  1005. no.
  1006. Arguments:
  1007. pCtx - the usual context that passes around to make WMI happy.
  1008. pszDatabase - Template's path (file name).
  1009. pszClsName - individual class name.
  1010. pszLog - the log file's path.
  1011. bstrMethod - method's name.
  1012. Option - Log options, not really used at this time. This is for SCE engine.
  1013. pInClass - input parameter's spawning object.
  1014. pdwStatus - the returned SCESTATUS value.
  1015. Return Value:
  1016. Success: many different success code (use SUCCEEDED(hr) to test)
  1017. Failure: various errors codes. If for multiple instances, one of them return errors during
  1018. execution of the methods, we will try to return to first such error..
  1019. Notes:
  1020. This is the per-instance method call, the final leg of method execution process.
  1021. */
  1022. HRESULT
  1023. CSceOperation::ExecuteExtensionClassMethod (
  1024. IN IWbemContext * pCtx,
  1025. IN LPCWSTR pszDatabase,
  1026. IN LPCWSTR pszLog OPTIONAL,
  1027. IN BSTR bstrClass,
  1028. IN BSTR bstrMethod,
  1029. IN IWbemClassObject * pInClass,
  1030. OUT DWORD * pdwStatus
  1031. )
  1032. {
  1033. //
  1034. // create the input parameter instance.
  1035. //
  1036. CComPtr<IWbemClassObject> srpInParams;
  1037. HRESULT hr = pInClass->SpawnInstance(0, &srpInParams);
  1038. //
  1039. // catch the first error to return
  1040. //
  1041. HRESULT hrFirstError = WBEM_NO_ERROR;
  1042. if (SUCCEEDED(hr))
  1043. {
  1044. //
  1045. // create a blank object
  1046. //
  1047. CComPtr<IWbemClassObject> srpSpawn;
  1048. hr = m_srpNamespace->GetObject(bstrClass, 0, m_srpCtx, &srpSpawn, NULL);
  1049. if (FAILED(hr))
  1050. {
  1051. return hr;
  1052. }
  1053. //
  1054. // CScePropertyMgr helps us to access WMI object's properties
  1055. // create an instance and attach the WMI object to it.
  1056. // This will always succeed.
  1057. //
  1058. CScePropertyMgr ScePropMgr;
  1059. ScePropMgr.Attach(srpInParams);
  1060. hr = ScePropMgr.PutProperty(pLogFilePath, pszLog);
  1061. if (FAILED(hr))
  1062. {
  1063. //
  1064. // indicating that the class's pLogFilePath key property can't be put
  1065. //
  1066. CComBSTR bstrExtraInfo = bstrClass;
  1067. bstrExtraInfo += CComBSTR(L".");
  1068. bstrExtraInfo += CComBSTR(pLogFilePath);
  1069. m_clsResLog.LogResult(hr, NULL, NULL, NULL, L"CSceOperation::ExecuteExtensionClassMethod", NULL, IDS_PUT_PROPERTY, bstrExtraInfo);
  1070. }
  1071. //
  1072. // Prepare a store (for persistence) for this store path (file)
  1073. //
  1074. CSceStore SceStore;
  1075. SceStore.SetPersistPath(pszDatabase);
  1076. //
  1077. // now create the list for the class so that we can get the path of the instances.
  1078. // this way, we don't need to query WMI for instances. That is very slow and a lot of redundant
  1079. // reading.
  1080. //
  1081. CExtClassInstCookieList clsInstCookies;
  1082. //
  1083. // we need the foreign class's info for the instance list
  1084. //
  1085. const CForeignClassInfo* pFCInfo = g_ExtClasses.GetForeignClassInfo(m_srpNamespace, pCtx, bstrClass);
  1086. if (pFCInfo == NULL)
  1087. {
  1088. hr = WBEM_E_NOT_FOUND;
  1089. }
  1090. else
  1091. {
  1092. hr = clsInstCookies.Create(&SceStore, bstrClass, pFCInfo->m_pVecKeyPropNames);
  1093. }
  1094. if (FAILED(hr))
  1095. {
  1096. m_clsResLog.LogResult(hr, NULL, NULL, NULL, L"CSceOperation::ExecuteExtensionClassMethod", NULL, IDS_CREATE_INSTANCE_LIST, bstrClass);
  1097. return hr;
  1098. }
  1099. //
  1100. // we have the instance list, so, ready to get the path and execute the method
  1101. //
  1102. if (SUCCEEDED(hr))
  1103. {
  1104. DWORD dwResumeHandle = 0;
  1105. //
  1106. // get the string version of the compound key, which can be
  1107. // used to get the object's path
  1108. //
  1109. CComBSTR bstrEachCompKey;
  1110. hr = clsInstCookies.Next(&bstrEachCompKey, NULL, &dwResumeHandle);
  1111. while (SUCCEEDED(hr) && hr != WBEM_S_NO_MORE_DATA)
  1112. {
  1113. //
  1114. // as long as there is more item, keep looping
  1115. //
  1116. if (SUCCEEDED(hr) && hr != WBEM_S_NO_MORE_DATA)
  1117. {
  1118. //
  1119. // WMI only takes the path (instead of the object) to execute the method.
  1120. // Now, we have the instanace list and it has given its the string version
  1121. // of the compound key, we can ask CScePersistMgr for the object path
  1122. //
  1123. CComBSTR bstrObjPath;
  1124. hr = ::GetObjectPath(srpSpawn, SceStore.GetExpandedPath(), bstrEachCompKey, &bstrObjPath);
  1125. //
  1126. // we get the instanace's path
  1127. //
  1128. if (SUCCEEDED(hr))
  1129. {
  1130. //
  1131. // any execution error will be logged in the calling function
  1132. //
  1133. CComPtr<IWbemClassObject> srpOutParams;
  1134. hr = m_srpNamespace->ExecMethod(bstrObjPath,
  1135. bstrMethod,
  1136. 0,
  1137. pCtx,
  1138. srpInParams,
  1139. &srpOutParams,
  1140. NULL
  1141. );
  1142. //
  1143. // don't overwrite the first error
  1144. //
  1145. if (FAILED(hr) && SUCCEEDED(hrFirstError))
  1146. {
  1147. hrFirstError = hr;
  1148. }
  1149. }
  1150. else
  1151. {
  1152. m_clsResLog.LogResult(hr, NULL, NULL, NULL, L"CSceOperation::ExecuteExtensionClassMethod", NULL, IDS_GET_FULLPATH, bstrClass);
  1153. }
  1154. }
  1155. //
  1156. // get ready to be reused!
  1157. //
  1158. bstrEachCompKey.Empty();
  1159. hr = clsInstCookies.Next(&bstrEachCompKey, NULL, &dwResumeHandle);
  1160. }
  1161. }
  1162. }
  1163. return SUCCEEDED(hrFirstError) ? hr : hrFirstError;
  1164. }