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

666 lines
19 KiB

  1. ////////////////////////////////////////////////////////////////////////
  2. //
  3. // Provider.cpp
  4. //
  5. // Module: WMI high performance provider
  6. //
  7. //
  8. // History:
  9. // a-dcrews 12-Jan-97 Created
  10. //
  11. //
  12. // Copyright (c) 1997-2001 Microsoft Corporation
  13. //
  14. ////////////////////////////////////////////////////////////////////////
  15. #include "precomp.h"
  16. #include <process.h>
  17. #include <autoptr.h>
  18. #include "Provider.h"
  19. #include "CookerUtils.h"
  20. #include <comdef.h>
  21. //////////////////////////////////////////////////////////////
  22. //
  23. //
  24. // Global, external and static variables
  25. //
  26. //
  27. //////////////////////////////////////////////////////////////
  28. // The COM object counter (declared in server.cpp)
  29. // ===============================================
  30. extern long g_lObjects;
  31. //////////////////////////////////////////////////////////////
  32. //
  33. //
  34. // CHiPerfProvider
  35. //
  36. //
  37. //////////////////////////////////////////////////////////////
  38. CHiPerfProvider::CHiPerfProvider() : m_lRef(0)
  39. //////////////////////////////////////////////////////////////
  40. //
  41. // Constructor
  42. //
  43. //////////////////////////////////////////////////////////////
  44. //ok
  45. {
  46. // Increment the global COM object counter
  47. // =======================================
  48. InterlockedIncrement(&g_lObjects);
  49. }
  50. CHiPerfProvider::~CHiPerfProvider()
  51. //////////////////////////////////////////////////////////////
  52. //
  53. // Destructor
  54. //
  55. //////////////////////////////////////////////////////////////
  56. //ok
  57. {
  58. long lObjCount = 0;
  59. // Decrement the global COM object counter
  60. // =======================================
  61. lObjCount = InterlockedDecrement(&g_lObjects);
  62. }
  63. //////////////////////////////////////////////////////////////
  64. //
  65. // COM methods
  66. //
  67. //////////////////////////////////////////////////////////////
  68. STDMETHODIMP CHiPerfProvider::QueryInterface(REFIID riid, void** ppv)
  69. //////////////////////////////////////////////////////////////
  70. //
  71. // Standard QueryInterface
  72. //
  73. // Parameters:
  74. // riid - the ID of the requested interface
  75. // ppv - a pointer to the interface pointer
  76. //
  77. //////////////////////////////////////////////////////////////
  78. //ok
  79. {
  80. if(riid == IID_IUnknown)
  81. *ppv = (LPVOID)(IUnknown*)(IWbemProviderInit*)this;
  82. else if(riid == IID_IWbemProviderInit)
  83. *ppv = (LPVOID)(IWbemProviderInit*)this;
  84. else if (riid == IID_IWbemHiPerfProvider)
  85. *ppv = (LPVOID)(IWbemHiPerfProvider*)this;
  86. else return E_NOINTERFACE;
  87. ((IUnknown*)*ppv)->AddRef();
  88. return WBEM_NO_ERROR;
  89. }
  90. STDMETHODIMP_(ULONG) CHiPerfProvider::AddRef()
  91. //////////////////////////////////////////////////////////////
  92. //
  93. // Standard COM AddRef
  94. //
  95. //////////////////////////////////////////////////////////////
  96. //ok
  97. {
  98. return InterlockedIncrement(&m_lRef);
  99. }
  100. STDMETHODIMP_(ULONG) CHiPerfProvider::Release()
  101. //////////////////////////////////////////////////////////////
  102. //
  103. // Standard COM Release
  104. //
  105. //////////////////////////////////////////////////////////////
  106. //ok
  107. {
  108. long lRef = InterlockedDecrement(&m_lRef);
  109. if(lRef == 0)
  110. delete this;
  111. return lRef;
  112. }
  113. STDMETHODIMP CHiPerfProvider::Initialize(
  114. /* [unique][in] */ LPWSTR wszUser,
  115. /* [in] */ long lFlags,
  116. /* [in] */ LPWSTR wszNamespace,
  117. /* [unique][in] */ LPWSTR wszLocale,
  118. /* [in] */ IWbemServices __RPC_FAR *pNamespace,
  119. /* [in] */ IWbemContext __RPC_FAR *pCtx,
  120. /* [in] */ IWbemProviderInitSink __RPC_FAR *pInitSink)
  121. //////////////////////////////////////////////////////////////////////
  122. //
  123. // Called once during startup for any one-time initialization. The
  124. // final call to Release() is for any cleanup.
  125. //
  126. // The parameters indicate to the provider which namespace it is being
  127. // invoked for and which User. It also supplies a back pointer to
  128. // WINMGMT so that class definitions can be retrieved.
  129. //
  130. // Initialize will create a single template object that can be used
  131. // by the provider to spawn instances for QueryInstances. It will
  132. // also initialize our mock data source and set the global ID access
  133. // handle.
  134. //
  135. // Parameters:
  136. // wszUser - The current user.
  137. // lFlags - Reserved.
  138. // wszNamespace - The namespace for which we are being activated.
  139. // wszLocale - The locale under which we are to be running.
  140. // pNamespace - An active pointer back into the current namespace
  141. // from which we can retrieve schema objects.
  142. // pCtx - The user's context object. We simply reuse this
  143. // during any reentrant operations into WINMGMT.
  144. // pInitSink - The sink to which we indicate our readiness.
  145. //
  146. //////////////////////////////////////////////////////////////////////
  147. //ok
  148. {
  149. HRESULT hResult = WBEM_NO_ERROR;
  150. if (wszNamespace == 0 || pNamespace == 0 || pInitSink == 0)
  151. hResult = WBEM_E_INVALID_PARAMETER;
  152. // Add further initialization code here
  153. // ====================================
  154. // We now have all the instances ready to go and the name handle
  155. // stored. Tell WINMGMT that we're ready to start 'providing'
  156. // =============================================================
  157. if ( SUCCEEDED( hResult ) )
  158. {
  159. pInitSink->SetStatus(WBEM_S_INITIALIZED, 0);
  160. }
  161. return hResult;
  162. }
  163. STDMETHODIMP CHiPerfProvider::CreateRefresher(
  164. /* [in] */ IWbemServices __RPC_FAR *pNamespace,
  165. /* [in] */ long lFlags,
  166. /* [out] */ IWbemRefresher __RPC_FAR *__RPC_FAR *ppRefresher )
  167. //////////////////////////////////////////////////////////////////////
  168. //
  169. // Called whenever a new refresher is needed by the client.
  170. //
  171. // Parameters:
  172. // pNamespace - A pointer to the relevant namespace. Not used.
  173. // lFlags - Reserved.
  174. // ppRefresher - Receives the requested refresher.
  175. //
  176. //////////////////////////////////////////////////////////////////////
  177. //ok
  178. {
  179. HRESULT hResult = WBEM_NO_ERROR;
  180. if ( pNamespace == 0 || ppRefresher == 0 )
  181. hResult = WBEM_E_INVALID_PARAMETER;
  182. if ( SUCCEEDED( hResult ) )
  183. {
  184. // Construct and initialize a new empty refresher
  185. // ==============================================
  186. CRefresher* pNewRefresher = new CRefresher;
  187. if ( NULL == pNewRefresher )
  188. {
  189. hResult = WBEM_E_OUT_OF_MEMORY;
  190. }
  191. else if ( !pNewRefresher->IsOK() )
  192. {
  193. hResult = WBEM_E_CRITICAL_ERROR;
  194. }
  195. if ( SUCCEEDED( hResult ) )
  196. {
  197. // Follow COM rules and AddRef() the thing before sending it back
  198. // ==============================================================
  199. pNewRefresher->AddRef();
  200. *ppRefresher = pNewRefresher;
  201. }
  202. else
  203. {
  204. if ( NULL != pNewRefresher )
  205. delete pNewRefresher;
  206. }
  207. }
  208. return hResult;
  209. }
  210. STDMETHODIMP CHiPerfProvider::CreateRefreshableObject(
  211. /* [in] */ IWbemServices __RPC_FAR *pNamespace,
  212. /* [in] */ IWbemObjectAccess __RPC_FAR *pTemplate,
  213. /* [in] */ IWbemRefresher __RPC_FAR *pRefresher,
  214. /* [in] */ long lFlags,
  215. /* [in] */ IWbemContext __RPC_FAR *pContext,
  216. /* [out] */ IWbemObjectAccess __RPC_FAR *__RPC_FAR *ppRefreshable,
  217. /* [out] */ long __RPC_FAR *plId )
  218. //////////////////////////////////////////////////////////////////////
  219. //
  220. // Called whenever a user wants to include an object in a refresher.
  221. //
  222. // Note that the object returned in ppRefreshable is a clone of the
  223. // actual instance maintained by the provider. If refreshers shared
  224. // a copy of the same instance, then a refresh call on one of the
  225. // refreshers would impact the state of both refreshers. This would
  226. // break the refresher rules. Instances in a refresher are only
  227. // allowed to be updated when 'Refresh' is called.
  228. //
  229. // Parameters:
  230. // pNamespace - A pointer to the relevant namespace in WINMGMT.
  231. // pTemplate - A pointer to a copy of the object which is to be
  232. // added. This object itself cannot be used, as
  233. // it not owned locally.
  234. // pRefresher - The refresher to which to add the object.
  235. // lFlags - Not used.
  236. // pContext - Not used here.
  237. // ppRefreshable - A pointer to the internal object which was added
  238. // to the refresher.
  239. // plId - The Object Id (for identification during removal).
  240. //
  241. //////////////////////////////////////////////////////////////////////
  242. //ok
  243. {
  244. HRESULT hResult = WBEM_NO_ERROR;
  245. if ( pNamespace == 0 || pTemplate == 0 || pRefresher == 0 )
  246. hResult = WBEM_E_INVALID_PARAMETER;
  247. // Verify hi-perf object
  248. // =====================
  249. if ( !IsHiPerfObj( pTemplate ) )
  250. hResult = WBEM_E_INVALID_CLASS;
  251. _variant_t VarClass;
  252. hResult = pTemplate->Get(L"__CLASS",0,&VarClass,NULL,NULL);
  253. if ( SUCCEEDED( hResult ) )
  254. {
  255. if (VT_BSTR == V_VT(&VarClass))
  256. {
  257. if ( !IsHiPerf( pNamespace, V_BSTR(&VarClass) ) )
  258. {
  259. hResult = WBEM_E_INVALID_CLASS;
  260. }
  261. }
  262. else
  263. {
  264. hResult = WBEM_E_INVALID_CLASS;
  265. }
  266. }
  267. if ( SUCCEEDED( hResult ) )
  268. {
  269. // The refresher being supplied by the caller is actually
  270. // one of our own refreshers, so a simple cast is convenient
  271. // so that we can access private members.
  272. // =========================================================
  273. CRefresher *pOurRefresher = ( CRefresher * ) pRefresher;
  274. // Add the object to the refresher. The ID is set by AddObject
  275. // ===========================================================
  276. // NB: We are passing a NULL in as the Raw object. The reason is so we
  277. // can maintain the interface while we are using a private refresher
  278. // on the inside of the cooking object refresher. This will change when
  279. // WMI is wired to synchronize raw instances within the client's refresher
  280. // =======================================================================
  281. hResult = pOurRefresher->AddInstance( pNamespace, pContext, pTemplate, NULL, ppRefreshable, plId );
  282. }
  283. return hResult;
  284. }
  285. STDMETHODIMP CHiPerfProvider::CreateRefreshableEnum(
  286. /* [in] */ IWbemServices* pNamespace,
  287. /* [in, string] */ LPCWSTR wszClass,
  288. /* [in] */ IWbemRefresher* pRefresher,
  289. /* [in] */ long lFlags,
  290. /* [in] */ IWbemContext* pContext,
  291. /* [in] */ IWbemHiPerfEnum* pHiPerfEnum,
  292. /* [out] */ long* plId )
  293. //////////////////////////////////////////////////////////////////////
  294. //
  295. // Called when an enumerator is being added to a refresher. The
  296. // enumerator will obtain a fresh set of instances of the specified
  297. // class every time that refresh is called.
  298. //
  299. // Parameters:
  300. // pNamespace - A pointer to the relevant namespace.
  301. // wszClass - The class name for the requested enumerator.
  302. // pRefresher - The refresher object for which we will add
  303. // the enumerator
  304. // lFlags - Reserved.
  305. // pContext - Not used here.
  306. // pHiPerfEnum - The enumerator to add to the refresher.
  307. // plId - A provider specified ID for the enumerator.
  308. //
  309. //////////////////////////////////////////////////////////////////////
  310. //ok
  311. {
  312. HRESULT hResult = WBEM_NO_ERROR;
  313. if ( pNamespace == 0 || pRefresher == 0 || pHiPerfEnum == 0 )
  314. hResult = WBEM_E_INVALID_PARAMETER;
  315. // Verify hi-perf class
  316. // =====================
  317. if ( !IsHiPerf( pNamespace, wszClass ) )
  318. hResult = WBEM_E_INVALID_CLASS;
  319. if ( SUCCEEDED( hResult ) )
  320. {
  321. // The refresher being supplied by the caller is actually
  322. // one of our own refreshers, so a simple cast is convenient
  323. // so that we can access private members.
  324. CRefresher *pOurRefresher = (CRefresher *) pRefresher;
  325. // Add the enumerator to the refresher. The ID is generated by AddEnum
  326. // ====================================================================
  327. hResult = pOurRefresher->AddEnum( pNamespace, pContext, wszClass, pHiPerfEnum, plId );
  328. }
  329. return hResult;
  330. }
  331. STDMETHODIMP CHiPerfProvider::StopRefreshing(
  332. /* [in] */ IWbemRefresher __RPC_FAR *pRefresher,
  333. /* [in] */ long lId,
  334. /* [in] */ long lFlags )
  335. //////////////////////////////////////////////////////////////////////
  336. //
  337. // Called whenever a user wants to remove an object from a refresher.
  338. //
  339. // Parameters:
  340. // pRefresher - The refresher object from which we are to
  341. // remove the perf object.
  342. // lId - The ID of the object.
  343. // lFlags - Not used.
  344. //
  345. //////////////////////////////////////////////////////////////////////
  346. //ok
  347. {
  348. HRESULT hResult = WBEM_NO_ERROR;
  349. if ( pRefresher == 0 )
  350. hResult = WBEM_E_INVALID_PARAMETER;
  351. if ( SUCCEEDED( hResult ) )
  352. {
  353. // The refresher being supplied by the caller is actually
  354. // one of our own refreshers, so a simple cast is convenient
  355. // so that we can access private members.
  356. // =========================================================
  357. CRefresher *pOurRefresher = (CRefresher *) pRefresher;
  358. hResult = pOurRefresher->Remove( lId );
  359. }
  360. return hResult;
  361. }
  362. STDMETHODIMP CHiPerfProvider::QueryInstances(
  363. /* [in] */ IWbemServices __RPC_FAR *pNamespace,
  364. /* [string][in] */ WCHAR __RPC_FAR *wszClass,
  365. /* [in] */ long lFlags,
  366. /* [in] */ IWbemContext __RPC_FAR *pCtx,
  367. /* [in] */ IWbemObjectSink __RPC_FAR *pSink )
  368. //////////////////////////////////////////////////////////////////////
  369. //
  370. // Called whenever a complete, fresh list of instances for a given
  371. // class is required. The objects are constructed and sent back to the
  372. // caller through the sink. The sink can be used in-line as here, or
  373. // the call can return and a separate thread could be used to deliver
  374. // the instances to the sink.
  375. //
  376. // Parameters:
  377. // pNamespace - A pointer to the relevant namespace. This
  378. // should not be AddRef'ed.
  379. // wszClass - The class name for which instances are required.
  380. // lFlags - Reserved.
  381. // pCtx - The user-supplied context (not used here).
  382. // pSink - The sink to which to deliver the objects. The objects
  383. // can be delivered synchronously through the duration
  384. // of this call or asynchronously (assuming we
  385. // had a separate thread). A IWbemObjectSink::SetStatus
  386. // call is required at the end of the sequence.
  387. //
  388. //////////////////////////////////////////////////////////////////////
  389. //ok
  390. {
  391. HRESULT hResult = WBEM_NO_ERROR;
  392. if (pNamespace == 0 || wszClass == 0 || pSink == 0)
  393. hResult = WBEM_E_INVALID_PARAMETER;
  394. // Verify hi-perf object
  395. // =====================
  396. if ( !IsHiPerf( pNamespace, wszClass ) )
  397. hResult = WBEM_E_INVALID_CLASS;
  398. if ( SUCCEEDED( hResult ) )
  399. {
  400. IWbemRefresher* pRefresher = NULL;
  401. IWbemConfigureRefresher* pConfig = NULL;
  402. IWbemHiPerfEnum* pHiPerfEnum = NULL;
  403. IWbemObjectAccess** apAccess = NULL;
  404. IWbemClassObject** apObject = NULL;
  405. hResult = CoCreateInstance( CLSID_WbemRefresher,
  406. NULL,
  407. CLSCTX_INPROC_SERVER,
  408. IID_IWbemRefresher,
  409. (void**) &pRefresher );
  410. CAutoRelease rm1(pRefresher);
  411. // Get the refresher configuration interface
  412. // =========================================
  413. if ( SUCCEEDED( hResult ) )
  414. {
  415. hResult = pRefresher->QueryInterface( IID_IWbemConfigureRefresher, (void**)&pConfig );
  416. }
  417. CAutoRelease rm2(pConfig);
  418. if ( SUCCEEDED( hResult ) )
  419. {
  420. ULONG uArraySize = 0,
  421. uObjRet = 0;
  422. long lID = 0;
  423. hResult = pConfig->AddEnum( pNamespace, wszClass, 0, pCtx, &pHiPerfEnum, &lID );
  424. CAutoRelease arHiPerfEnum( pHiPerfEnum );
  425. if ( SUCCEEDED( hResult ) )
  426. {
  427. hResult = pRefresher->Refresh( 0L );
  428. hResult = pRefresher->Refresh( 0L );
  429. }
  430. if ( SUCCEEDED( hResult ) )
  431. {
  432. hResult = pHiPerfEnum->GetObjects( 0L, 0, NULL, &uObjRet );
  433. if ( WBEM_E_BUFFER_TOO_SMALL == hResult )
  434. {
  435. uArraySize = uObjRet;
  436. wmilib::auto_buffer<IWbemObjectAccess*> apAccess( new IWbemObjectAccess*[ uObjRet ]);
  437. wmilib::auto_buffer<IWbemClassObject*> apObject(new IWbemClassObject*[ uObjRet ]);
  438. if ( (NULL != apObject.get()) && (NULL != apAccess.get()))
  439. {
  440. hResult = pHiPerfEnum->GetObjects( 0L, uArraySize, apAccess.get(), &uObjRet );
  441. for ( ULONG uIndex = 0; uIndex < uArraySize; uIndex++ )
  442. {
  443. apAccess[ uIndex ]->QueryInterface( IID_IWbemClassObject, (void**)&( apObject[uIndex] ) );
  444. apAccess[ uIndex ]->Release();
  445. }
  446. }
  447. else
  448. {
  449. hResult = WBEM_E_OUT_OF_MEMORY;
  450. }
  451. if ( SUCCEEDED( hResult ) )
  452. {
  453. hResult = pSink->Indicate( uArraySize, apObject.get() );
  454. for ( ULONG uIndex = 0; uIndex < uArraySize; uIndex++ )
  455. {
  456. apObject[ uIndex ]->Release();
  457. }
  458. }
  459. }
  460. }
  461. if ( SUCCEEDED( hResult ) )
  462. {
  463. pConfig->Remove( lID , 0 );
  464. }
  465. }
  466. }
  467. pSink->SetStatus(0, hResult, 0, 0);
  468. return hResult;
  469. }
  470. STDMETHODIMP CHiPerfProvider::GetObjects(
  471. /* [in] */ IWbemServices* pNamespace,
  472. /* [in] */ long lNumObjects,
  473. /* [in,size_is(lNumObjects)] */ IWbemObjectAccess** apObj,
  474. /* [in] */ long lFlags,
  475. /* [in] */ IWbemContext* pContext)
  476. //////////////////////////////////////////////////////////////////////
  477. //
  478. // Called when a request is made to provide all instances currently
  479. // being managed by the provider in the specified namespace.
  480. //
  481. // Parameters:
  482. // pNamespace - A pointer to the relevant namespace.
  483. // lNumObjects - The number of instances being returned.
  484. // apObj - The array of instances being returned.
  485. // lFlags - Reserved.
  486. // pContext - Not used here.
  487. //
  488. //////////////////////////////////////////////////////////////////////
  489. //ok
  490. {
  491. // Update objects
  492. // ==============
  493. IWbemRefresher* pRefresher = NULL;
  494. IWbemConfigureRefresher* pConfig = NULL;
  495. wmilib::auto_buffer<IWbemClassObject*> apRefObj(new IWbemClassObject*[lNumObjects]);
  496. if (0 == apRefObj.get())
  497. {
  498. return WBEM_E_OUT_OF_MEMORY;
  499. }
  500. // CoCreate the refresher interface
  501. // ================================
  502. HRESULT hResult = CoCreateInstance( CLSID_WbemRefresher,
  503. NULL,
  504. CLSCTX_INPROC_SERVER,
  505. IID_IWbemRefresher,
  506. (void**) &pRefresher );
  507. CAutoRelease arRefresher( pRefresher );
  508. // Get the refresher configuration interface
  509. // =========================================
  510. if ( SUCCEEDED( hResult ) )
  511. {
  512. hResult = pRefresher->QueryInterface( IID_IWbemConfigureRefresher, (void**)&pConfig );
  513. }
  514. CAutoRelease arConfig( pConfig );
  515. // Get the object data
  516. // ===================
  517. if ( SUCCEEDED( hResult ) )
  518. {
  519. long lIndex = 0,
  520. lID = 0;
  521. // Add all of the requested objects to the refresher
  522. // =================================================
  523. for ( lIndex = 0; SUCCEEDED( hResult ) && lIndex < lNumObjects; lIndex++ )
  524. {
  525. // Verify hi-perf object
  526. if ( !IsHiPerfObj( apObj[ lIndex ] ) )
  527. hResult = WBEM_E_INVALID_CLASS;
  528. #ifdef _VERBOSE
  529. {
  530. _variant_t VarPath;
  531. apObj[lIndex]->Get(L"__RELPATH",0,&VarPath,NULL,NULL);
  532. _variant_t VarName;
  533. apObj[lIndex]->Get(L"Name",0,&VarName,NULL,NULL);
  534. WCHAR pBuff[256];
  535. wsprintfW(pBuff,L"%s %s\n",V_BSTR(&VarPath),V_BSTR(&VarName));
  536. OutputDebugStringW(pBuff);
  537. }
  538. #endif
  539. if ( SUCCEEDED( hResult ) )
  540. {
  541. hResult = pConfig->AddObjectByTemplate( pNamespace,
  542. apObj[ lIndex ],
  543. 0,
  544. NULL,
  545. &(apRefObj[ lIndex ]),
  546. &lID );
  547. lID = 0;
  548. }
  549. }
  550. if ( SUCCEEDED( hResult ) )
  551. {
  552. hResult = pRefresher->Refresh( 0L );
  553. hResult = pRefresher->Refresh( 0L );
  554. }
  555. for ( lIndex = 0; SUCCEEDED( hResult ) && lIndex < lNumObjects; lIndex++ )
  556. {
  557. hResult = CopyBlob( apRefObj[lIndex], apObj[lIndex] );
  558. apRefObj[lIndex]->Release();
  559. }
  560. }
  561. return hResult;
  562. }