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.

1716 lines
40 KiB

  1. /*
  2. - perfdll.cpp
  3. -
  4. * Purpose:
  5. * Provide mechanism for user configuring of Perfmon Counters
  6. * Implement Open, Collect and Close for Perfmon DLL Extension
  7. *
  8. */
  9. #include <windows.h>
  10. #include <winperf.h>
  11. #include <winerror.h>
  12. #include <Pop3RegKeys.h>
  13. #include <perfUtil.h>
  14. #include <perfdll.h>
  15. #include <loadperf.h> // for unlodctr
  16. #include <shlwapi.h> // for SHDeleteKey
  17. #include <string>
  18. #include <cstring>
  19. // ----------------------------------------------------------------------
  20. // Declarations & Typedefs
  21. // ----------------------------------------------------------------------
  22. //
  23. // Performance Counter Data Structures
  24. typedef struct _perfdata
  25. {
  26. PERF_OBJECT_TYPE potGlobal;
  27. PERF_COUNTER_DEFINITION * rgCntrDef;
  28. PERF_COUNTER_BLOCK CntrBlk;
  29. } PERFDATA;
  30. typedef struct _instdata
  31. {
  32. PERF_INSTANCE_DEFINITION InstDef;
  33. WCHAR szInstName[MAX_PATH];
  34. PERF_COUNTER_BLOCK CntrBlk;
  35. } INSTDATA;
  36. typedef struct _perfinst
  37. {
  38. PERF_OBJECT_TYPE potInst;
  39. PERF_COUNTER_DEFINITION * rgCntrDef;
  40. } PERFINST;
  41. //
  42. // Constants and other stuff required by PerfMon
  43. static WCHAR szGlobal[] = L"Global";
  44. static WCHAR szForeign[] = L"Foreign";
  45. static WCHAR szCostly[] = L"Costly";
  46. static WCHAR szNull[] = L"\0";
  47. #define DIGIT 1
  48. #define DELIMITER 2
  49. #define INVALID 3
  50. #define QUERY_GLOBAL 1
  51. #define QUERY_ITEMS 2
  52. #define QUERY_FOREIGN 3
  53. #define QUERY_COSTLY 4
  54. static DWORD GetQueryType(LPWSTR lpValue);
  55. static BOOL IsNumberInUnicodeList(DWORD dwNumber, LPWSTR pszUnicodeList);
  56. #define EvalThisChar(c,d) ( \
  57. (c == d) ? DELIMITER : \
  58. (c == 0) ? DELIMITER : \
  59. (c < (WCHAR)'0') ? INVALID : \
  60. (c > (WCHAR)'9') ? INVALID : \
  61. DIGIT)
  62. // Perfmon likes things to be aligned on 8 byte boundaries
  63. #define ROUND_TO_8_BYTE(x) (((x)+7) & (~7))
  64. // PerfMon counter layout required for CollectData calls
  65. static PERFDATA g_perfdata;
  66. static PERFINST g_perfinst;
  67. static INSTDATA g_instdata;
  68. // perf data as layed out in shared memory
  69. // Global Counters
  70. static HANDLE g_hsmGlobalCntr = NULL;
  71. static DWORD * g_rgdwGlobalCntr = NULL;
  72. // Instance Counters
  73. static HANDLE g_hsmInstAdm = NULL;
  74. static HANDLE g_hsmInstCntr = NULL;
  75. static INSTCNTR_DATA * g_pic = NULL;
  76. static INSTREC * g_rgInstRec = NULL;
  77. static DWORD * g_rgdwInstCntr = NULL;
  78. // Accounting and protection stuff
  79. static DWORD g_cRef = 0;
  80. static HANDLE g_hmtxInst = NULL;
  81. static BOOL g_fInit = FALSE;
  82. // Parameter Info
  83. static PERF_DATA_INFO g_PDI;
  84. static BOOL g_fInitCalled = FALSE;
  85. //Max instance to be 128
  86. static const DWORD g_cMaxInst = 128;
  87. // Function prototypes from winperf.h
  88. PM_OPEN_PROC OpenPerformanceData;
  89. PM_COLLECT_PROC CollectPerformanceData;
  90. PM_CLOSE_PROC ClosePerformanceData;
  91. // Helper functions
  92. static HRESULT HrLogEvent(HANDLE hEventLog, WORD wType, DWORD msgid);
  93. static HRESULT HrOpenSharedMemoryBlocks(HANDLE hEventLog, SECURITY_ATTRIBUTES * psa);
  94. static HRESULT HrGetCounterIDsFromReg(HANDLE hEventLog, DWORD * pdwFirstCntr, DWORD * pdwFirstHelp);
  95. static HRESULT HrAllocPerfCounterMem(HANDLE hEventLog);
  96. static HRESULT HrFreePerfCounterMem(void);
  97. // ----------------------------------------------------------------------
  98. // Implementation
  99. // ----------------------------------------------------------------------
  100. // Register constants
  101. static wchar_t szServiceRegKeyPrefix[] = L"SYSTEM\\CurrentControlSet\\Services\\" ;
  102. static wchar_t szServiceRegKeySuffix[] = L"\\Performance" ;
  103. static wchar_t szEventLogRegKeyPrefix[] = L"System\\CurrentControlSet\\Services\\EventLog\\Application\\" ;
  104. // ----------------------------------------------------------------------
  105. // RegisterPerfDll -
  106. // Create the registry keys we need.
  107. // ----------------------------------------------------------------------
  108. HRESULT RegisterPerfDll(LPCWSTR szService,
  109. LPCWSTR szOpenFnName,
  110. LPCWSTR szCollectFnName,
  111. LPCWSTR szCloseFnName)
  112. {
  113. HRESULT hr = S_OK;
  114. wchar_t szFileName[_MAX_PATH+1] ;
  115. DWORD dwRet;
  116. // Use WIN32 API's to get the path to the module name
  117. // DEVNOTE - JMW - Since we need to make sure we have the instance handle of the DLL
  118. // and not the executable, we will use VirtualQuery.
  119. MEMORY_BASIC_INFORMATION mbi;
  120. VirtualQuery(RegisterPerfDll, &mbi, sizeof(mbi));
  121. dwRet = GetModuleFileName( reinterpret_cast<HINSTANCE>(mbi.AllocationBase), szFileName, sizeof(szFileName)/sizeof(wchar_t) -1) ;
  122. if (dwRet == 0)
  123. {
  124. goto Failed;
  125. }
  126. szFileName[_MAX_PATH]=0;
  127. wchar_t szDrive[_MAX_DRIVE] ;
  128. wchar_t szDir[_MAX_DIR ] ;
  129. wchar_t szPerfFilename[ _MAX_FNAME ] ;
  130. wchar_t szExt[_MAX_EXT ] ;
  131. _wsplitpath( szFileName, szDrive, szDir, szPerfFilename, szExt ) ;
  132. // Now that I have split it, put it back together with the Pop3Perf.dll in
  133. // place of my module name
  134. _wmakepath( szFileName, szDrive, szDir, L"Pop3Perf", L".dll" ) ;
  135. hr = RegisterPerfDllEx(szService,
  136. szPerfFilename,
  137. szFileName,
  138. szOpenFnName,
  139. szCollectFnName,
  140. szCloseFnName );
  141. Cleanup:
  142. return hr;
  143. Failed:
  144. if (!FAILED(hr))
  145. {
  146. hr = GetLastError();
  147. }
  148. goto Cleanup;
  149. }
  150. // ----------------------------------------------------------------------
  151. // RegisterPerfDllEx -
  152. // Create the registry keys we need, checking to see if they're already
  153. // there.
  154. //
  155. // Parameters:
  156. // szService Service Name
  157. // szOpenFnName Name of the "Open" function
  158. // szCollectFnName " " " "Collect" "
  159. // szCloseFnName " " " "Close" "
  160. //
  161. // Returns:
  162. // S_OK
  163. // E_INVALIDARG
  164. // ERROR_ALREADY_EXISTS
  165. // <downstream error>
  166. // ----------------------------------------------------------------------
  167. HRESULT RegisterPerfDllEx(
  168. IN LPCWSTR szService,
  169. IN LPCWSTR szPerfSvc,
  170. IN LPCWSTR szPerfMsgFile,
  171. IN LPCWSTR szOpenFnName,
  172. IN LPCWSTR szCollectFnName,
  173. IN LPCWSTR szCloseFnName )
  174. {
  175. HRESULT hr = S_OK;
  176. wchar_t szFileName[_MAX_PATH+1] ;
  177. DWORD cbExistingPath = (_MAX_PATH+1);
  178. wchar_t szExistingPath[_MAX_PATH+1];
  179. std::wstring wszRegKey ;
  180. DWORD dwRet;
  181. // Verify all the args and do the correct thing if they are NULL or zero length
  182. if ( !szService ||
  183. !szPerfSvc ||
  184. !szOpenFnName ||
  185. !szCollectFnName ||
  186. !szCloseFnName )
  187. {
  188. hr = E_INVALIDARG ;
  189. goto Cleanup;
  190. }
  191. if ( !szService[0] ||
  192. !szPerfSvc[0] ||
  193. !szOpenFnName[0] ||
  194. !szCollectFnName[0] ||
  195. !szCloseFnName[0] )
  196. {
  197. hr = E_INVALIDARG ;
  198. goto Cleanup;
  199. }
  200. // Use WIN32 API's to get the path to the module name
  201. // NOTE: We will assume that this DLL is also the EventMessageFile.
  202. MEMORY_BASIC_INFORMATION mbi;
  203. VirtualQuery(RegisterPerfDllEx, &mbi, sizeof(mbi));
  204. dwRet = GetModuleFileName( reinterpret_cast<HINSTANCE>(mbi.AllocationBase), szFileName, sizeof(szFileName)/sizeof(wchar_t)-1) ;
  205. if (dwRet == 0)
  206. {
  207. // Wow, don't know what happened,
  208. goto Failed;
  209. }
  210. szFileName[_MAX_PATH]=0;
  211. // If the user passed in NULL for the Event Log Message File for this Perfmon DLL,
  212. // use this DLL as the Event Log Message File.
  213. if (!szPerfMsgFile)
  214. {
  215. szPerfMsgFile = szFileName;
  216. }
  217. // Register the perfmon counter DLL under the
  218. // provided service.
  219. wszRegKey = szServiceRegKeyPrefix ;
  220. wszRegKey += szService ;
  221. wszRegKey += szServiceRegKeySuffix ;
  222. // Check to see if the library has already been registered.
  223. if (ERROR_SUCCESS==RegQueryString(
  224. wszRegKey.c_str(),
  225. L"Library",
  226. szExistingPath,
  227. &cbExistingPath ))
  228. {
  229. if (_wcsicmp(szExistingPath, szFileName))
  230. {
  231. // EventLog
  232. // "RegisterPerfDllEx: Error: Attempt to replace Perfmon Library %s with %s. Failing. \n",
  233. // szExistingPath,
  234. // szFileName);
  235. hr = E_FAIL;
  236. goto Cleanup;
  237. }
  238. //Otherwise, the dll is already registered!
  239. }
  240. // Continue registering
  241. if (ERROR_SUCCESS!=RegSetString(
  242. wszRegKey.c_str(),
  243. L"Library",
  244. (LPWSTR)szFileName ))
  245. {
  246. goto Failed;
  247. }
  248. if (ERROR_SUCCESS!=RegSetString(
  249. wszRegKey.c_str(),
  250. L"Open",
  251. (LPWSTR)szOpenFnName) )
  252. {
  253. goto Failed;
  254. }
  255. if (ERROR_SUCCESS!=RegSetString(
  256. wszRegKey.c_str(),
  257. L"Collect",
  258. (LPWSTR)szCollectFnName) )
  259. {
  260. goto Failed;
  261. }
  262. if (ERROR_SUCCESS!=RegSetString(
  263. wszRegKey.c_str(),
  264. L"Close",
  265. (LPWSTR)szCloseFnName) )
  266. {
  267. goto Failed;
  268. }
  269. // Set up the Event Message File
  270. wszRegKey = szEventLogRegKeyPrefix ;
  271. wszRegKey += szPerfSvc ;
  272. // See if the EventMessageFile value is already set for this service
  273. if (ERROR_SUCCESS==RegQueryString(
  274. wszRegKey.c_str(),
  275. L"EventMessageFile",
  276. szExistingPath,
  277. &cbExistingPath ))
  278. {
  279. if (_wcsicmp(szExistingPath, szPerfMsgFile))
  280. {
  281. hr = E_FAIL;
  282. goto Cleanup;
  283. }
  284. }
  285. // Set the EventMessageFile value
  286. if ( ERROR_SUCCESS!=RegSetString(
  287. wszRegKey.c_str(),
  288. L"EventMessageFile",
  289. (LPWSTR)szPerfMsgFile ) )
  290. {
  291. goto Failed;
  292. }
  293. if (ERROR_SUCCESS!=RegSetDWORD(
  294. wszRegKey.c_str(),
  295. L"TypesSupported",
  296. 0x07) ) // Error + Waring + Informational == 0x07
  297. {
  298. goto Failed;
  299. }
  300. // Assume that the CategoryMessageFile is the same as
  301. // the EventMessageFile.
  302. if (ERROR_SUCCESS!=RegSetString(
  303. wszRegKey.c_str(),
  304. L"CategoryMessageFile",
  305. (LPWSTR)szPerfMsgFile ) )
  306. {
  307. goto Failed;
  308. }
  309. // NOTE: since we don't know what the count of categories is for the
  310. // NOTE: CategoryMessageFile, do not set the CategoryCount value.
  311. Cleanup:
  312. if (FAILED(hr))
  313. {
  314. //EventLog ?? (L"RegisterPerfDllEx: Failed : (0x%08X)\n", hr);
  315. }
  316. return hr;
  317. Failed:
  318. if (!FAILED(hr))
  319. {
  320. hr = GetLastError();
  321. }
  322. goto Cleanup;
  323. }
  324. /*
  325. - HrInitPerf
  326. -
  327. * Purpose:
  328. * Init data structure used to parameterize perfmon dll. Must be called
  329. * in DllMain for reason DLL_PROCESS_ATTACH.
  330. */
  331. HRESULT
  332. HrInitPerf(PERF_DATA_INFO * pPDI)
  333. {
  334. HRESULT hr = S_OK;
  335. if (!pPDI)
  336. return E_INVALIDARG;
  337. if (g_fInitCalled)
  338. {
  339. return S_OK;
  340. }
  341. CopyMemory(&g_PDI, pPDI, sizeof(PERF_DATA_INFO));
  342. // Find the Service Name for using Event Logging on this Perfmon DLL
  343. if (!(pPDI->wszPerfSvcName[0]))
  344. {
  345. wchar_t szFileName[_MAX_PATH+1] ;
  346. DWORD dwRet;
  347. // Use WIN32 API's to get the path to the module name
  348. // DEVNOTE - JMW - Since we need to make sure we have the instance handle of the DLL
  349. // and not the executable, we will use VirtualQuery.
  350. MEMORY_BASIC_INFORMATION mbi;
  351. VirtualQuery(HrInitPerf, &mbi, sizeof(mbi));
  352. dwRet = GetModuleFileName( reinterpret_cast<HINSTANCE>(mbi.AllocationBase), szFileName, sizeof(szFileName)/sizeof(wchar_t)) ;
  353. if (dwRet == 0)
  354. {
  355. // Wow, don't know what happened
  356. goto err;
  357. }
  358. wchar_t szDrive[_MAX_DRIVE] ;
  359. wchar_t szDir[_MAX_DIR ] ;
  360. wchar_t szPerfFilename[ _MAX_FNAME ] ;
  361. wchar_t szExt[_MAX_EXT ] ;
  362. _wsplitpath( szFileName, szDrive, szDir, szPerfFilename, szExt ) ;
  363. wcscpy(g_PDI.wszPerfSvcName, szPerfFilename);
  364. }
  365. // Safety: Need to alloc our own CounterTypes arrays
  366. g_PDI.rgdwGlobalCounterTypes = NULL;
  367. g_PDI.rgdwInstCounterTypes = NULL;
  368. DWORD cb;
  369. // Alloc & Copy Global Counter Types
  370. if (g_PDI.cGlobalCounters)
  371. {
  372. cb = sizeof(DWORD) * g_PDI.cGlobalCounters;
  373. g_PDI.rgdwGlobalCounterTypes = (DWORD *) malloc(cb);
  374. if(NULL == g_PDI.rgdwGlobalCounterTypes)
  375. {
  376. hr=E_OUTOFMEMORY;
  377. goto err;
  378. }
  379. CopyMemory(g_PDI.rgdwGlobalCounterTypes,
  380. pPDI->rgdwGlobalCounterTypes,
  381. cb);
  382. g_PDI.rgdwGlobalCntrScale = (DWORD *) malloc(cb);
  383. if(NULL == g_PDI.rgdwGlobalCntrScale)
  384. {
  385. hr=E_OUTOFMEMORY;
  386. goto err;
  387. }
  388. CopyMemory(g_PDI.rgdwGlobalCntrScale,
  389. pPDI->rgdwGlobalCntrScale,
  390. cb);
  391. }
  392. // Alloc & Copy Inst Counter Types
  393. if (g_PDI.cInstCounters)
  394. {
  395. cb = sizeof(DWORD) * g_PDI.cInstCounters;
  396. g_PDI.rgdwInstCounterTypes = (DWORD *) malloc(cb);
  397. if(NULL == g_PDI.rgdwInstCounterTypes)
  398. {
  399. hr=E_OUTOFMEMORY;
  400. goto err;
  401. }
  402. CopyMemory(g_PDI.rgdwInstCounterTypes,
  403. pPDI->rgdwInstCounterTypes,
  404. cb);
  405. }
  406. // Done!
  407. g_fInitCalled = TRUE;
  408. return S_OK;
  409. err:
  410. if (g_PDI.rgdwGlobalCounterTypes)
  411. {
  412. free(g_PDI.rgdwGlobalCounterTypes);
  413. g_PDI.rgdwGlobalCounterTypes=NULL;
  414. }
  415. if (g_PDI.rgdwGlobalCntrScale)
  416. {
  417. free(g_PDI.rgdwGlobalCntrScale);
  418. g_PDI.rgdwGlobalCntrScale=NULL;
  419. }
  420. if (g_PDI.rgdwInstCounterTypes)
  421. {
  422. free(g_PDI.rgdwInstCounterTypes);
  423. g_PDI.rgdwInstCounterTypes=NULL;
  424. }
  425. return hr;
  426. }
  427. /*
  428. - HrShutdownPerf
  429. -
  430. * Purpose:
  431. * Release memory blocks allocated in HrInitPerf
  432. *
  433. */
  434. HRESULT HrShutdownPerf(void)
  435. {
  436. HRESULT hr = S_OK;
  437. if (g_cRef)
  438. {
  439. //EventLog ??(L"Warning: PERFDLL is being shut down with non-zero refcount!");
  440. hr = E_UNEXPECTED;
  441. }
  442. if (g_fInitCalled)
  443. {
  444. // We must invalidate the DLL if we release the memory in the g_PDI
  445. g_fInitCalled = FALSE;
  446. if (g_PDI.rgdwGlobalCounterTypes)
  447. {
  448. free(g_PDI.rgdwGlobalCounterTypes);
  449. g_PDI.rgdwGlobalCounterTypes=NULL;
  450. }
  451. if (g_PDI.rgdwGlobalCntrScale)
  452. {
  453. free(g_PDI.rgdwGlobalCntrScale);
  454. g_PDI.rgdwGlobalCntrScale=NULL;
  455. }
  456. if (g_PDI.rgdwInstCounterTypes)
  457. {
  458. free(g_PDI.rgdwInstCounterTypes);
  459. g_PDI.rgdwInstCounterTypes=NULL;
  460. }
  461. }
  462. return hr;
  463. }
  464. /*
  465. - OpenPerformanceData
  466. -
  467. * Purpose:
  468. * Called by PerfMon to init the counters and this DLL.
  469. *
  470. * Parameters:
  471. * pszDeviceNames Ignored.
  472. *
  473. * Errors:
  474. * dwStat Indicates various errors that can occur during init
  475. */
  476. DWORD
  477. APIENTRY
  478. OpenPerformanceData(LPWSTR pszDeviceNames)
  479. {
  480. DWORD dwStat = ERROR_SUCCESS;
  481. HANDLE hEventLog = NULL;
  482. BOOL fInMutex = FALSE;
  483. DWORD * rgdw;
  484. SECURITY_ATTRIBUTES sa;
  485. sa.lpSecurityDescriptor=NULL;
  486. if (!g_fInitCalled)
  487. return E_FAIL;
  488. // REVIEW: Assumes Open will be single-threaded. Verify?
  489. if (g_cRef == 0)
  490. {
  491. DWORD idx;
  492. DWORD dwFirstCntr;
  493. DWORD dwFirstHelp;
  494. HRESULT hr = NOERROR;
  495. // PERF_DATA_INFO wszSvcName is mandatory.
  496. hEventLog = RegisterEventSource(NULL, g_PDI.wszPerfSvcName);
  497. hr = HrInitializeSecurityAttribute(&sa);
  498. if (FAILED(hr))
  499. {
  500. //HrLogEvent(hEventLog, EVENTLOG_ERROR_TYPE, msgidCntrInitSA);
  501. dwStat = (DWORD)hr;
  502. goto err;
  503. }
  504. if (g_PDI.cInstCounters)
  505. {
  506. // Create Controling Mutex
  507. hr = HrCreatePerfMutex(&sa,
  508. g_PDI.wszInstMutexName,
  509. &g_hmtxInst);
  510. if (FAILED(hr))
  511. {
  512. //HrLogEvent(hEventLog, EVENTLOG_ERROR_TYPE, msgidCntrInitSA);
  513. dwStat = (DWORD)hr;
  514. goto err;
  515. }
  516. fInMutex = TRUE;
  517. }
  518. // Open shared memory blocks
  519. dwStat = (DWORD) HrOpenSharedMemoryBlocks(hEventLog, &sa);
  520. if (FAILED(dwStat))
  521. goto err;
  522. // Allocate PERF_COUNTER_DEFINITION arrays for both g_perfdata
  523. dwStat = (DWORD) HrAllocPerfCounterMem(hEventLog);
  524. if (FAILED(dwStat))
  525. goto err;
  526. // Get First Counter and First Help string offsets from Registry
  527. dwStat = (DWORD) HrGetCounterIDsFromReg(hEventLog,
  528. &dwFirstCntr,
  529. &dwFirstHelp);
  530. if (FAILED(dwStat))
  531. goto err;
  532. //
  533. // Fill in PerfMon structures to make Collect() faster
  534. // Global Counters
  535. if (g_PDI.cGlobalCounters)
  536. {
  537. PERF_COUNTER_DEFINITION * ppcd;
  538. DWORD cb;
  539. PERF_OBJECT_TYPE * ppot = &g_perfdata.potGlobal;
  540. cb = sizeof(PERF_OBJECT_TYPE) +
  541. (sizeof(PERF_COUNTER_DEFINITION) * g_PDI.cGlobalCounters) +
  542. sizeof(PERF_COUNTER_BLOCK) +
  543. (sizeof(DWORD) * g_PDI.cGlobalCounters);
  544. ppot->TotalByteLength = ROUND_TO_8_BYTE(cb);
  545. ppot->DefinitionLength = sizeof(PERF_OBJECT_TYPE) +
  546. (g_PDI.cGlobalCounters * sizeof(PERF_COUNTER_DEFINITION));
  547. ppot->HeaderLength = sizeof(PERF_OBJECT_TYPE);
  548. ppot->ObjectNameTitleIndex = dwFirstCntr;
  549. ppot->ObjectNameTitle = NULL;
  550. ppot->ObjectHelpTitleIndex = dwFirstHelp;
  551. ppot->ObjectHelpTitle = NULL;
  552. ppot->DetailLevel = PERF_DETAIL_NOVICE;
  553. ppot->NumCounters = g_PDI.cGlobalCounters;
  554. ppot->DefaultCounter = -1;
  555. ppot->NumInstances = PERF_NO_INSTANCES;
  556. ppot->CodePage = 0;
  557. dwFirstCntr += 2;
  558. dwFirstHelp += 2;
  559. rgdw = g_PDI.rgdwGlobalCounterTypes;
  560. for (ppcd = g_perfdata.rgCntrDef, idx = 0;
  561. idx < g_PDI.cGlobalCounters; ppcd++, idx++)
  562. {
  563. ppcd->ByteLength = sizeof(PERF_COUNTER_DEFINITION);
  564. ppcd->CounterNameTitleIndex = dwFirstCntr;
  565. ppcd->CounterNameTitle = NULL;
  566. ppcd->CounterHelpTitleIndex = dwFirstHelp;
  567. ppcd->CounterHelpTitle = NULL;
  568. ppcd->DefaultScale = g_PDI.rgdwGlobalCntrScale[idx];
  569. ppcd->DetailLevel = PERF_DETAIL_NOVICE;
  570. ppcd->CounterType = g_PDI.rgdwGlobalCounterTypes[idx];
  571. ppcd->CounterSize = sizeof(DWORD);
  572. ppcd->CounterOffset = sizeof(PERF_COUNTER_BLOCK) +
  573. (idx * sizeof(DWORD));
  574. dwFirstCntr += 2;
  575. dwFirstHelp += 2;
  576. }
  577. // Last step: set the size of the counter block and data for this object
  578. g_perfdata.CntrBlk.ByteLength = sizeof(PERF_COUNTER_BLOCK) +
  579. (g_PDI.cGlobalCounters * sizeof(DWORD));
  580. } // Global Counters
  581. // Instance Counters
  582. if (g_PDI.cInstCounters)
  583. {
  584. PERF_COUNTER_DEFINITION * ppcd;
  585. PERF_OBJECT_TYPE * ppot = &g_perfinst.potInst;
  586. // TotalByteLength will be overridden on each call to CollectPerfData().
  587. ppot->DefinitionLength = sizeof(PERF_OBJECT_TYPE) +
  588. (g_PDI.cInstCounters * sizeof(PERF_COUNTER_DEFINITION));
  589. ppot->HeaderLength = sizeof(PERF_OBJECT_TYPE);
  590. ppot->ObjectNameTitleIndex = dwFirstCntr;
  591. ppot->ObjectNameTitle = NULL;
  592. ppot->ObjectHelpTitleIndex = dwFirstHelp;
  593. ppot->ObjectHelpTitle = NULL;
  594. ppot->DetailLevel = PERF_DETAIL_NOVICE;
  595. ppot->NumCounters = g_PDI.cInstCounters;
  596. ppot->DefaultCounter = -1;
  597. ppot->NumInstances = 0;
  598. ppot->CodePage = 0;
  599. dwFirstCntr += 2;
  600. dwFirstHelp += 2;
  601. for (ppcd = g_perfinst.rgCntrDef, idx = 0;
  602. idx < g_PDI.cInstCounters; ppcd++, idx++)
  603. {
  604. ppcd->ByteLength = sizeof(PERF_COUNTER_DEFINITION);
  605. ppcd->CounterNameTitleIndex = dwFirstCntr;
  606. ppcd->CounterNameTitle = NULL;
  607. ppcd->CounterHelpTitleIndex = dwFirstHelp;
  608. ppcd->CounterHelpTitle = NULL;
  609. ppcd->DefaultScale = 0;
  610. ppcd->DetailLevel = PERF_DETAIL_NOVICE;
  611. ppcd->CounterType = g_PDI.rgdwInstCounterTypes[idx];
  612. ppcd->CounterSize = sizeof(DWORD);
  613. ppcd->CounterOffset = sizeof(PERF_COUNTER_BLOCK) +
  614. (idx * sizeof(DWORD));
  615. dwFirstCntr += 2;
  616. dwFirstHelp += 2;
  617. }
  618. // Initialize generic INSTDATA for future use
  619. g_instdata.InstDef.ByteLength = sizeof(PERF_INSTANCE_DEFINITION) +
  620. (MAX_PATH * sizeof(WCHAR)) ;
  621. g_instdata.InstDef.ParentObjectTitleIndex = 0; // No parent object
  622. g_instdata.InstDef.ParentObjectInstance = 0;
  623. g_instdata.InstDef.UniqueID = PERF_NO_UNIQUE_ID;
  624. g_instdata.InstDef.NameOffset = sizeof(PERF_INSTANCE_DEFINITION);
  625. g_instdata.InstDef.NameLength = 0; // To be overriden in Collect
  626. g_instdata.CntrBlk.ByteLength = (sizeof(PERF_COUNTER_BLOCK) +
  627. (g_PDI.cInstCounters * sizeof(DWORD)));
  628. } // Instance Counters
  629. // Done! Ready for business....
  630. g_fInit = TRUE;
  631. }
  632. // If we got here, we're okay!
  633. dwStat = ERROR_SUCCESS;
  634. g_cRef++;
  635. ret:
  636. if (fInMutex)
  637. ReleaseMutex(g_hmtxInst);
  638. if (hEventLog)
  639. DeregisterEventSource(hEventLog);
  640. if (sa.lpSecurityDescriptor)
  641. LocalFree(sa.lpSecurityDescriptor);
  642. return dwStat;
  643. err:
  644. if (g_hsmGlobalCntr)
  645. {
  646. UnmapViewOfFile(g_rgdwGlobalCntr);
  647. CloseHandle(g_hsmGlobalCntr);
  648. }
  649. if (g_hsmInstAdm)
  650. {
  651. UnmapViewOfFile(g_pic);
  652. CloseHandle(g_hsmInstAdm);
  653. }
  654. if (g_hsmInstCntr)
  655. {
  656. UnmapViewOfFile(g_rgdwInstCntr);
  657. CloseHandle(g_hsmInstCntr);
  658. }
  659. if (g_hmtxInst)
  660. CloseHandle(g_hmtxInst);
  661. // TODO: release all that memory we Alloc'd
  662. HrFreePerfCounterMem();
  663. goto ret;
  664. }
  665. /*
  666. - CollectPerformanceData
  667. -
  668. * Purpose:
  669. * Called by PerfMon to collect performance counter data
  670. *
  671. * Parameters:
  672. * pszValueName
  673. * ppvData
  674. * pcbTotal
  675. * pcObjTypes
  676. *
  677. * Errors:
  678. * ERROR_SUCCESS
  679. * ERROR_MORE_DATA
  680. */
  681. DWORD
  682. APIENTRY
  683. CollectPerformanceData(
  684. LPWSTR pszValueName,
  685. LPVOID *ppvData,
  686. LPDWORD pcbTotal,
  687. LPDWORD pcObjTypes)
  688. {
  689. BOOL fCollectGlobalData;
  690. BOOL fCollectInstData;
  691. DWORD dwQueryType;
  692. ULONG cbBuff = *pcbTotal;
  693. char * pcT;
  694. // In case we have to bail out
  695. *pcbTotal = 0;
  696. *pcObjTypes = 0;
  697. if (!g_fInit)
  698. return ERROR_SUCCESS;
  699. // Determine Query Type; we only support QUERY_ITEMS
  700. dwQueryType = GetQueryType(pszValueName);
  701. if (dwQueryType == QUERY_FOREIGN)
  702. return ERROR_SUCCESS;
  703. // Assume PerfMon is collecting both until we prove otherwise
  704. fCollectGlobalData = TRUE;
  705. fCollectInstData = TRUE;
  706. if (dwQueryType == QUERY_ITEMS)
  707. {
  708. if (!IsNumberInUnicodeList(g_perfdata.potGlobal.ObjectNameTitleIndex, pszValueName))
  709. fCollectGlobalData = FALSE;
  710. if (!IsNumberInUnicodeList(g_perfinst.potInst.ObjectNameTitleIndex, pszValueName))
  711. fCollectInstData = FALSE;
  712. if (!fCollectGlobalData && !fCollectInstData)
  713. return ERROR_SUCCESS;
  714. }
  715. // Get a temporary pointer to the returned data buffer. If all goes well
  716. // then we update ppvData before leaving, else we leave it unchanged and
  717. // set *pcbTotal and pcObjTypes to zero and return ERROR_MORE_DATA.
  718. pcT = (char *) *ppvData;
  719. // Copy the data from the shared memory block for the system-wide
  720. // counters into the buffer provided and update our OUT params.
  721. if (g_rgdwGlobalCntr && fCollectGlobalData && g_PDI.cGlobalCounters)
  722. {
  723. DWORD cb;
  724. DWORD cbTotal;
  725. // Estimate total size, and see if we can fit.
  726. if (g_perfdata.potGlobal.TotalByteLength > cbBuff)
  727. return ERROR_MORE_DATA;
  728. // Copy data in chunks.
  729. cbTotal = 0;
  730. // PERF_OBJECT_TYPE
  731. cb = sizeof(PERF_OBJECT_TYPE);
  732. cbTotal += cb;
  733. CopyMemory((LPVOID) pcT, &g_perfdata.potGlobal, cb);
  734. pcT += cb;
  735. // PERF_COUNTER_DEFINITION []
  736. cb = g_PDI.cGlobalCounters * sizeof(PERF_COUNTER_DEFINITION);
  737. cbTotal += cb;
  738. CopyMemory((LPVOID) pcT, g_perfdata.rgCntrDef, cb);
  739. pcT += cb;
  740. // PERF_COUNTER_BLOCK
  741. cb = sizeof(PERF_COUNTER_BLOCK);
  742. cbTotal += cb;
  743. CopyMemory((LPVOID) pcT, &g_perfdata.CntrBlk , cb);
  744. pcT += cb;
  745. // (counters) DWORD []
  746. cb = g_PDI.cGlobalCounters * sizeof(DWORD);
  747. cbTotal += cb;
  748. CopyMemory((LPVOID) pcT, g_rgdwGlobalCntr, cb);
  749. pcT += cb;
  750. // If we've done our math right, This assert should be valid.
  751. //assert((DWORD)(pcT - (char *)*ppvData) == cbTotal);
  752. if (g_perfdata.potGlobal.TotalByteLength > cbTotal)
  753. {
  754. cb = g_perfdata.potGlobal.TotalByteLength - cbTotal;
  755. pcT += cb;
  756. }
  757. *pcbTotal += g_perfdata.potGlobal.TotalByteLength;
  758. (*pcObjTypes)++;
  759. }
  760. // Copy the data from the shared memory block for the per-instance
  761. // counters into the buffer provided and update our OUT params. We
  762. // must enter the mutex here to prevent connection instances from
  763. // being added to or removed from the list while we are copying data.
  764. if (g_pic && fCollectInstData && g_PDI.cInstCounters)
  765. {
  766. DWORD cb;
  767. DWORD cbTotal;
  768. DWORD ism;
  769. DWORD ipd;
  770. DWORD cInst;
  771. PERF_OBJECT_TYPE * pPOT;
  772. INSTDATA * pInstData;
  773. if (WaitForSingleObject(g_hmtxInst, INFINITE) != WAIT_OBJECT_0)
  774. {
  775. *pcbTotal = 0;
  776. *pcObjTypes = 0;
  777. // BUGBUG: wrong return code for the problem. We timed out waiting for
  778. // BUGBUG: the mutex; However, we may not return anything other than
  779. // BUGBUG: ERROR_SUCCESS or ERROR_MORE_DATA without disabling the DLL.
  780. return ERROR_SUCCESS;
  781. }
  782. // Find out how many instances exist.
  783. // NOTE: Zero instances is valid. We must still copy the "core" perf data.
  784. cInst = g_pic->cInstRecInUse;
  785. // Estimate total size, and see if we can fit.
  786. cbTotal = sizeof(PERF_OBJECT_TYPE) +
  787. (g_PDI.cInstCounters * sizeof(PERF_COUNTER_DEFINITION)) +
  788. (cInst * sizeof(INSTDATA)) +
  789. (cInst * (g_PDI.cInstCounters * sizeof(DWORD)));
  790. // Must return data aligned on 8-byte boundaries.
  791. cbTotal = ROUND_TO_8_BYTE(cbTotal);
  792. if (cbTotal > (cbBuff - *pcbTotal))
  793. {
  794. ReleaseMutex(g_hmtxInst);
  795. *pcbTotal = 0;
  796. *pcObjTypes = 0;
  797. return ERROR_MORE_DATA;
  798. }
  799. // Keep a pointer to beginig so we can update the "total bytes" value at the end.
  800. pPOT = (PERF_OBJECT_TYPE *) pcT;
  801. // PERF_OBJECT_TYPE
  802. CopyMemory(pPOT,
  803. &(g_perfinst.potInst),
  804. sizeof(PERF_OBJECT_TYPE));
  805. pcT += sizeof(PERF_OBJECT_TYPE);
  806. // PERF_COUNTER_DEFINITION []
  807. cb = g_PDI.cInstCounters * sizeof(PERF_COUNTER_DEFINITION);
  808. CopyMemory(pcT, g_perfinst.rgCntrDef, cb);
  809. pcT += cb;
  810. // Find instances and copy their counter data blocks
  811. for (ism = 0, ipd = 0; (ism < g_pic->cMaxInstRec) && (ipd < cInst); ism++)
  812. {
  813. if (g_rgInstRec[ism].fInUse)
  814. {
  815. pInstData = (INSTDATA *) pcT;
  816. // PERF_INSTANCE_DATA
  817. cb = sizeof(INSTDATA);
  818. CopyMemory(pcT,
  819. &g_instdata,
  820. cb);
  821. pcT += cb;
  822. // (inst name) WCHAR [] (inside INSTDATA block)
  823. cb = (wcslen(g_rgInstRec[ism].szInstName) + 1) * sizeof(WCHAR);
  824. //Assert( cb > 0 );
  825. //Assert( cb < (MAX_PATH * sizeof(WCHAR)) );
  826. CopyMemory(pInstData->szInstName,
  827. g_rgInstRec[ism].szInstName,
  828. cb);
  829. // Update PERF_INSTANCE_DEFINITION with correct name length.
  830. pInstData->InstDef.NameLength = cb;
  831. // (counters) DWORD []
  832. cb = g_PDI.cInstCounters * sizeof(DWORD);
  833. CopyMemory(pcT,
  834. &g_rgdwInstCntr[(ism * g_PDI.cInstCounters)],
  835. cb);
  836. pcT += cb;
  837. ipd++;
  838. }
  839. }
  840. // NOTE: we are deliberately ignoring the condition of
  841. // (ipd < cInst), even though that may indicate corruption
  842. // of the Shared Memory Block. Further note that this code
  843. // will never trap the condition of (ipd > cInst).
  844. // Done looking at Shared Memory Block.
  845. ReleaseMutex(g_hmtxInst);
  846. // Align data on 8-byte boundary
  847. cb = (DWORD)((char *) pcT - (char *) pPOT);
  848. cbTotal = ROUND_TO_8_BYTE(cb);
  849. if (cbTotal > cb)
  850. pcT += (cbTotal - cb);
  851. // Update PERF_OBJECT_TYPE with correct numbers
  852. pPOT->TotalByteLength = cbTotal;
  853. pPOT->NumInstances = ipd; // Use the count of instances we actually *found*
  854. *pcbTotal += cbTotal;
  855. (*pcObjTypes)++;
  856. }
  857. // We only get here if nothing failed. It is now safe
  858. // to update *ppvData and return a success indication.
  859. *ppvData = (LPVOID) pcT;
  860. return ERROR_SUCCESS;
  861. }
  862. /*
  863. - ClosePerformanceData
  864. -
  865. * Purpose:
  866. * Called by PerfMon to uninit the counter DLL.
  867. *
  868. * Parameters:
  869. * void
  870. *
  871. * Errors:
  872. * ERROR_SUCCESS Always!
  873. */
  874. DWORD
  875. APIENTRY
  876. ClosePerformanceData(void)
  877. {
  878. if (g_cRef > 0)
  879. {
  880. if (--g_cRef == 0)
  881. {
  882. // We're going to free stuff; make sure later calls
  883. // don't de-ref bad pointers.
  884. g_fInit = FALSE;
  885. // Close down Global Counters
  886. if (g_rgdwGlobalCntr)
  887. UnmapViewOfFile(g_rgdwGlobalCntr);
  888. if (g_hsmGlobalCntr)
  889. CloseHandle(g_hsmGlobalCntr);
  890. // Close down Instance Counters
  891. // NOTE: g_pic is the starting offset of the SM block.
  892. // NOTE: DO NOT Unmap on g_rgInstRec!
  893. if (g_pic)
  894. UnmapViewOfFile(g_pic);
  895. if (g_hsmInstAdm)
  896. CloseHandle(g_hsmInstAdm);
  897. if (g_rgdwInstCntr)
  898. UnmapViewOfFile(g_rgdwInstCntr);
  899. if (g_hsmInstCntr)
  900. CloseHandle(g_hsmInstCntr);
  901. if (g_hmtxInst)
  902. CloseHandle(g_hmtxInst);
  903. // Free all that memory we've alloc'd
  904. HrFreePerfCounterMem();
  905. g_rgdwGlobalCntr = NULL;
  906. g_hsmGlobalCntr = NULL;
  907. g_pic = NULL;
  908. g_rgInstRec = NULL;
  909. g_rgdwInstCntr = NULL;
  910. g_hsmInstAdm = NULL;
  911. g_hsmInstCntr = NULL;
  912. g_hmtxInst = NULL;
  913. }
  914. }
  915. return ERROR_SUCCESS;
  916. }
  917. /*
  918. - GetQueryType
  919. -
  920. * Purpose:
  921. * Returns the type of query described in the lpValue string so that
  922. * the appropriate processing method may be used.
  923. *
  924. * Parameters:
  925. * lpValue String passed to PerfRegQuery Value for processing
  926. *
  927. * Returns:
  928. * QUERY_GLOBAL | QUERY_FOREIGN | QUERY_COSTLY | QUERY_ITEMS
  929. *
  930. */
  931. static
  932. DWORD
  933. GetQueryType(LPWSTR lpValue)
  934. {
  935. WCHAR * pwcArgChar, *pwcTypeChar;
  936. BOOL bFound;
  937. if (lpValue == 0)
  938. return QUERY_GLOBAL;
  939. if (*lpValue == 0)
  940. return QUERY_GLOBAL;
  941. // check for "Global" request
  942. pwcArgChar = lpValue;
  943. pwcTypeChar = szGlobal;
  944. bFound = TRUE; // assume found until contradicted
  945. // check to the length of the shortest string
  946. while ((*pwcArgChar != 0) && (*pwcTypeChar != 0))
  947. {
  948. if (*pwcArgChar++ != *pwcTypeChar++)
  949. {
  950. bFound = FALSE; // no match
  951. break; // bail out now
  952. }
  953. }
  954. if (bFound)
  955. return QUERY_GLOBAL;
  956. // check for "Foreign" request
  957. pwcArgChar = lpValue;
  958. pwcTypeChar = szForeign;
  959. bFound = TRUE; // assume found until contradicted
  960. // check to the length of the shortest string
  961. while ((*pwcArgChar != 0) && (*pwcTypeChar != 0))
  962. {
  963. if (*pwcArgChar++ != *pwcTypeChar++)
  964. {
  965. bFound = FALSE; // no match
  966. break; // bail out now
  967. }
  968. }
  969. if (bFound)
  970. return QUERY_FOREIGN;
  971. // check for "Costly" request
  972. pwcArgChar = lpValue;
  973. pwcTypeChar = szCostly;
  974. bFound = TRUE; // assume found until contradicted
  975. // check to the length of the shortest string
  976. while ((*pwcArgChar != 0) && (*pwcTypeChar != 0))
  977. {
  978. if (*pwcArgChar++ != *pwcTypeChar++)
  979. {
  980. bFound = FALSE; // no match
  981. break; // bail out now
  982. }
  983. }
  984. if (bFound)
  985. return QUERY_COSTLY;
  986. // if not Global and not Foreign and not Costly,
  987. // then it must be an item list
  988. return QUERY_ITEMS;
  989. }
  990. /*
  991. - IsNumberInUnicodeList
  992. -
  993. * Purpose:
  994. * Determines if dwNumber is in the pszUnicodeList.
  995. *
  996. * Parameters:
  997. * dwNumber Number to find in list
  998. * pszUnicodeList Space delimited list of decimal numbers
  999. *
  1000. * Errors:
  1001. * TRUE/FALSE If found/not found respectively
  1002. *
  1003. */
  1004. static
  1005. BOOL
  1006. IsNumberInUnicodeList(DWORD dwNumber, LPWSTR pszUnicodeList)
  1007. {
  1008. DWORD dwThisNumber = 0;
  1009. BOOL bValidNumber = FALSE;
  1010. BOOL bNewItem = TRUE;
  1011. WCHAR wcDelimiter = (WCHAR)' ';
  1012. WCHAR *pwcThisChar;
  1013. if (pszUnicodeList == NULL)
  1014. return FALSE;
  1015. pwcThisChar = pszUnicodeList;
  1016. while (TRUE) /*lint !e774*/
  1017. {
  1018. switch (EvalThisChar(*pwcThisChar, wcDelimiter))
  1019. {
  1020. case DIGIT:
  1021. // if this is the first digit after a delimiter, then
  1022. // set flags to start computing the new number
  1023. if (bNewItem)
  1024. {
  1025. bNewItem = FALSE;
  1026. bValidNumber = TRUE;
  1027. }
  1028. if (bValidNumber)
  1029. {
  1030. dwThisNumber *= 10;
  1031. dwThisNumber += (*pwcThisChar - (WCHAR)'0');
  1032. }
  1033. break;
  1034. case DELIMITER:
  1035. // a delimter is either the delimiter character or the
  1036. // end of the string ('\0') if when the delimiter has been
  1037. // reached a valid number was found, then compare it to the
  1038. // number from the argument list. if this is the end of the
  1039. // string and no match was found, then return.
  1040. if (bValidNumber)
  1041. {
  1042. if (dwThisNumber == dwNumber)
  1043. return TRUE;
  1044. bValidNumber = FALSE;
  1045. }
  1046. if (*pwcThisChar == 0)
  1047. {
  1048. return FALSE;
  1049. }
  1050. else
  1051. {
  1052. bNewItem = TRUE;
  1053. dwThisNumber = 0;
  1054. }
  1055. break;
  1056. case INVALID:
  1057. // if an invalid character was encountered, ignore all
  1058. // characters up to the next delimiter and then start fresh.
  1059. // the invalid number is not compared.
  1060. bValidNumber = FALSE;
  1061. break;
  1062. default:
  1063. break;
  1064. }
  1065. pwcThisChar++;
  1066. }
  1067. }
  1068. /*
  1069. - HrLogEvent
  1070. -
  1071. * Purpose:
  1072. * Wrap up the call to ReportEvent to make things look nicer.
  1073. */
  1074. HRESULT
  1075. HrLogEvent(HANDLE hEventLog, WORD wType, DWORD msgid)
  1076. {
  1077. if (g_fInitCalled)
  1078. {
  1079. DWORD cb = sizeof(WCHAR) * wcslen(g_PDI.wszSvcName);
  1080. if (hEventLog)
  1081. return ReportEvent(hEventLog,
  1082. wType, // Event Type
  1083. (WORD)0, // Category
  1084. msgid, // Event ID
  1085. NULL, // User SID
  1086. 0, // # strings to merge
  1087. cb, // size of binary data (bytes)
  1088. NULL, // array of strings to merge
  1089. g_PDI.wszSvcName); // binary data
  1090. else
  1091. return E_FAIL;
  1092. }
  1093. else
  1094. return E_FAIL;
  1095. }
  1096. /*
  1097. - HrOpenSharedMemoryBlocks
  1098. -
  1099. * Purpose:
  1100. * Encapsulate the grossness of opening the shared memory blocks.
  1101. */
  1102. HRESULT
  1103. HrOpenSharedMemoryBlocks(HANDLE hEventLog, SECURITY_ATTRIBUTES * psa)
  1104. {
  1105. HRESULT hr=S_OK;
  1106. BOOL fExist;
  1107. if (!g_fInitCalled)
  1108. return E_FAIL;
  1109. if (!psa)
  1110. return E_INVALIDARG;
  1111. // Shared Memory for Global Counters
  1112. if (g_PDI.cGlobalCounters)
  1113. {
  1114. hr = HrOpenSharedMemory(g_PDI.wszGlobalSMName,
  1115. (sizeof(DWORD) * g_PDI.cGlobalCounters),
  1116. psa,
  1117. &g_hsmGlobalCntr,
  1118. (LPVOID *) &g_rgdwGlobalCntr,
  1119. &fExist);
  1120. if (FAILED(hr))
  1121. {
  1122. //HrLogEvent(hEventLog, EVENTLOG_ERROR_TYPE, msgidCntrInitSharedMemory1);
  1123. goto ret;
  1124. }
  1125. if (!fExist)
  1126. ZeroMemory(g_rgdwGlobalCntr, (g_PDI.cGlobalCounters * sizeof(DWORD)));
  1127. }
  1128. // Shared Memory for Instance Counters
  1129. if (g_PDI.cInstCounters)
  1130. {
  1131. DWORD cbAdm;
  1132. DWORD cbCntr;
  1133. WCHAR szAdmName[MAX_PATH]; // Admin SM Name
  1134. WCHAR szCntrName[MAX_PATH]; // Counter SM Name
  1135. // Calc required memory sizes
  1136. // BUGBUG: Since we're puntin on dynamic instances, we use g_cMaxInst
  1137. cbAdm = sizeof(INSTCNTR_DATA) + (sizeof(INSTREC) * g_cMaxInst);
  1138. cbCntr = ((sizeof(DWORD) * g_PDI.cInstCounters) * g_cMaxInst);
  1139. // Build SM names for Admin and Counters
  1140. wsprintf(szAdmName, L"%s_ADM", g_PDI.wszInstSMName);
  1141. wsprintf(szCntrName,L"%s_CNTR", g_PDI.wszInstSMName);
  1142. // Open Instance Admin Memory
  1143. hr = HrOpenSharedMemory(szAdmName,
  1144. cbAdm,
  1145. psa,
  1146. &g_hsmInstAdm,
  1147. (LPVOID *)&g_pic,
  1148. &fExist);
  1149. if (FAILED(hr))
  1150. {
  1151. //HrLogEvent(hEventLog, EVENTLOG_ERROR_TYPE, msgidCntrInitSharedMemory2);
  1152. goto ret;
  1153. }
  1154. // Fixup Pointers
  1155. g_rgInstRec = (INSTREC *) ((LPBYTE) g_pic + sizeof(INSTCNTR_DATA));
  1156. if (!fExist)
  1157. {
  1158. ZeroMemory(g_pic, cbAdm);
  1159. g_pic->cMaxInstRec = g_cMaxInst;
  1160. g_pic->cInstRecInUse = 0;
  1161. }
  1162. // Because we don't support dynamic instances, We should *always*
  1163. // have a MaxInstRec of g_cMaxInst
  1164. //Assert(g_cMaxInst == g_pic->cMaxInstRec);
  1165. // Open Instance Counter Memory
  1166. hr = HrOpenSharedMemory(szCntrName,
  1167. cbCntr,
  1168. psa,
  1169. &g_hsmInstCntr,
  1170. (LPVOID *)&g_rgdwInstCntr,
  1171. &fExist);
  1172. if (FAILED(hr))
  1173. {
  1174. //HrLogEvent(hEventLog, EVENTLOG_ERROR_TYPE, msgidCntrInitSharedMemory2);
  1175. goto ret;
  1176. }
  1177. if (!fExist)
  1178. ZeroMemory(g_rgdwInstCntr, cbCntr);
  1179. }
  1180. ret:
  1181. return hr;
  1182. }
  1183. /*
  1184. - HrGetCounterIDsFromReg
  1185. -
  1186. * Purpose:
  1187. * Get the "First Name" and "First Help" inicies from the Registry in the
  1188. * special place for the configured service.
  1189. */
  1190. HRESULT
  1191. HrGetCounterIDsFromReg(HANDLE hEventLog, DWORD * pdwFirstCntr, DWORD * pdwFirstHelp)
  1192. {
  1193. HRESULT hr;
  1194. HKEY hKey = NULL;
  1195. WCHAR wszServicePerfKey[MAX_PATH];
  1196. DWORD dwSize;
  1197. DWORD dwType;
  1198. if (!g_fInitCalled)
  1199. return E_FAIL;
  1200. if (!pdwFirstCntr || !pdwFirstHelp)
  1201. return E_INVALIDARG;
  1202. // Get the First Counter and First Help from the registry
  1203. wsprintf(wszServicePerfKey, L"SYSTEM\\CurrentControlSet\\Services\\%s\\Performance", g_PDI.wszSvcName);
  1204. hr = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
  1205. wszServicePerfKey,
  1206. 0L,
  1207. KEY_READ,
  1208. &hKey);
  1209. if (hr != ERROR_SUCCESS)
  1210. {
  1211. //HrLogEvent(hEventLog, EVENTLOG_ERROR_TYPE, msgidCntrOpenRegistry);
  1212. goto ret;
  1213. }
  1214. dwSize = sizeof(DWORD);
  1215. hr = RegQueryValueExW(hKey,
  1216. L"First Counter",
  1217. 0L,
  1218. &dwType,
  1219. (LPBYTE)pdwFirstCntr,
  1220. &dwSize);
  1221. if (hr != ERROR_SUCCESS)
  1222. {
  1223. //HrLogEvent(hEventLog, EVENTLOG_ERROR_TYPE, msgidCntrQueryRegistry1);
  1224. goto ret;
  1225. }
  1226. dwSize = sizeof(DWORD);
  1227. hr = RegQueryValueExW(hKey,
  1228. L"First Help",
  1229. 0L,
  1230. &dwType,
  1231. (LPBYTE)pdwFirstHelp,
  1232. &dwSize);
  1233. if (hr != ERROR_SUCCESS)
  1234. {
  1235. //HrLogEvent(hEventLog, EVENTLOG_ERROR_TYPE, msgidCntrQueryRegistry2);
  1236. goto ret;
  1237. }
  1238. ret:
  1239. if (hKey)
  1240. RegCloseKey(hKey);
  1241. return hr;
  1242. }
  1243. /*
  1244. - HrAllocPerfCounterMem
  1245. -
  1246. * Purpose:
  1247. * Allocates memory for PERF_COUNTER_DEFINITION arrays for both
  1248. * g_perfdata and g_perfinst.
  1249. *
  1250. * Notes:
  1251. * Uses ProcessHeap handle obtained in HrInit.
  1252. */
  1253. HRESULT
  1254. HrAllocPerfCounterMem(HANDLE hEventLog)
  1255. {
  1256. HRESULT hr;
  1257. DWORD cb;
  1258. if (!g_fInitCalled)
  1259. return E_FAIL;
  1260. // Global Counters
  1261. if (g_PDI.cGlobalCounters)
  1262. {
  1263. // Alloc Global PERF_COUNTER_DEFINITION array
  1264. cb = (sizeof(PERF_COUNTER_DEFINITION) * g_PDI.cGlobalCounters);
  1265. g_perfdata.rgCntrDef = (PERF_COUNTER_DEFINITION *) malloc(cb);
  1266. if(NULL == g_perfdata.rgCntrDef)
  1267. {
  1268. hr = E_OUTOFMEMORY;
  1269. goto err;
  1270. }
  1271. }
  1272. // Instance Counters
  1273. if (g_PDI.cInstCounters)
  1274. {
  1275. // Alloc Inst PERF_COUNTER_DEFINITION array
  1276. cb = (sizeof(PERF_COUNTER_DEFINITION) * g_PDI.cInstCounters);
  1277. g_perfinst.rgCntrDef = (PERF_COUNTER_DEFINITION *) malloc(cb);
  1278. if(NULL == g_perfinst.rgCntrDef )
  1279. {
  1280. hr = E_OUTOFMEMORY;
  1281. goto err;
  1282. }
  1283. }
  1284. return S_OK;
  1285. err:
  1286. //HrLogEvent(hEventLog, EVENTLOG_ERROR_TYPE, msgidCntrAlloc);
  1287. HrFreePerfCounterMem();
  1288. return hr;
  1289. }
  1290. /*
  1291. - HrFreePerfCounterMem
  1292. -
  1293. * Purpose:
  1294. * Companion to HrAllocPerfCounterMem
  1295. *
  1296. * Note:
  1297. * Uses ProcessHeap handle obtained in HrInit.
  1298. */
  1299. HRESULT
  1300. HrFreePerfCounterMem(void)
  1301. {
  1302. if (!g_fInitCalled)
  1303. return E_FAIL;
  1304. // We must invalidate the DLL if we release the memory in the g_PDI
  1305. g_fInitCalled = FALSE;
  1306. if (g_perfdata.rgCntrDef)
  1307. {
  1308. free(g_perfdata.rgCntrDef);
  1309. g_perfdata.rgCntrDef = NULL;
  1310. }
  1311. if (g_perfinst.rgCntrDef)
  1312. {
  1313. free(g_perfinst.rgCntrDef);
  1314. g_perfinst.rgCntrDef = NULL;
  1315. }
  1316. return S_OK;
  1317. }
  1318. HRESULT
  1319. HrUninstallPerfDll(
  1320. IN LPCWSTR szService )
  1321. {
  1322. // Make sure we've valid input
  1323. if( !szService ) return E_INVALIDARG;
  1324. // First, do unlodctr since removing the Performance key without removing
  1325. // counter names and descriptions may toast the perfmon system
  1326. std::wstring wszService = L"x "; // KB Article Q188769
  1327. wszService += szService;
  1328. DWORD dwErr = UnloadPerfCounterTextStringsW(const_cast<LPWSTR>(wszService.c_str()), TRUE);
  1329. if( dwErr != ERROR_SUCCESS )
  1330. {
  1331. // Continue without error if unlodctr has already been called
  1332. if( (dwErr != ERROR_FILE_NOT_FOUND) && (dwErr != ERROR_BADKEY) )
  1333. {
  1334. return HRESULT_FROM_WIN32(dwErr);
  1335. }
  1336. }
  1337. // Now that unlodctr has succeeded, we can start deleting registry keys
  1338. // Start with the Performance key of the service
  1339. std::wstring wszRegKey;
  1340. wszRegKey = szServiceRegKeyPrefix;
  1341. wszRegKey += szService;
  1342. dwErr = SHDeleteKey(HKEY_LOCAL_MACHINE, wszRegKey.c_str());
  1343. if( (dwErr != ERROR_SUCCESS) && (dwErr != ERROR_FILE_NOT_FOUND) )
  1344. {
  1345. return HRESULT_FROM_WIN32(dwErr);
  1346. }
  1347. // Use WIN32 API's to get the path to the module name
  1348. wchar_t szFileName[_MAX_PATH+1] ;
  1349. MEMORY_BASIC_INFORMATION mbi;
  1350. VirtualQuery(HrUninstallPerfDll, &mbi, sizeof(mbi));
  1351. DWORD dwRet = GetModuleFileName( reinterpret_cast<HINSTANCE>(mbi.AllocationBase), szFileName, sizeof(szFileName)/sizeof(wchar_t)-1) ;
  1352. if (dwRet == 0)
  1353. {
  1354. // Wow, don't know what happened,
  1355. return HRESULT_FROM_WIN32(::GetLastError());
  1356. }
  1357. szFileName[_MAX_PATH]=0;
  1358. // Split the module path to get the filename
  1359. wchar_t szDrive[_MAX_DRIVE] ;
  1360. wchar_t szDir[_MAX_DIR ] ;
  1361. wchar_t szPerfFilename[ _MAX_FNAME ] ;
  1362. wchar_t szExt[_MAX_EXT ] ;
  1363. _wsplitpath( szFileName, szDrive, szDir, szPerfFilename, szExt ) ;
  1364. // Delete the Event Log key for the service
  1365. wszRegKey = szEventLogRegKeyPrefix;
  1366. wszRegKey += szPerfFilename;
  1367. dwErr = SHDeleteKey(HKEY_LOCAL_MACHINE, wszRegKey.c_str());
  1368. if( ERROR_FILE_NOT_FOUND == dwErr ) dwErr = ERROR_SUCCESS;
  1369. return HRESULT_FROM_WIN32(dwErr);
  1370. }