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.

1383 lines
42 KiB

  1. /*++
  2. Copyright (C) 1996-1999 Microsoft Corporation
  3. Module Name:
  4. perfdata.c
  5. Abstract:
  6. <abstract>
  7. --*/
  8. #include <nt.h>
  9. #include <ntrtl.h>
  10. #include <nturtl.h>
  11. #include <windows.h>
  12. #include <winperf.h>
  13. #include <assert.h>
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #include <stdio.h>
  17. #include <tchar.h>
  18. #include <mbctype.h>
  19. #include "pdhitype.h"
  20. #include "pdhidef.h"
  21. #include "perftype.h"
  22. #include "perfdata.h"
  23. #include "pdhmsg.h"
  24. #include "strings.h"
  25. // the following strings are for getting texts from perflib
  26. #define OLD_VERSION 0x010000
  27. #define tohexdigit(x) ((CHAR) (((x) < 10) ? ((x) + L'0') : ((x) + L'a' - 10)))
  28. DWORD
  29. PdhiMakePerfPrimaryLangId(
  30. IN LANGID lID,
  31. OUT LPWSTR szBuffer
  32. )
  33. {
  34. WCHAR LangId;
  35. WCHAR nDigit;
  36. LangId = (WCHAR) PRIMARYLANGID(lID);
  37. nDigit = (WCHAR) (LangId >> 8);
  38. szBuffer[0] = tohexdigit(nDigit);
  39. nDigit = (WCHAR) (LangId & 0XF0) >> 4;
  40. szBuffer[1] = tohexdigit(nDigit);
  41. nDigit = (WCHAR) (LangId & 0xF);
  42. szBuffer[2] = tohexdigit(nDigit);
  43. szBuffer[3] = L'\0';
  44. return ERROR_SUCCESS;
  45. }
  46. BOOL IsMatchingInstance (
  47. PERF_INSTANCE_DEFINITION *pInstanceDef,
  48. DWORD dwCodePage,
  49. LPWSTR szInstanceNameToMatch,
  50. DWORD dwInstanceNameLength
  51. )
  52. // compares pInstanceName to the name in the instance
  53. {
  54. DWORD dwThisInstanceNameLength;
  55. LPWSTR szThisInstanceName = NULL;
  56. WCHAR szBufferForANSINames[MAX_PATH];
  57. ZeroMemory(szBufferForANSINames, sizeof(WCHAR) * MAX_PATH);
  58. if (dwInstanceNameLength == 0) {
  59. // get the length to compare
  60. dwInstanceNameLength = lstrlenW (szInstanceNameToMatch);
  61. }
  62. if (dwCodePage == 0) {
  63. // try to take a shortcut here if it's a unicode string
  64. // compare to the length of the shortest string
  65. // get the pointer to this string
  66. szThisInstanceName = GetInstanceName(pInstanceDef);
  67. // convert instance Name from bytes to chars
  68. dwThisInstanceNameLength = pInstanceDef->NameLength / sizeof(WCHAR);
  69. // see if this length includes the term. null. If so shorten it
  70. if (szThisInstanceName[dwThisInstanceNameLength-1] == 0) {
  71. dwThisInstanceNameLength--;
  72. }
  73. } else {
  74. // go the long way and read/translate/convert the string
  75. dwThisInstanceNameLength =GetInstanceNameStr (pInstanceDef,
  76. szBufferForANSINames,
  77. dwCodePage);
  78. if (dwThisInstanceNameLength > 0) {
  79. szThisInstanceName = &szBufferForANSINames[0];
  80. }
  81. }
  82. // if the lengths are not equal then the names can't be either
  83. if (dwInstanceNameLength != dwThisInstanceNameLength) {
  84. return FALSE;
  85. } else {
  86. if (szThisInstanceName != NULL) {
  87. if (lstrcmpiW(szInstanceNameToMatch, szThisInstanceName) == 0) {
  88. // this is a match
  89. return TRUE;
  90. } else {
  91. // this is not a match
  92. return FALSE;
  93. }
  94. } else {
  95. // this is not a match
  96. return FALSE;
  97. }
  98. }
  99. }
  100. LPWSTR
  101. *BuildNameTable(
  102. LPWSTR szComputerName, // computer to query names from
  103. LANGID LangId, // language ID
  104. PPERF_MACHINE pMachine // update member fields
  105. )
  106. /*++
  107. BuildNameTable
  108. Arguments:
  109. hKeyRegistry
  110. Handle to an open registry (this can be local or remote.) and
  111. is the value returned by RegConnectRegistry or a default key.
  112. lpszLangId
  113. The unicode id of the language to look up. (default is 409)
  114. Return Value:
  115. pointer to an allocated table. (the caller must free it when finished!)
  116. the table is an array of pointers to zero terminated strings. NULL is
  117. returned if an error occured.
  118. --*/
  119. {
  120. LPWSTR *lpCounterId;
  121. LPWSTR lpCounterNames;
  122. LPWSTR lpHelpText;
  123. LPWSTR lpThisName;
  124. LONG lWin32Status = ERROR_SUCCESS;
  125. DWORD dwLastError;
  126. DWORD dwValueType;
  127. DWORD dwArraySize;
  128. DWORD dwBufferSize;
  129. DWORD dwCounterSize = 0;
  130. DWORD dwHelpSize = 0;
  131. DWORD dw009CounterSize = 0;
  132. DWORD dw009HelpSize = 0;
  133. DWORD dwThisCounter;
  134. DWORD dwLastCounter;
  135. DWORD dwSystemVersion;
  136. DWORD dwLastId;
  137. DWORD dwLastHelpId;
  138. HKEY hKeyRegistry = NULL;
  139. HKEY hKeyValue = NULL;
  140. HKEY hKeyNames = NULL;
  141. HKEY hKey009Names = NULL;
  142. LPWSTR lpValueNameString;
  143. LPWSTR lp009ValueNameString;
  144. WCHAR CounterNameBuffer[50];
  145. WCHAR HelpNameBuffer[50];
  146. WCHAR Counter009NameBuffer[50];
  147. WCHAR Help009NameBuffer[50];
  148. WCHAR lpszLangId[16];
  149. BOOL bUse009Locale = FALSE;
  150. BOOL bUsePerfTextKey = TRUE;
  151. lpValueNameString = NULL; //initialize to NULL
  152. lp009ValueNameString = NULL;
  153. pMachine->szPerfStrings = NULL;
  154. pMachine->sz009PerfStrings = NULL;
  155. pMachine->typePerfStrings = NULL;
  156. if (szComputerName == NULL) {
  157. // use local machine
  158. hKeyRegistry = HKEY_LOCAL_MACHINE;
  159. } else {
  160. if ((lWin32Status = RegConnectRegistryW(szComputerName,
  161. HKEY_LOCAL_MACHINE, & hKeyRegistry)) != ERROR_SUCCESS) {
  162. // unable to connect to registry
  163. goto BNT_BAILOUT;
  164. }
  165. }
  166. // check for null arguments and insert defaults if necessary
  167. if ( (LangId == MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US))
  168. || (PRIMARYLANGID(LangId) == LANG_ENGLISH)) {
  169. bUse009Locale = TRUE;
  170. }
  171. PdhiMakePerfPrimaryLangId(LangId, lpszLangId);
  172. // open registry to get number of items for computing array size
  173. lWin32Status = RegOpenKeyExW (
  174. hKeyRegistry,
  175. cszNamesKey,
  176. RESERVED,
  177. KEY_READ,
  178. &hKeyValue);
  179. if (lWin32Status != ERROR_SUCCESS) {
  180. goto BNT_BAILOUT;
  181. }
  182. // get last update time of registry key
  183. lWin32Status = RegQueryInfoKey (
  184. hKeyValue, NULL, NULL, NULL, NULL, NULL, NULL,
  185. NULL, NULL, NULL, NULL, & pMachine->LastStringUpdateTime);
  186. // get number of items
  187. dwBufferSize = sizeof (dwLastHelpId);
  188. lWin32Status = RegQueryValueExW (
  189. hKeyValue,
  190. cszLastHelp,
  191. RESERVED,
  192. &dwValueType,
  193. (LPBYTE)&dwLastHelpId,
  194. &dwBufferSize);
  195. if ((lWin32Status != ERROR_SUCCESS) || (dwValueType != REG_DWORD)) {
  196. goto BNT_BAILOUT;
  197. }
  198. // get number of items
  199. dwBufferSize = sizeof (dwLastId);
  200. lWin32Status = RegQueryValueExW (
  201. hKeyValue,
  202. cszLastCounter,
  203. RESERVED,
  204. &dwValueType,
  205. (LPBYTE)&dwLastId,
  206. &dwBufferSize);
  207. if ((lWin32Status != ERROR_SUCCESS) || (dwValueType != REG_DWORD)) {
  208. goto BNT_BAILOUT;
  209. }
  210. if (dwLastId < dwLastHelpId)
  211. dwLastId = dwLastHelpId;
  212. dwArraySize = (dwLastId + 1) * sizeof(LPWSTR);
  213. // get Perflib system version
  214. dwBufferSize = sizeof (dwSystemVersion);
  215. lWin32Status = RegQueryValueExW (
  216. hKeyValue,
  217. cszVersionName,
  218. RESERVED,
  219. &dwValueType,
  220. (LPBYTE)&dwSystemVersion,
  221. &dwBufferSize);
  222. if ((lWin32Status != ERROR_SUCCESS) || (dwValueType != REG_DWORD)) {
  223. dwSystemVersion = OLD_VERSION;
  224. }
  225. if (dwSystemVersion == OLD_VERSION) {
  226. // get names from registry
  227. lpValueNameString = G_ALLOC (
  228. lstrlenW(cszNamesKey) * sizeof (WCHAR) +
  229. lstrlenW(cszBackSlash) * sizeof (WCHAR) +
  230. lstrlenW(lpszLangId) * sizeof (WCHAR) +
  231. sizeof (UNICODE_NULL));
  232. if (!lpValueNameString) goto BNT_BAILOUT;
  233. lstrcpyW (lpValueNameString, cszNamesKey);
  234. lstrcatW (lpValueNameString, cszBackSlash);
  235. lstrcatW (lpValueNameString, lpszLangId);
  236. lWin32Status = RegOpenKeyExW (
  237. hKeyRegistry,
  238. lpValueNameString,
  239. RESERVED,
  240. KEY_READ,
  241. &hKeyNames);
  242. if (! bUse009Locale && lWin32Status == ERROR_SUCCESS) {
  243. lp009ValueNameString = G_ALLOC(sizeof(UNICODE_NULL)
  244. + lstrlenW(cszNamesKey) * sizeof (WCHAR)
  245. + lstrlenW(cszBackSlash) * sizeof (WCHAR)
  246. + lstrlenW(cszDefaultLangId) * sizeof (WCHAR));
  247. if (!lpValueNameString) goto BNT_BAILOUT;
  248. lstrcpyW (lpValueNameString, cszNamesKey);
  249. lstrcatW (lpValueNameString, cszBackSlash);
  250. lstrcatW (lpValueNameString, cszDefaultLangId);
  251. lWin32Status = RegOpenKeyExW(hKeyRegistry,
  252. lp009ValueNameString,
  253. RESERVED,
  254. KEY_READ,
  255. & hKey009Names);
  256. }
  257. } else {
  258. __try {
  259. if (bUse009Locale == FALSE) {
  260. if ((lWin32Status = RegConnectRegistryW(szComputerName,
  261. HKEY_PERFORMANCE_NLSTEXT,
  262. & hKeyNames)) == ERROR_SUCCESS) {
  263. if ((lWin32Status = RegConnectRegistryW(szComputerName,
  264. HKEY_PERFORMANCE_TEXT,
  265. & hKey009Names)) != ERROR_SUCCESS) {
  266. bUsePerfTextKey = FALSE;
  267. RegCloseKey(hKeyNames);
  268. }
  269. }
  270. else {
  271. bUsePerfTextKey = FALSE;
  272. }
  273. }
  274. else {
  275. if ((lWin32Status = RegConnectRegistryW(szComputerName,
  276. HKEY_PERFORMANCE_TEXT,
  277. & hKeyNames)) != ERROR_SUCCESS) {
  278. bUsePerfTextKey = FALSE;
  279. }
  280. else {
  281. hKey009Names = hKeyNames;
  282. }
  283. }
  284. }
  285. __except (EXCEPTION_EXECUTE_HANDLER) {
  286. bUsePerfTextKey = FALSE;
  287. }
  288. }
  289. if (! bUsePerfTextKey) {
  290. lstrcpyW(CounterNameBuffer, cszCounterName);
  291. lstrcatW(CounterNameBuffer, lpszLangId);
  292. lstrcpyW(HelpNameBuffer, cszHelpName);
  293. lstrcatW(HelpNameBuffer, lpszLangId);
  294. lstrcpyW(Counter009NameBuffer, cszCounterName);
  295. lstrcatW(Counter009NameBuffer, cszDefaultLangId);
  296. lstrcpyW(Help009NameBuffer, cszHelpName);
  297. lstrcatW(Help009NameBuffer, cszDefaultLangId);
  298. // cannot open HKEY_PERFORMANCE_TEXT, try the old way
  299. //
  300. if (szComputerName == NULL) {
  301. hKeyNames = HKEY_PERFORMANCE_DATA;
  302. }
  303. else if ((lWin32Status = RegConnectRegistryW(szComputerName,
  304. HKEY_PERFORMANCE_DATA,
  305. & hKeyNames)) != ERROR_SUCCESS) {
  306. goto BNT_BAILOUT;
  307. }
  308. hKey009Names = hKeyNames;
  309. }
  310. else {
  311. lstrcpyW(CounterNameBuffer, cszCounters);
  312. lstrcpyW(HelpNameBuffer, cszHelp);
  313. lstrcpyW(Counter009NameBuffer, cszCounters);
  314. lstrcpyW(Help009NameBuffer, cszHelp);
  315. }
  316. // get size of counter names and add that to the arrays
  317. if (lWin32Status != ERROR_SUCCESS) goto BNT_BAILOUT;
  318. dwBufferSize = 0;
  319. lWin32Status = RegQueryValueExW(
  320. hKeyNames,
  321. CounterNameBuffer,
  322. RESERVED,
  323. & dwValueType,
  324. NULL,
  325. & dwBufferSize);
  326. if (lWin32Status != ERROR_SUCCESS) goto BNT_BAILOUT;
  327. dwCounterSize = dwBufferSize;
  328. if (! bUse009Locale) {
  329. dwBufferSize = 0;
  330. lWin32Status = RegQueryValueExW(hKey009Names,
  331. Counter009NameBuffer,
  332. RESERVED,
  333. & dwValueType,
  334. NULL,
  335. & dwBufferSize);
  336. if (lWin32Status != ERROR_SUCCESS) goto BNT_BAILOUT;
  337. dw009CounterSize = dwBufferSize;
  338. }
  339. else {
  340. dw009CounterSize = dwCounterSize;
  341. }
  342. // get size of counter names and add that to the arrays
  343. if (lWin32Status != ERROR_SUCCESS) goto BNT_BAILOUT;
  344. dwBufferSize = 0;
  345. lWin32Status = RegQueryValueExW(
  346. hKeyNames,
  347. HelpNameBuffer,
  348. RESERVED,
  349. & dwValueType,
  350. NULL,
  351. & dwBufferSize);
  352. if (lWin32Status != ERROR_SUCCESS) goto BNT_BAILOUT;
  353. dwHelpSize = dwBufferSize;
  354. if (! bUse009Locale) {
  355. dwBufferSize = 0;
  356. lWin32Status = RegQueryValueExW(hKey009Names,
  357. Help009NameBuffer,
  358. RESERVED,
  359. & dwValueType,
  360. NULL,
  361. & dwBufferSize);
  362. if (lWin32Status != ERROR_SUCCESS) goto BNT_BAILOUT;
  363. dw009HelpSize = dwBufferSize;
  364. }
  365. else {
  366. dw009HelpSize = dwHelpSize;
  367. }
  368. pMachine->szPerfStrings = G_ALLOC(dwArraySize + dwCounterSize + dwHelpSize);
  369. if (! pMachine->szPerfStrings) goto BNT_BAILOUT;
  370. if (bUse009Locale) {
  371. pMachine->sz009PerfStrings = pMachine->szPerfStrings;
  372. }
  373. else {
  374. pMachine->sz009PerfStrings =
  375. G_ALLOC(dwArraySize + dw009CounterSize + dw009HelpSize);
  376. if (! pMachine->sz009PerfStrings) goto BNT_BAILOUT;
  377. }
  378. pMachine->typePerfStrings = G_ALLOC(dwLastId + 1);
  379. if (! pMachine->typePerfStrings) goto BNT_BAILOUT;
  380. // initialize pointers into buffer
  381. lpCounterId = pMachine->szPerfStrings;
  382. lpCounterNames = (LPWSTR)((LPBYTE)lpCounterId + dwArraySize);
  383. lpHelpText = (LPWSTR)((LPBYTE)lpCounterNames + dwCounterSize);
  384. // read counters into memory
  385. dwBufferSize = dwCounterSize;
  386. lWin32Status = RegQueryValueExW (
  387. hKeyNames,
  388. CounterNameBuffer,
  389. RESERVED,
  390. & dwValueType,
  391. (LPVOID)lpCounterNames,
  392. & dwBufferSize);
  393. if (lWin32Status != ERROR_SUCCESS) goto BNT_BAILOUT;
  394. dwBufferSize = dwHelpSize;
  395. lWin32Status = RegQueryValueExW (
  396. hKeyNames,
  397. HelpNameBuffer,
  398. RESERVED,
  399. & dwValueType,
  400. (LPVOID)lpHelpText,
  401. & dwBufferSize);
  402. if (lWin32Status != ERROR_SUCCESS) goto BNT_BAILOUT;
  403. // load counter array items
  404. dwLastCounter = 0;
  405. for (lpThisName = lpCounterNames;
  406. *lpThisName;
  407. lpThisName += (lstrlenW(lpThisName)+1) ) {
  408. // first string should be an integer (in decimal unicode digits)
  409. dwThisCounter = wcstoul (lpThisName, NULL, 10);
  410. // check for registry corruption. This shouldn't occur under
  411. // normal conditions
  412. assert (dwThisCounter > dwLastCounter);
  413. // point to corresponding counter name
  414. lpThisName += (lstrlenW(lpThisName)+1);
  415. // and load array element;
  416. if ((dwThisCounter > 0) && (dwThisCounter <= dwLastId)) {
  417. lpCounterId[dwThisCounter] = lpThisName;
  418. pMachine->typePerfStrings[dwThisCounter] = STR_COUNTER;
  419. dwLastCounter = dwThisCounter;
  420. }
  421. }
  422. dwLastCounter = 0;
  423. for (lpThisName = lpHelpText;
  424. *lpThisName;
  425. lpThisName += (lstrlenW(lpThisName)+1) ) {
  426. // first string should be an integer (in decimal unicode digits)
  427. dwThisCounter = wcstoul (lpThisName, NULL, 10);
  428. // check for registry corruption. This shouldn't occur under
  429. // normal conditions
  430. assert (dwThisCounter > dwLastCounter);
  431. // point to corresponding counter name
  432. lpThisName += (lstrlenW(lpThisName)+1);
  433. // and load array element;
  434. if ((dwThisCounter > 0) && (dwThisCounter <= dwLastId)) {
  435. lpCounterId[dwThisCounter] = lpThisName;
  436. pMachine->typePerfStrings[dwThisCounter] = STR_HELP;
  437. dwLastCounter = dwThisCounter;
  438. }
  439. }
  440. lpCounterId = pMachine->sz009PerfStrings;
  441. lpCounterNames = (LPWSTR) ((LPBYTE) lpCounterId + dwArraySize);
  442. lpHelpText = (LPWSTR) ((LPBYTE) lpCounterNames + dw009CounterSize);
  443. // read counters into memory
  444. dwBufferSize = dw009CounterSize;
  445. lWin32Status = RegQueryValueExW(hKey009Names,
  446. Counter009NameBuffer,
  447. RESERVED,
  448. & dwValueType,
  449. (LPVOID) lpCounterNames,
  450. & dwBufferSize);
  451. if (lWin32Status != ERROR_SUCCESS) goto BNT_BAILOUT;
  452. dwBufferSize = dw009HelpSize;
  453. lWin32Status = RegQueryValueExW(hKey009Names,
  454. Help009NameBuffer,
  455. RESERVED,
  456. & dwValueType,
  457. (LPVOID) lpHelpText,
  458. & dwBufferSize);
  459. if (lWin32Status != ERROR_SUCCESS) goto BNT_BAILOUT;
  460. for ( lpThisName = lpCounterNames;
  461. * lpThisName;
  462. lpThisName += (lstrlenW(lpThisName) + 1)) {
  463. dwThisCounter = wcstoul(lpThisName, NULL, 10);
  464. lpThisName += (lstrlenW(lpThisName) + 1);
  465. if ((dwThisCounter > 0) && (dwThisCounter <= dwLastId)) {
  466. lpCounterId[dwThisCounter] = lpThisName;
  467. }
  468. }
  469. for ( lpThisName = lpHelpText;
  470. * lpThisName;
  471. lpThisName += (lstrlenW(lpThisName) + 1) ) {
  472. dwThisCounter = wcstoul (lpThisName, NULL, 10);
  473. lpThisName += (lstrlenW(lpThisName) + 1);
  474. if ((dwThisCounter > 0) && (dwThisCounter <= dwLastId)) {
  475. lpCounterId[dwThisCounter] = lpThisName;
  476. }
  477. }
  478. pMachine->dwLastPerfString = dwLastId;
  479. if (lpValueNameString) G_FREE ((LPVOID) lpValueNameString);
  480. if (lp009ValueNameString) G_FREE ((LPVOID) lp009ValueNameString);
  481. RegCloseKey(hKeyValue);
  482. if (hKey009Names && hKey009Names != hKeyNames) RegCloseKey(hKey009Names);
  483. RegCloseKey(hKeyNames);
  484. if (hKeyRegistry && hKeyRegistry != HKEY_LOCAL_MACHINE)
  485. RegCloseKey(hKeyRegistry);
  486. return pMachine->szPerfStrings;
  487. BNT_BAILOUT:
  488. if (lWin32Status != ERROR_SUCCESS) {
  489. dwLastError = GetLastError();
  490. }
  491. if (lpValueNameString) {
  492. G_FREE ((LPVOID)lpValueNameString);
  493. }
  494. if ( pMachine->sz009PerfStrings
  495. && pMachine->sz009PerfStrings != pMachine->szPerfStrings) {
  496. G_FREE(pMachine->sz009PerfStrings);
  497. }
  498. if (pMachine->szPerfStrings) {
  499. G_FREE(pMachine->szPerfStrings);
  500. }
  501. if (pMachine->typePerfStrings) {
  502. G_FREE(pMachine->typePerfStrings);
  503. }
  504. if (hKeyValue) RegCloseKey(hKeyValue);
  505. if (hKey009Names && hKey009Names != hKeyNames) RegCloseKey(hKey009Names);
  506. if (hKeyNames) RegCloseKey(hKeyNames);
  507. if (hKeyRegistry) RegCloseKey(hKeyRegistry);
  508. return NULL;
  509. }
  510. #pragma warning ( disable : 4127 )
  511. PERF_OBJECT_TYPE *
  512. GetObjectDefByTitleIndex(
  513. IN PERF_DATA_BLOCK *pDataBlock,
  514. IN DWORD ObjectTypeTitleIndex
  515. )
  516. {
  517. DWORD NumTypeDef;
  518. PERF_OBJECT_TYPE *pObjectDef = NULL;
  519. PERF_OBJECT_TYPE *pReturnObject = NULL;
  520. PERF_OBJECT_TYPE *pEndOfBuffer = NULL;
  521. __try {
  522. pObjectDef = FirstObject(pDataBlock);
  523. pEndOfBuffer = (PPERF_OBJECT_TYPE)
  524. ((DWORD_PTR)pDataBlock +
  525. pDataBlock->TotalByteLength);
  526. assert (pObjectDef != NULL);
  527. NumTypeDef = 0;
  528. while (1) {
  529. if ( pObjectDef->ObjectNameTitleIndex == ObjectTypeTitleIndex ) {
  530. pReturnObject = pObjectDef;
  531. break;
  532. } else {
  533. NumTypeDef++;
  534. if (NumTypeDef < pDataBlock->NumObjectTypes) {
  535. pObjectDef = NextObject(pObjectDef);
  536. //make sure next object is legit
  537. if (pObjectDef != NULL) {
  538. if (pObjectDef->TotalByteLength > 0) {
  539. if (pObjectDef >= pEndOfBuffer) {
  540. // looks like we ran off the end of the data buffer
  541. assert (pObjectDef < pEndOfBuffer);
  542. break;
  543. }
  544. } else {
  545. // 0-length object buffer returned
  546. assert (pObjectDef->TotalByteLength > 0);
  547. break;
  548. }
  549. } else {
  550. // and continue
  551. assert (pObjectDef != NULL);
  552. break;
  553. }
  554. } else {
  555. // no more data objects in this data block
  556. break;
  557. }
  558. }
  559. }
  560. } __except (EXCEPTION_EXECUTE_HANDLER) {
  561. pReturnObject = NULL;
  562. }
  563. return pReturnObject;
  564. }
  565. PERF_OBJECT_TYPE *
  566. GetObjectDefByName (
  567. IN PERF_DATA_BLOCK *pDataBlock,
  568. IN DWORD dwLastNameIndex,
  569. IN LPCWSTR *NameArray,
  570. IN LPCWSTR szObjectName
  571. )
  572. {
  573. DWORD NumTypeDef;
  574. PERF_OBJECT_TYPE *pReturnObject = NULL;
  575. PERF_OBJECT_TYPE *pObjectDef = NULL;
  576. PERF_OBJECT_TYPE *pEndOfBuffer = NULL;
  577. __try {
  578. pObjectDef = FirstObject(pDataBlock);
  579. pEndOfBuffer = (PPERF_OBJECT_TYPE)
  580. ((DWORD_PTR)pDataBlock +
  581. pDataBlock->TotalByteLength);
  582. assert (pObjectDef != NULL);
  583. NumTypeDef = 0;
  584. while (1) {
  585. if ( pObjectDef->ObjectNameTitleIndex < dwLastNameIndex ) {
  586. // look up name of object & compare
  587. if (lstrcmpiW(NameArray[pObjectDef->ObjectNameTitleIndex],
  588. szObjectName) == 0) {
  589. pReturnObject = pObjectDef;
  590. break;
  591. }
  592. }
  593. NumTypeDef++;
  594. if (NumTypeDef < pDataBlock->NumObjectTypes) {
  595. pObjectDef = NextObject(pObjectDef); // get next
  596. //make sure next object is legit
  597. if (pObjectDef != NULL) {
  598. if (pObjectDef->TotalByteLength > 0) {
  599. if (pObjectDef >= pEndOfBuffer) {
  600. // looks like we ran off the end of the data buffer
  601. assert (pObjectDef < pEndOfBuffer);
  602. break;
  603. }
  604. } else {
  605. // 0-length object buffer returned
  606. assert (pObjectDef->TotalByteLength > 0);
  607. break;
  608. }
  609. } else {
  610. // null pointer
  611. assert (pObjectDef != NULL);
  612. break;
  613. }
  614. } else {
  615. // end of data block
  616. break;
  617. }
  618. }
  619. } __except (EXCEPTION_EXECUTE_HANDLER) {
  620. pReturnObject = NULL;
  621. }
  622. return pReturnObject;
  623. }
  624. #pragma warning ( default : 4127 )
  625. PERF_INSTANCE_DEFINITION *
  626. GetInstance(
  627. IN PERF_OBJECT_TYPE *pObjectDef,
  628. IN LONG InstanceNumber
  629. )
  630. {
  631. PERF_INSTANCE_DEFINITION *pInstanceDef;
  632. LONG NumInstance;
  633. if (!pObjectDef) {
  634. return 0;
  635. }
  636. pInstanceDef = FirstInstance(pObjectDef);
  637. for ( NumInstance = 0;
  638. NumInstance < pObjectDef->NumInstances;
  639. NumInstance++ ) {
  640. if ( InstanceNumber == NumInstance ) {
  641. return pInstanceDef;
  642. }
  643. pInstanceDef = NextInstance(pInstanceDef);
  644. }
  645. return NULL;
  646. }
  647. PERF_INSTANCE_DEFINITION *
  648. GetInstanceByUniqueId(
  649. IN PERF_OBJECT_TYPE *pObjectDef,
  650. IN LONG InstanceUniqueId
  651. )
  652. {
  653. PERF_INSTANCE_DEFINITION *pInstanceDef;
  654. LONG NumInstance;
  655. if (!pObjectDef) {
  656. return 0;
  657. }
  658. pInstanceDef = FirstInstance(pObjectDef);
  659. for ( NumInstance = 0;
  660. NumInstance < pObjectDef->NumInstances;
  661. NumInstance++ ) {
  662. if ( InstanceUniqueId == pInstanceDef->UniqueID ) {
  663. return pInstanceDef;
  664. }
  665. pInstanceDef = NextInstance(pInstanceDef);
  666. }
  667. return NULL;
  668. }
  669. DWORD
  670. GetAnsiInstanceName (PPERF_INSTANCE_DEFINITION pInstance,
  671. LPWSTR lpszInstance,
  672. DWORD dwCodePage)
  673. {
  674. LPSTR szSource;
  675. DWORD dwLength;
  676. szSource = (LPSTR)GetInstanceName(pInstance);
  677. // the locale should be set here
  678. DBG_UNREFERENCED_PARAMETER(dwCodePage);
  679. // pInstance->NameLength == the number of bytes (chars) in the string
  680. dwLength = (DWORD) MultiByteToWideChar(_getmbcp(),
  681. 0,
  682. szSource,
  683. lstrlenA(szSource),
  684. (LPWSTR) lpszInstance,
  685. pInstance->NameLength);
  686. lpszInstance[dwLength] = 0; // null terminate string buffer
  687. return dwLength;
  688. }
  689. DWORD
  690. GetUnicodeInstanceName (PPERF_INSTANCE_DEFINITION pInstance,
  691. LPWSTR lpszInstance)
  692. {
  693. LPWSTR wszSource;
  694. DWORD dwLength;
  695. wszSource = GetInstanceName(pInstance) ;
  696. // pInstance->NameLength == length of string in BYTES so adjust to
  697. // number of wide characters here
  698. dwLength = pInstance->NameLength / sizeof(WCHAR);
  699. wcsncpy (lpszInstance,
  700. (LPWSTR)wszSource,
  701. dwLength);
  702. // add null termination if string length does not include the null
  703. if ((dwLength > 0) && (lpszInstance[dwLength-1] != 0)) { // i.e. it's the last character of the string
  704. lpszInstance[dwLength] = 0; // then add a terminating null char to the string
  705. } else {
  706. // assume that the length value includes the terminating NULL
  707. // so adjust value to indicate chars only
  708. dwLength--;
  709. }
  710. return (dwLength); // just incase there's null's in the string
  711. }
  712. DWORD
  713. GetInstanceNameStr (PPERF_INSTANCE_DEFINITION pInstance,
  714. LPWSTR lpszInstance,
  715. DWORD dwCodePage)
  716. {
  717. DWORD dwCharSize;
  718. DWORD dwLength = 0;
  719. if (pInstance != NULL) {
  720. if (lpszInstance != NULL) {
  721. if (dwCodePage > 0) {
  722. dwCharSize = sizeof(CHAR);
  723. dwLength = GetAnsiInstanceName (pInstance, lpszInstance, dwCodePage);
  724. } else { // it's a UNICODE name
  725. dwCharSize = sizeof(WCHAR);
  726. dwLength = GetUnicodeInstanceName (pInstance, lpszInstance);
  727. }
  728. // sanity check here...
  729. // the returned string length (in characters) plus the terminating NULL
  730. // should be the same as the specified length in bytes divided by the
  731. // character size. If not then the codepage and instance data type
  732. // don't line up so test that here
  733. if ((dwLength + 1) != (pInstance->NameLength / dwCharSize)) {
  734. // something isn't quite right so try the "other" type of string type
  735. if (dwCharSize == sizeof(CHAR)) {
  736. // then we tried to read it as an ASCII string and that didn't work
  737. // so try it as a UNICODE (if that doesn't work give up and return
  738. // it any way.
  739. dwLength = GetUnicodeInstanceName (pInstance, lpszInstance);
  740. } else if (dwCharSize == sizeof(WCHAR)) {
  741. // then we tried to read it as a UNICODE string and that didn't work
  742. // so try it as an ASCII string (if that doesn't work give up and return
  743. // it any way.
  744. dwLength = GetAnsiInstanceName (pInstance, lpszInstance, dwCodePage);
  745. }
  746. }
  747. } // else return buffer is null
  748. } else {
  749. // no instance def object is specified so return an empty string
  750. *lpszInstance = 0;
  751. }
  752. return dwLength;
  753. }
  754. PERF_INSTANCE_DEFINITION *
  755. GetInstanceByNameUsingParentTitleIndex(
  756. PERF_DATA_BLOCK *pDataBlock,
  757. PERF_OBJECT_TYPE *pObjectDef,
  758. LPWSTR pInstanceName,
  759. LPWSTR pParentName,
  760. DWORD dwIndex
  761. )
  762. {
  763. BOOL fHaveParent;
  764. PERF_OBJECT_TYPE *pParentObj;
  765. PERF_INSTANCE_DEFINITION *pParentInst,
  766. *pInstanceDef;
  767. LONG NumInstance;
  768. DWORD dwLocalIndex;
  769. DWORD dwInstanceNameLength;
  770. fHaveParent = FALSE;
  771. pInstanceDef = FirstInstance(pObjectDef);
  772. if (pInstanceDef == NULL) return NULL;
  773. dwLocalIndex = dwIndex;
  774. dwInstanceNameLength = lstrlenW(pInstanceName);
  775. for ( NumInstance = 0;
  776. NumInstance < pObjectDef->NumInstances;
  777. NumInstance++ )
  778. {
  779. if (IsMatchingInstance (pInstanceDef,
  780. pObjectDef->CodePage,
  781. pInstanceName,
  782. dwInstanceNameLength)) {
  783. // Instance name matches
  784. if ( pParentName == NULL )
  785. {
  786. // No parent, we're done if this is the right "copy"
  787. if (dwLocalIndex == 0) {
  788. return pInstanceDef;
  789. } else {
  790. --dwLocalIndex;
  791. }
  792. }
  793. else
  794. {
  795. // Must match parent as well
  796. pParentObj = GetObjectDefByTitleIndex(
  797. pDataBlock,
  798. pInstanceDef->ParentObjectTitleIndex);
  799. if (!pParentObj)
  800. {
  801. // can't locate the parent, forget it
  802. break ;
  803. }
  804. // Object type of parent found; now find parent
  805. // instance
  806. pParentInst = GetInstance(pParentObj,
  807. pInstanceDef->ParentObjectInstance);
  808. if (!pParentInst)
  809. {
  810. // can't locate the parent instance, forget it
  811. break ;
  812. }
  813. if (IsMatchingInstance (pParentInst,
  814. pParentObj->CodePage,
  815. pParentName, 0)) {
  816. // Parent Instance Name matches that passed in
  817. if (dwLocalIndex == 0) {
  818. return pInstanceDef;
  819. } else {
  820. --dwLocalIndex;
  821. }
  822. }
  823. }
  824. }
  825. pInstanceDef = NextInstance(pInstanceDef);
  826. if (pInstanceDef == NULL) return NULL;
  827. }
  828. return 0;
  829. }
  830. PERF_INSTANCE_DEFINITION *
  831. GetInstanceByName(
  832. PERF_DATA_BLOCK *pDataBlock,
  833. PERF_OBJECT_TYPE *pObjectDef,
  834. LPWSTR pInstanceName,
  835. LPWSTR pParentName,
  836. DWORD dwIndex
  837. )
  838. {
  839. BOOL fHaveParent;
  840. PERF_OBJECT_TYPE *pParentObj;
  841. PERF_INSTANCE_DEFINITION *pParentInst,
  842. *pInstanceDef;
  843. LONG NumInstance;
  844. DWORD dwLocalIndex;
  845. DWORD dwInstanceNameLength;
  846. fHaveParent = FALSE;
  847. pInstanceDef = FirstInstance(pObjectDef);
  848. if (pInstanceDef == NULL) return NULL;
  849. dwLocalIndex = dwIndex;
  850. assert (pInstanceDef != NULL);
  851. dwInstanceNameLength = lstrlenW(pInstanceName);
  852. for ( NumInstance = 0;
  853. NumInstance < pObjectDef->NumInstances;
  854. NumInstance++ ) {
  855. if (IsMatchingInstance (pInstanceDef,
  856. pObjectDef->CodePage,
  857. pInstanceName,
  858. dwInstanceNameLength)) {
  859. // Instance name matches
  860. if (( !pInstanceDef->ParentObjectTitleIndex ) || (pParentName == NULL)){
  861. // No parent, we're done
  862. if (dwLocalIndex == 0) {
  863. return pInstanceDef;
  864. } else {
  865. --dwLocalIndex;
  866. }
  867. } else {
  868. // Must match parent as well
  869. pParentObj = GetObjectDefByTitleIndex(
  870. pDataBlock,
  871. pInstanceDef->ParentObjectTitleIndex);
  872. // if parent object is not found,
  873. // then exit and return NULL
  874. if (pParentObj == NULL) return NULL;
  875. // Object type of parent found; now find parent
  876. // instance
  877. pParentInst = GetInstance(pParentObj,
  878. pInstanceDef->ParentObjectInstance);
  879. if (pParentInst != NULL) {
  880. if (IsMatchingInstance (pParentInst,
  881. pParentObj->CodePage,
  882. pParentName, 0)) {
  883. // Parent Instance Name matches that passed in
  884. if (dwLocalIndex == 0) {
  885. return pInstanceDef;
  886. } else {
  887. --dwLocalIndex;
  888. }
  889. }
  890. } else {
  891. // continue
  892. }
  893. }
  894. }
  895. pInstanceDef = NextInstance(pInstanceDef);
  896. if (pInstanceDef == NULL) return NULL;
  897. }
  898. return 0;
  899. } // GetInstanceByName
  900. PERF_COUNTER_DEFINITION *
  901. GetCounterDefByName (
  902. IN PERF_OBJECT_TYPE *pObject,
  903. IN DWORD dwLastNameIndex,
  904. IN LPWSTR *NameArray,
  905. IN LPWSTR szCounterName
  906. )
  907. {
  908. DWORD NumTypeDef;
  909. PERF_COUNTER_DEFINITION *pThisCounter;
  910. pThisCounter = FirstCounter(pObject);
  911. // no counter found so bail out
  912. if (pThisCounter == NULL) return NULL;
  913. for ( NumTypeDef = 0;
  914. NumTypeDef < pObject->NumCounters;
  915. NumTypeDef++ ) {
  916. if ((pThisCounter->CounterNameTitleIndex > 0) &&
  917. (pThisCounter->CounterNameTitleIndex < dwLastNameIndex )) {
  918. // look up name of counter & compare
  919. if (lstrcmpiW(NameArray[pThisCounter->CounterNameTitleIndex],
  920. szCounterName) == 0) {
  921. return pThisCounter;
  922. }
  923. }
  924. pThisCounter = NextCounter(pThisCounter); // get next
  925. if (pThisCounter == NULL) return NULL;
  926. }
  927. return NULL;
  928. }
  929. PERF_COUNTER_DEFINITION *
  930. GetCounterDefByTitleIndex(
  931. IN PERF_OBJECT_TYPE *pObjectDef,
  932. IN BOOL bBaseCounterDef,
  933. IN DWORD CounterTitleIndex
  934. )
  935. {
  936. DWORD NumCounters;
  937. PERF_COUNTER_DEFINITION * pCounterDef;
  938. pCounterDef = FirstCounter(pObjectDef);
  939. if (pCounterDef == NULL) return NULL;
  940. for ( NumCounters = 0;
  941. NumCounters < pObjectDef->NumCounters;
  942. NumCounters++ ) {
  943. if ( pCounterDef->CounterNameTitleIndex == CounterTitleIndex ) {
  944. if (bBaseCounterDef) {
  945. // get next definition block
  946. if (++NumCounters < pObjectDef->NumCounters) {
  947. // then it should be in there
  948. pCounterDef = NextCounter(pCounterDef);
  949. if (pCounterDef) {
  950. assert (pCounterDef->CounterType & PERF_COUNTER_BASE);
  951. // make sure this is really a base counter
  952. if (!(pCounterDef->CounterType & PERF_COUNTER_BASE)) {
  953. // it's not and it should be so return NULL
  954. pCounterDef = NULL;
  955. }
  956. }
  957. }
  958. } else {
  959. // found so return it as is
  960. }
  961. return pCounterDef;
  962. }
  963. pCounterDef = NextCounter(pCounterDef);
  964. if (pCounterDef == NULL) return NULL;
  965. }
  966. return NULL;
  967. }
  968. #pragma warning ( disable : 4127 )
  969. LONG
  970. GetSystemPerfData (
  971. IN HKEY hKeySystem,
  972. IN PPERF_DATA_BLOCK *ppPerfData,
  973. IN LPWSTR szObjectList,
  974. IN BOOL bCollectCostlyData
  975. )
  976. { // GetSystemPerfData
  977. LONG lError = ERROR_SUCCESS;
  978. DWORD Size;
  979. DWORD Type;
  980. PPERF_DATA_BLOCK pCostlyPerfData;
  981. DWORD CostlySize;
  982. LPDWORD pdwSrc, pdwDest, pdwLast;
  983. if (*ppPerfData == NULL) {
  984. *ppPerfData = G_ALLOC (INITIAL_SIZE);
  985. if (*ppPerfData == NULL) return PDH_MEMORY_ALLOCATION_FAILURE;
  986. }
  987. __try {
  988. while (TRUE) {
  989. Size = (DWORD)HeapSize (hPdhHeap, 0, *ppPerfData);
  990. lError = RegQueryValueExW (
  991. hKeySystem,
  992. szObjectList,
  993. RESERVED,
  994. &Type,
  995. (LPBYTE)*ppPerfData,
  996. &Size);
  997. if ((!lError) &&
  998. (Size > 0) &&
  999. ((*ppPerfData)->Signature[0] == (WCHAR)'P') &&
  1000. ((*ppPerfData)->Signature[1] == (WCHAR)'E') &&
  1001. ((*ppPerfData)->Signature[2] == (WCHAR)'R') &&
  1002. ((*ppPerfData)->Signature[3] == (WCHAR)'F')) {
  1003. if (bCollectCostlyData) {
  1004. // collect the costly counters now
  1005. // the size available is that not used by the above call
  1006. CostlySize = (DWORD)HeapSize (hPdhHeap, 0, *ppPerfData) - Size;
  1007. pCostlyPerfData =
  1008. (PPERF_DATA_BLOCK)((LPBYTE)(*ppPerfData) + Size);
  1009. lError = RegQueryValueExW (
  1010. hKeySystem,
  1011. cszCostly,
  1012. RESERVED,
  1013. &Type,
  1014. (LPBYTE)pCostlyPerfData,
  1015. &CostlySize);
  1016. if ((!lError) &&
  1017. (CostlySize > 0) &&
  1018. (pCostlyPerfData->Signature[0] == (WCHAR)'P') &&
  1019. (pCostlyPerfData->Signature[1] == (WCHAR)'E') &&
  1020. (pCostlyPerfData->Signature[2] == (WCHAR)'R') &&
  1021. (pCostlyPerfData->Signature[3] == (WCHAR)'F')) {
  1022. // update the header block
  1023. (*ppPerfData)->TotalByteLength +=
  1024. pCostlyPerfData->TotalByteLength -
  1025. pCostlyPerfData->HeaderLength;
  1026. (*ppPerfData)->NumObjectTypes +=
  1027. pCostlyPerfData->NumObjectTypes;
  1028. // move the costly data to the end of the global data
  1029. pdwSrc = (LPDWORD)((LPBYTE)pCostlyPerfData +
  1030. pCostlyPerfData->HeaderLength);
  1031. pdwDest = (LPDWORD)pCostlyPerfData ;
  1032. pdwLast = (LPDWORD)((LPBYTE)pCostlyPerfData +
  1033. pCostlyPerfData->TotalByteLength -
  1034. pCostlyPerfData->HeaderLength);
  1035. while (pdwSrc < pdwLast) {*pdwDest++ = *pdwSrc++;}
  1036. lError = ERROR_SUCCESS;
  1037. break;
  1038. }
  1039. } else {
  1040. lError = ERROR_SUCCESS;
  1041. break;
  1042. }
  1043. }
  1044. if (lError == ERROR_MORE_DATA) {
  1045. Size = (DWORD)HeapSize (hPdhHeap, 0, *ppPerfData);
  1046. G_FREE (*ppPerfData);
  1047. *ppPerfData = NULL;
  1048. *ppPerfData = G_ALLOC ((Size + EXTEND_SIZE));
  1049. if (*ppPerfData == NULL) {
  1050. lError = PDH_MEMORY_ALLOCATION_FAILURE;
  1051. break;
  1052. }
  1053. } else {
  1054. break;
  1055. }
  1056. }
  1057. } __except (EXCEPTION_EXECUTE_HANDLER) {
  1058. lError = GetExceptionCode();
  1059. }
  1060. return lError;
  1061. } // GetSystemPerfData
  1062. #pragma warning ( default : 4127 )
  1063. DWORD
  1064. GetFullInstanceNameStr (
  1065. PERF_DATA_BLOCK *pPerfData,
  1066. PERF_OBJECT_TYPE *pObjectDef,
  1067. PERF_INSTANCE_DEFINITION *pInstanceDef,
  1068. LPWSTR szInstanceName
  1069. )
  1070. {
  1071. WCHAR szInstanceNameString[1024];
  1072. WCHAR szParentNameString[1024];
  1073. // compile instance name.
  1074. // the instance name can either be just
  1075. // the instance name itself or it can be
  1076. // the concatenation of the parent instance,
  1077. // a delimiting char (backslash) followed by
  1078. // the instance name
  1079. DWORD dwLength = 0;
  1080. PERF_OBJECT_TYPE * pParentObjectDef;
  1081. PERF_INSTANCE_DEFINITION * pParentInstanceDef;
  1082. ZeroMemory(szInstanceNameString, sizeof(WCHAR) * 1024);
  1083. ZeroMemory(szParentNameString, sizeof(WCHAR) * 1024);
  1084. if (pInstanceDef->UniqueID == PERF_NO_UNIQUE_ID) {
  1085. dwLength = GetInstanceNameStr (pInstanceDef,
  1086. szInstanceNameString,
  1087. pObjectDef->CodePage);
  1088. } else {
  1089. // make a string out of the unique ID
  1090. _ltow (pInstanceDef->UniqueID, szInstanceNameString, 10);
  1091. dwLength = lstrlenW (szInstanceNameString);
  1092. }
  1093. if (dwLength > 0) {
  1094. if (pInstanceDef->ParentObjectTitleIndex > 0) {
  1095. // then add in parent instance name
  1096. pParentObjectDef = GetObjectDefByTitleIndex (
  1097. pPerfData,
  1098. pInstanceDef->ParentObjectTitleIndex);
  1099. if (pParentObjectDef != NULL) {
  1100. pParentInstanceDef = GetInstance (
  1101. pParentObjectDef,
  1102. pInstanceDef->ParentObjectInstance);
  1103. assert ((ULONG_PTR)pParentObjectDef != (DWORD)0xFFFFFFFF);
  1104. if (pParentInstanceDef != NULL) {
  1105. if (pParentInstanceDef->UniqueID == PERF_NO_UNIQUE_ID) {
  1106. dwLength += GetInstanceNameStr (pParentInstanceDef,
  1107. szParentNameString,
  1108. pParentObjectDef->CodePage);
  1109. } else {
  1110. // make a string out of the unique ID
  1111. _ltow (pParentInstanceDef->UniqueID, szParentNameString, 10);
  1112. dwLength += lstrlenW (szParentNameString);
  1113. }
  1114. lstrcatW (szParentNameString, cszSlash);
  1115. dwLength += 1;
  1116. lstrcatW (szParentNameString, szInstanceNameString);
  1117. lstrcpyW (szInstanceName, szParentNameString);
  1118. } else {
  1119. lstrcpyW (szInstanceName, szInstanceNameString);
  1120. }
  1121. } else {
  1122. lstrcpyW (szInstanceName, szInstanceNameString);
  1123. }
  1124. } else {
  1125. lstrcpyW (szInstanceName, szInstanceNameString);
  1126. }
  1127. }
  1128. return dwLength;
  1129. }
  1130. #if DBG
  1131. #define DEBUG_BUFFER_LENGTH 1024
  1132. UCHAR PdhDebugBuffer[DEBUG_BUFFER_LENGTH];
  1133. // debug level:
  1134. // 5 = memory allocs (if _VALIDATE_PDH_MEM_ALLOCS defined) and all 4's
  1135. // 4 = function entry and exits (w/ status codes) and all 3's
  1136. // 3 = Not impl
  1137. // 2 = Not impl
  1138. // 1 = Not impl
  1139. // 0 = No messages
  1140. ULONG pdhDebugLevel = 0;
  1141. VOID
  1142. __cdecl
  1143. PdhDebugPrint(
  1144. ULONG DebugPrintLevel,
  1145. char * DebugMessage,
  1146. ...
  1147. )
  1148. {
  1149. va_list ap;
  1150. if ((DebugPrintLevel <= (pdhDebugLevel & 0x0000ffff)) ||
  1151. ((1 << (DebugPrintLevel + 15)) & pdhDebugLevel)) {
  1152. DbgPrint("%d:PDH!", GetCurrentThreadId());
  1153. }
  1154. else return;
  1155. va_start(ap, DebugMessage);
  1156. _vsnprintf((PCHAR)PdhDebugBuffer, DEBUG_BUFFER_LENGTH, DebugMessage, ap);
  1157. DbgPrint((PCHAR)PdhDebugBuffer);
  1158. va_end(ap);
  1159. }
  1160. #endif // DBG