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.

622 lines
18 KiB

  1. /*++
  2. Copyright (C) 1997-2001 Microsoft Corporation
  3. Module Name:
  4. Abstract:
  5. History:
  6. --*/
  7. //***************************************************************************
  8. //
  9. // NTPERF.CPP
  10. //
  11. // Mapped NT5 Perf Counter Provider
  12. //
  13. // raymcc 02-Dec-97 Created.
  14. // raymcc 20-Feb-98 Updated to use new initializer.
  15. //
  16. //***************************************************************************
  17. #include "precomp.h"
  18. #include <stdio.h>
  19. #include <wbemidl.h>
  20. #include <wbemint.h>
  21. #include "flexarry.h"
  22. #include "ntperf.h"
  23. #include "oahelp.inl"
  24. #include "perfhelp.h"
  25. #include "refreshr.h"
  26. //***************************************************************************
  27. //
  28. // CNt5PerfProvider constructor
  29. //
  30. //***************************************************************************
  31. // ok
  32. CNt5PerfProvider::CNt5PerfProvider()
  33. {
  34. m_lRef = 0;
  35. }
  36. //***************************************************************************
  37. //
  38. // CNt5PerfProvider destructor
  39. //
  40. //***************************************************************************
  41. // ok
  42. CNt5PerfProvider::~CNt5PerfProvider()
  43. {
  44. for (int i = 0; i < m_aCache.Size(); i++)
  45. delete (CClassMapInfo *) m_aCache[i];
  46. RegCloseKey(HKEY_PERFORMANCE_DATA);
  47. }
  48. //***************************************************************************
  49. //
  50. // CNt5Refresher::AddRef
  51. //
  52. // Standard COM AddRef().
  53. //
  54. //***************************************************************************
  55. // ok
  56. ULONG CNt5PerfProvider::AddRef()
  57. {
  58. return InterlockedIncrement(&m_lRef);
  59. }
  60. //***************************************************************************
  61. //
  62. // CNt5Refresher::Release
  63. //
  64. // Standard COM Release().
  65. //
  66. //***************************************************************************
  67. // ok
  68. ULONG CNt5PerfProvider::Release()
  69. {
  70. long lRef = InterlockedDecrement(&m_lRef);
  71. if(lRef == 0)
  72. delete this;
  73. return lRef;
  74. }
  75. //***************************************************************************
  76. //
  77. // CNt5Refresher::QueryInterface
  78. //
  79. // Standard COM QueryInterface(). We have to support two interfaces,
  80. // the IWbemHiPerfProvider interface itself to provide the objects and
  81. // the IWbemProviderInit interface to initialize the provider.
  82. //
  83. //***************************************************************************
  84. // ok
  85. HRESULT CNt5PerfProvider::QueryInterface(REFIID riid, void** ppv)
  86. {
  87. if(riid == IID_IUnknown || riid == IID_IWbemHiPerfProvider)
  88. {
  89. *ppv = (IWbemHiPerfProvider*) this;
  90. AddRef();
  91. return S_OK;
  92. }
  93. else if (riid == IID_IWbemProviderInit)
  94. {
  95. *ppv = (IWbemProviderInit *) this;
  96. AddRef();
  97. return S_OK;
  98. }
  99. else return E_NOINTERFACE;
  100. }
  101. //***************************************************************************
  102. //
  103. // CNt5Refresher::Initialize
  104. //
  105. // Called once during startup. Indicates to the provider which
  106. // namespace it is being invoked for and which User. It also supplies
  107. // a back pointer to WINMGMT so that class definitions can be retrieved.
  108. //
  109. // We perform any one-time initialization in this routine. The
  110. // final call to Release() is for any cleanup.
  111. //
  112. // <wszUser> The current user.
  113. // <lFlags> Reserved.
  114. // <wszNamespace> The namespace for which we are being activated.
  115. // <wszLocale> The locale under which we are to be running.
  116. // <pNamespace> An active pointer back into the current namespace
  117. // from which we can retrieve schema objects.
  118. // <pCtx> The user's context object. We simply reuse this
  119. // during any reentrant operations into WINMGMT.
  120. // <pInitSink> The sink to which we indicate our readiness.
  121. //
  122. //***************************************************************************
  123. // ok
  124. HRESULT CNt5PerfProvider::Initialize(
  125. /* [unique][in] */ LPWSTR wszUser,
  126. /* [in] */ LONG lFlags,
  127. /* [in] */ LPWSTR wszNamespace,
  128. /* [unique][in] */ LPWSTR wszLocale,
  129. /* [in] */ IWbemServices __RPC_FAR *pNamespace,
  130. /* [in] */ IWbemContext __RPC_FAR *pCtx,
  131. /* [in] */ IWbemProviderInitSink __RPC_FAR *pInitSink
  132. )
  133. {
  134. pInitSink->SetStatus(0, WBEM_S_INITIALIZED);
  135. return NO_ERROR;
  136. }
  137. //***************************************************************************
  138. //
  139. // CNt5Refresher::QueryInstances
  140. //
  141. // Called whenever a complete, fresh list of instances for a given
  142. // class is required. The objects are constructed and sent back to the
  143. // caller through the sink. The sink can be used in-line as here, or
  144. // the call can return and a separate thread could be used to deliver
  145. // the instances to the sink.
  146. //
  147. // Parameters:
  148. // <pNamespace> A pointer to the relevant namespace. This
  149. // should not be AddRef'ed or retained past the
  150. // execution of this method.
  151. // <wszClass> The class name for which instances are required.
  152. // <lFlags> Reserved.
  153. // <pCtx> The user-supplied context (used during callbacks
  154. // into WINMGMT).
  155. // <pSink> The sink to which to deliver the objects. The objects
  156. // can be delivered synchronously through the duration
  157. // of this call or asynchronously (assuming we
  158. // had a separate thread). A IWbemObjectSink::SetStatus
  159. // call is required at the end of the sequence.
  160. //
  161. //***************************************************************************
  162. // ok
  163. HRESULT CNt5PerfProvider::QueryInstances(
  164. /* [in] */ IWbemServices __RPC_FAR *pNamespace,
  165. /* [string][in] */ WCHAR __RPC_FAR *wszClass,
  166. /* [in] */ long lFlags,
  167. /* [in] */ IWbemContext __RPC_FAR *pCtx,
  168. /* [in] */ IWbemObjectSink __RPC_FAR *pSink
  169. )
  170. {
  171. if (pNamespace == 0 || wszClass == 0 || pSink == 0)
  172. return WBEM_E_INVALID_PARAMETER;
  173. // Ensure the class is in our cache and mapped.
  174. // ============================================
  175. BOOL bRes = MapClass(pNamespace, wszClass, pCtx);
  176. if (bRes == FALSE)
  177. {
  178. // Class is not one of ours.
  179. return WBEM_E_INVALID_CLASS;
  180. }
  181. CClassMapInfo *pClsMap = FindClassMap(wszClass);
  182. // Refresh the instances.
  183. // ======================
  184. PerfHelper::QueryInstances(pClsMap, pSink);
  185. // Tell WINMGMT we are finished.
  186. // ===========================
  187. pSink->SetStatus(0, WBEM_NO_ERROR, 0, 0);
  188. return NO_ERROR;
  189. }
  190. //***************************************************************************
  191. //
  192. // CNt5Refresher::CreateRefresher
  193. //
  194. // Called whenever a new refresher is needed by the client.
  195. //
  196. // Parameters:
  197. // <pNamespace> A pointer to the relevant namespace. Not used.
  198. // <lFlags> Not used.
  199. // <ppRefresher> Receives the requested refresher.
  200. //
  201. //***************************************************************************
  202. // ok
  203. HRESULT CNt5PerfProvider::CreateRefresher(
  204. /* [in] */ IWbemServices __RPC_FAR *pNamespace,
  205. /* [in] */ long lFlags,
  206. /* [out] */ IWbemRefresher __RPC_FAR *__RPC_FAR *ppRefresher
  207. )
  208. {
  209. if (pNamespace == 0 || ppRefresher == 0)
  210. return WBEM_E_INVALID_PARAMETER;
  211. // Construct a new empty refresher.
  212. // ================================
  213. CNt5Refresher *pNewRefresher = new CNt5Refresher;
  214. // Follow COM rules and AddRef() the thing before sending it back.
  215. // ===============================================================
  216. pNewRefresher->AddRef();
  217. *ppRefresher = pNewRefresher;
  218. return NO_ERROR;
  219. }
  220. //***************************************************************************
  221. //
  222. // CNt5Refresher::CreateRefreshableObject
  223. //
  224. // Called whenever a user wants to include an object in a refresher.
  225. //
  226. // Parameters:
  227. // <pNamespace> A pointer to the relevant namespace in WINMGMT.
  228. // <pTemplate> A pointer to a copy of the object which is to be
  229. // added. This object itself cannot be used, as
  230. // it not owned locally.
  231. // <pRefresher> The refresher to which to add the object.
  232. // <lFlags> Not used.
  233. // <pContext> Not used here.
  234. // <ppRefreshable> A pointer to the internal object which was added
  235. // to the refresher.
  236. // <plId> The Object Id (for identification during removal).
  237. //
  238. //***************************************************************************
  239. // ok
  240. HRESULT CNt5PerfProvider::CreateRefreshableObject(
  241. /* [in] */ IWbemServices __RPC_FAR *pNamespace,
  242. /* [in] */ IWbemObjectAccess __RPC_FAR *pTemplate,
  243. /* [in] */ IWbemRefresher __RPC_FAR *pRefresher,
  244. /* [in] */ long lFlags,
  245. /* [in] */ IWbemContext __RPC_FAR *pContext,
  246. /* [out] */ IWbemObjectAccess __RPC_FAR *__RPC_FAR *ppRefreshable,
  247. /* [out] */ long __RPC_FAR *plId
  248. )
  249. {
  250. *ppRefreshable = 0;
  251. // Make a copy of the template object.
  252. // ===================================
  253. IWbemClassObject *pOriginal = 0;
  254. pTemplate->QueryInterface(IID_IWbemClassObject, (LPVOID *) &pOriginal);
  255. IWbemClassObject *pNewCopy = 0;
  256. pOriginal->Clone(&pNewCopy);
  257. // Get the class name of the object.
  258. // =================================
  259. VARIANT v;
  260. VariantInit(&v);
  261. BSTR strClassProp = SysAllocString(L"__CLASS");
  262. pOriginal->Get(strClassProp, 0, &v, 0, 0);
  263. SysFreeString(strClassProp);
  264. // We are now done with the original object
  265. // ========================================
  266. pOriginal->Release();
  267. // We now get the IWbemObjectAccess form of the cloned object
  268. // and release the unused interface.
  269. // ==========================================================
  270. IWbemObjectAccess *pNewAccess = 0;
  271. pNewCopy->QueryInterface(IID_IWbemObjectAccess, (LPVOID *) &pNewAccess);
  272. pNewCopy->Release(); // We don't need the IWbemClassObject interface any more
  273. // We now have an IWbemObjectAccess pointer for the refreshable
  274. // object in <pNewAccess>.
  275. // ============================================================
  276. CNt5Refresher *pRef = (CNt5Refresher *) pRefresher;
  277. // Map the class info for this instance.
  278. // =====================================
  279. BOOL bRes = MapClass(pNamespace, V_BSTR(&v), pContext);
  280. if (bRes == FALSE)
  281. {
  282. // Class is not one of ours.
  283. pNewAccess->Release();
  284. VariantClear(&v);
  285. return WBEM_E_INVALID_CLASS;
  286. }
  287. CClassMapInfo *pClsMap = FindClassMap(V_BSTR(&v));
  288. if (pClsMap == 0)
  289. {
  290. pNewAccess->Release();
  291. VariantClear(&v);
  292. return WBEM_E_INVALID_CLASS;
  293. }
  294. // Add the object to the refresher.
  295. // This method will AddRef() the object before returning.
  296. // ======================================================
  297. pRef->AddObject(
  298. pNewAccess,
  299. pClsMap,
  300. plId
  301. );
  302. // Return object to the user.
  303. // ==========================
  304. *ppRefreshable = pNewAccess;
  305. VariantClear(&v);
  306. return NO_ERROR;
  307. }
  308. //***************************************************************************
  309. //
  310. // CNt5Refresher::StopRefreshing
  311. //
  312. // Called whenever a user wants to remove an object from a refresher.
  313. //
  314. // Parameters:
  315. // <pRefresher> The refresher object from which we are to
  316. // remove the perf object.
  317. // <lId> The ID of the object.
  318. // <lFlags> Not used.
  319. //
  320. //***************************************************************************
  321. // ok
  322. HRESULT CNt5PerfProvider::StopRefreshing(
  323. /* [in] */ IWbemRefresher __RPC_FAR *pRefresher,
  324. /* [in] */ long lId,
  325. /* [in] */ long lFlags
  326. )
  327. {
  328. CNt5Refresher *pRef = (CNt5Refresher *) pRefresher;
  329. BOOL bRes = pRef->RemoveObject(lId);
  330. if (bRes == FALSE)
  331. return WBEM_E_FAILED;
  332. return WBEM_NO_ERROR;
  333. }
  334. //***************************************************************************
  335. //
  336. // CNt5Refresher::CreateRefreshableEnum
  337. //
  338. // Called whenever a user wants to create an enumeration in a refresher.
  339. //
  340. // Parameters:
  341. // <pNamespace> The namespace this is for
  342. // <wszClass> Name of the class we are enumerating
  343. // <pRefresher> The refresher object from which we are to
  344. // remove the perf object.
  345. // <lFlags> Not used.
  346. // <pContext> Wbem Context object
  347. // <pHiPerfEnum> Enumerator object into which refresher should place
  348. // its results
  349. // <plId> The enum id (for identification during removal)
  350. //
  351. //***************************************************************************
  352. // ok
  353. HRESULT CNt5PerfProvider::CreateRefreshableEnum(
  354. /* [in] */ IWbemServices* pNamespace,
  355. /* [in, string] */ LPCWSTR wszClass,
  356. /* [in] */ IWbemRefresher* pRefresher,
  357. /* [in] */ long lFlags,
  358. /* [in] */ IWbemContext* pContext,
  359. /* [in] */ IWbemHiPerfEnum* pHiPerfEnum,
  360. /* [out] */ long* plId )
  361. {
  362. // Just a placeholder for now
  363. return E_NOTIMPL;
  364. }
  365. //***************************************************************************
  366. //
  367. // CNt5Refresher::GetObjects
  368. //
  369. // Called whenever a user wants to create an enumeration in a refresher.
  370. //
  371. // Parameters:
  372. // <pNamespace> The namespace this is for
  373. // <lNumObjects> Number of objects in the array
  374. // <apObj> Objects to retrieve (keys are set)
  375. // <lFlags> Not used.
  376. // <pContext> Wbem Context object
  377. // <pHiPerfEnum> Enumerator object into which refresher should place
  378. // its results
  379. // <plId> The enum id (for identification during removal)
  380. //
  381. //***************************************************************************
  382. // ok
  383. HRESULT CNt5PerfProvider::GetObjects(
  384. /* [in] */ IWbemServices* pNamespace,
  385. /* [in] */ long lNumObjects,
  386. /* [in,size_is(lNumObjects)] */ IWbemObjectAccess** apObj,
  387. /* [in] */ long lFlags,
  388. /* [in] */ IWbemContext* pContext)
  389. {
  390. // Just a placeholder for now
  391. return E_NOTIMPL;
  392. }
  393. //***************************************************************************
  394. //
  395. // CNt5Refresher::MapClass
  396. //
  397. // Adds the class map to an internal cache.
  398. //
  399. // <pClsMap> The pointer to the map info to add. This pointer
  400. // is acquired by this function and should not be
  401. // deleted by the caller.
  402. //
  403. //***************************************************************************
  404. // ok
  405. void CNt5PerfProvider::AddClassMap(
  406. IN CClassMapInfo *pClsMap
  407. )
  408. {
  409. for (int i = 0; i < m_aCache.Size(); i++)
  410. {
  411. CClassMapInfo *pTracer = (CClassMapInfo *) m_aCache[i];
  412. if (_wcsicmp(pClsMap->m_pszClassName, pTracer->m_pszClassName) < 0)
  413. {
  414. m_aCache.InsertAt(i, pClsMap);
  415. return;
  416. }
  417. }
  418. // If here, add it to the end.
  419. // ===========================
  420. m_aCache.Add(pClsMap);
  421. }
  422. //***************************************************************************
  423. //
  424. // CNt5Refresher::FindClassMap
  425. //
  426. //***************************************************************************
  427. // ok
  428. CClassMapInfo *CNt5PerfProvider::FindClassMap(
  429. LPWSTR pszClassName
  430. )
  431. {
  432. // Binary search the cache.
  433. // ========================
  434. int l = 0, u = m_aCache.Size() - 1;
  435. while (l <= u)
  436. {
  437. int m = (l + u) / 2;
  438. CClassMapInfo *pClsMap = (CClassMapInfo *) m_aCache[m];
  439. if (_wcsicmp(pszClassName, pClsMap->m_pszClassName) < 0)
  440. u = m - 1;
  441. else if (_wcsicmp(pszClassName, pClsMap->m_pszClassName) > 0)
  442. l = m + 1;
  443. else // Hit!
  444. return pClsMap;
  445. }
  446. return NULL;
  447. }
  448. //***************************************************************************
  449. //
  450. // CNt5Refresher::MapClass
  451. //
  452. // Retrieves the requested class and places it in the cache.
  453. //
  454. // Parameters:
  455. // pNs The namespace which contains the class definition.
  456. // wsClass The class name.
  457. // pCtx The inbound context object. Only used for reentrant
  458. // calls.
  459. //
  460. //***************************************************************************
  461. // ok
  462. BOOL CNt5PerfProvider::MapClass(
  463. IN IWbemServices *pNs,
  464. IN WCHAR *wszClass,
  465. IN IWbemContext *pCtx
  466. )
  467. {
  468. HRESULT hRes = 0;
  469. // See if the class is already in the cache.
  470. // =========================================
  471. if (FindClassMap(wszClass) != 0)
  472. return TRUE;
  473. // Get the class definition from WINMGMT.
  474. // ====================================
  475. IWbemClassObject *pClsDef = 0;
  476. hRes = pNs->GetObject(CBSTR(wszClass), 0, pCtx, &pClsDef, 0);
  477. if (hRes)
  478. {
  479. // Unable to retrieve the class definition
  480. return FALSE;
  481. }
  482. // Verify the class is one of ours by checking
  483. // the "provider" qualifier to ensure it matches
  484. // the name that we we have for this component.
  485. // =============================================
  486. IWbemQualifierSet *pQSet = 0;
  487. hRes = pClsDef->GetQualifierSet(&pQSet);
  488. if (hRes)
  489. {
  490. pClsDef->Release();
  491. return FALSE;
  492. }
  493. VARIANT v;
  494. VariantInit(&v);
  495. pQSet->Get(CBSTR(L"Provider"), 0, &v, 0);
  496. pQSet->Release();
  497. if (_wcsicmp(V_BSTR(&v), PROVIDER_NAME) != 0)
  498. {
  499. pClsDef->Release();
  500. return FALSE;
  501. }
  502. // Get the property handles and mappings to the perf counter ids
  503. // by calling the Map() method of CClassMapInfo.
  504. // ==============================================================
  505. CClassMapInfo *pMapInfo = new CClassMapInfo;
  506. if (pMapInfo->Map(pClsDef) == FALSE)
  507. {
  508. delete pMapInfo;
  509. pClsDef->Release();
  510. return FALSE;
  511. }
  512. // Add it to the cache.
  513. // ====================
  514. AddClassMap(pMapInfo);
  515. return TRUE;
  516. }