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.

1316 lines
38 KiB

  1. /*++
  2. Copyright (c) 1991-1993 Microsoft Corporation
  3. Module Name:
  4. ctrlist.c
  5. Abstract:
  6. Program to read the current perfmon counters and dump a list of
  7. objects and counters returned by the registry
  8. Author:
  9. Bob Watson (a-robw) 4 Dec 92
  10. Revision History:
  11. HonWah Chan May 22, 93 - added more features
  12. HonWah Chan Oct 18, 93 - added check for perflib version.
  13. Old version --> get names from registry
  14. New version --> get names from PerfLib thru HKEY_PERFORMANCE_DATA
  15. Bob Watson (a-robw) 1 Dec 95 added new counter types
  16. --*/
  17. #define UNICODE 1
  18. #include <assert.h>
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <windows.h>
  23. #include <winperf.h>
  24. #include <ntprfctr.h>
  25. #include <wbemutil.h>
  26. #define MAX_LEVEL 400
  27. LPSTR DetailLevelStr[] = { "Novice", "Advanced", "Expert", "Wizard"};
  28. // LPCWSTR lpwszDiskPerfKey = (LPCWSTR)L"SYSTEM\\CurrentControlSet\\Services\\Diskperf";
  29. LPCWSTR NamesKey = (LPCWSTR)L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib";
  30. LPCWSTR DefaultLangId = (LPCWSTR)L"009";
  31. LPCWSTR Counters = (LPCWSTR)L"Counters";
  32. LPCWSTR Help = (LPCWSTR)L"Help";
  33. LPCWSTR LastHelp = (LPCWSTR)L"Last Help";
  34. LPCWSTR LastCounter = (LPCWSTR)L"Last Counter";
  35. LPCWSTR Slash = (LPCWSTR)L"\\";
  36. // the following strings are for getting texts from perflib
  37. #define OLD_VERSION 0x010000
  38. LPCWSTR VersionName = (LPCWSTR)L"Version";
  39. LPCWSTR CounterName = (LPCWSTR)L"Counter ";
  40. LPCWSTR HelpName = (LPCWSTR)L"Explain ";
  41. #define RESERVED 0L
  42. #define INITIAL_SIZE (1024*64)
  43. #define EXTEND_SIZE (1024*16)
  44. #define LINE_LENGTH 80
  45. #define WRAP_POINT LINE_LENGTH-12
  46. typedef LPVOID LPMEMORY;
  47. typedef HGLOBAL HMEMORY;
  48. #define MemoryAllocate(x) ((LPMEMORY)GlobalAlloc(GPTR, x))
  49. #define MemoryFree(x) ((VOID)GlobalFree(x))
  50. #define MemorySize(x) ((x != NULL) ? (DWORD)GlobalSize(x) : (DWORD)0)
  51. #define MemoryResize(x,y) ((LPMEMORY)GlobalReAlloc(x,y,GMEM_MOVEABLE));
  52. LPWSTR *lpCounterText;
  53. LPWSTR *lpDisplayText;
  54. TCHAR szComputerName[MAX_COMPUTERNAME_LENGTH+1];
  55. const CHAR PerfCounterCounter[] = "PERF_COUNTER_COUNTER";
  56. const CHAR PerfCounterTimer[] = "PERF_COUNTER_TIMER";
  57. const CHAR PerfCounterQueueLen[] = "PERF_COUNTER_QUEUELEN_TYPE";
  58. const CHAR PerfCounterLargeQueueLen[] = "PERF_COUNTER_LARGE_QUEUELEN_TYPE";
  59. const CHAR PerfCounterBulkCount[] = "PERF_COUNTER_BULK_COUNT";
  60. const CHAR PerfCounterText[] = "PERF_COUNTER_TEXT";
  61. const CHAR PerfCounterRawcount[] = "PERF_COUNTER_RAWCOUNT";
  62. const CHAR PerfCounterRawcountHex[] = "PERF_COUNTER_RAWCOUNT_HEX";
  63. const CHAR PerfCounterLargeRawcount[] = "PERF_COUNTER_LARGE_RAWCOUNT";
  64. const CHAR PerfCounterLargeRawcountHex[] = "PERF_COUNTER_LARGE_RAWCOUNT_HEX";
  65. const CHAR PerfSampleFraction[] = "PERF_SAMPLE_FRACTION";
  66. const CHAR PerfSampleCounter[] = "PERF_SAMPLE_COUNTER";
  67. const CHAR PerfCounterNodata[] = "PERF_COUNTER_NODATA";
  68. const CHAR PerfCounterTimerInv[] = "PERF_COUNTER_TIMER_INV";
  69. const CHAR PerfSampleBase[] = "PERF_SAMPLE_BASE";
  70. const CHAR PerfAverageTimer[] = "PERF_AVERAGE_TIMER";
  71. const CHAR PerfAverageBase[] = "PERF_AVERAGE_BASE";
  72. const CHAR PerfAverageBulk[] = "PERF_AVERAGE_BULK";
  73. const CHAR Perf100nsecTimer[] = "PERF_100NSEC_TIMER";
  74. const CHAR Perf100nsecTimerInv[] = "PERF_100NSEC_TIMER_INV";
  75. const CHAR PerfCounterMultiTimer[] = "PERF_COUNTER_MULTI_TIMER";
  76. const CHAR PerfCounterMultiTimerInv[] = "PERF_COUNTER_MULTI_TIMER_INV";
  77. const CHAR PerfCounterMultiBase[] = "PERF_COUNTER_MULTI_BASE";
  78. const CHAR Perf100nsecMultiTimer[] = "PERF_100NSEC_MULTI_TIMER";
  79. const CHAR Perf100nsecMultiTimerInv[] = "PERF_100NSEC_MULTI_TIMER_INV";
  80. const CHAR PerfRawFraction[] = "PERF_RAW_FRACTION";
  81. const CHAR PerfRawBase[] = "PERF_RAW_BASE";
  82. const CHAR PerfElapsedTime[] = "PERF_ELAPSED_TIME";
  83. const CHAR PerfCounterHistogramType[] = "PERF_COUNTER_HISTOGRAM_TYPE";
  84. const CHAR PerfCounterDelta[] = "PERF_COUNTER_DELTA";
  85. const CHAR PerfCounterLargeDelta[] = "PERF_COUNTER_LARGE_DELTA";
  86. const CHAR NotDefineCounterType[] = " ";
  87. const CHAR PerfCounter100NsQueLenType[] = "PERF_COUNTER_100NS_QUEUELEN_TYPE";
  88. const CHAR PerfCounterObjTimeQueLenType[] = "PERF_COUNTER_OBJ_TIME_QUEUELEN_TYPE";
  89. const CHAR PerfObjTimeTimer[] = "PERF_OBJ_TIME_TIMER";
  90. const CHAR PerfLargeRawFraction[] = "PERF_LARGE_RAW_FRACTION";
  91. const CHAR PerfLargeRawBase[] = "PERF_LARGE_RAW_BASE";
  92. const CHAR PerfPrecisionSystemTimer[] = "PERF_PRECISION_SYSTEM_TIMER";
  93. const CHAR PerfPrecision100NsTimer[] = "PERF_PRECISION_100NS_TIMER";
  94. const CHAR PerfPrecisionObjectTimer[] = "PERF_PRECISION_OBJECT_TIMER";
  95. BOOL bFormatCSV = FALSE;
  96. BOOL bFormatMOF = FALSE;
  97. BOOL bPrintMOFData = FALSE;
  98. BOOL bCheckCtrType = FALSE;
  99. //
  100. // Object Record Fields are:
  101. // Record Type = "O" for Object Record
  102. // Object name string ID
  103. // Object Name in selected language
  104. // Object Detail Level string (in english)
  105. // has Instance Records [1= yes, 0= no]
  106. // Object Instance Code Page [0 = unicode]
  107. // Help text ID
  108. // Help text
  109. //
  110. const CHAR fmtObjectRecord[] =
  111. "\n\"O\",\"%d\",\"%ws\",\"%s\",\"%d\",\"%d\",\"%d\",\"%ws\"";
  112. //
  113. // Counter Record Fields are:
  114. // Record Type = "C" for Counter Record
  115. // Object name string ID { these fields are used as links
  116. // Object Name in selected language { to object info records
  117. // Counter name string ID
  118. // Counter name text in selected language
  119. // Counter Detail Level string (in english)
  120. // Counter Type value as a HEX string
  121. // Counter Type Name
  122. // Counter Data field size in bytes
  123. // Counter Visibility [1= listed in list box, 0=hidden]
  124. // Counter Help text ID
  125. // Counter Help text
  126. //
  127. const CHAR fmtCounterRecord[] =
  128. "\n\"C\",\"%d\",\"%ws\",\"%d\",\"%ws\",\"%s\",\"0x%8.8x\",\"%s\",\"%d\",\"%d\",\"%d\",\"%ws\"";
  129. __inline
  130. static
  131. PPERF_OBJECT_TYPE
  132. FirstObject (
  133. PPERF_DATA_BLOCK pPerfData
  134. )
  135. {
  136. return ((PPERF_OBJECT_TYPE) ((PBYTE) pPerfData + pPerfData->HeaderLength));
  137. }
  138. __inline
  139. static
  140. PPERF_OBJECT_TYPE
  141. NextObject (
  142. PPERF_OBJECT_TYPE pObject
  143. )
  144. { // NextObject
  145. return ((PPERF_OBJECT_TYPE) ((PBYTE) pObject + pObject->TotalByteLength));
  146. } // NextObject
  147. __inline
  148. static
  149. PERF_COUNTER_DEFINITION *
  150. FirstCounter(
  151. PERF_OBJECT_TYPE *pObjectDef
  152. )
  153. {
  154. return (PERF_COUNTER_DEFINITION *)
  155. ((PCHAR) pObjectDef + pObjectDef->HeaderLength);
  156. }
  157. __inline
  158. static
  159. PERF_COUNTER_DEFINITION *
  160. NextCounter(
  161. PERF_COUNTER_DEFINITION *pCounterDef
  162. )
  163. {
  164. return (PERF_COUNTER_DEFINITION *)
  165. ((PCHAR) pCounterDef + pCounterDef->ByteLength);
  166. }
  167. __inline
  168. static
  169. BOOL
  170. ValidCtrSizeDef(
  171. PERF_COUNTER_DEFINITION *pThisCounter
  172. )
  173. {
  174. #define PERF_COUNTER_SIZE_MASK 0x00000300
  175. DWORD dwSizeValue = pThisCounter->CounterType & PERF_COUNTER_SIZE_MASK;
  176. BOOL bReturn = TRUE;
  177. if ((dwSizeValue == PERF_SIZE_DWORD) && (pThisCounter->CounterSize != sizeof(DWORD))) {
  178. bReturn = FALSE;
  179. } else if ((dwSizeValue == PERF_SIZE_LARGE) && (pThisCounter->CounterSize != sizeof(__int64))) {
  180. bReturn = FALSE;
  181. } else if ((dwSizeValue == PERF_SIZE_ZERO) && (pThisCounter->CounterSize != 0)) {
  182. bReturn = FALSE;
  183. } // else assume that the variable length value is valid
  184. return bReturn;
  185. }
  186. _inline
  187. static
  188. DWORD
  189. CtrTypeSize (
  190. PERF_COUNTER_DEFINITION *pThisCounter
  191. )
  192. {
  193. DWORD dwSizeValue = pThisCounter->CounterType & PERF_COUNTER_SIZE_MASK;
  194. switch (dwSizeValue) {
  195. case PERF_SIZE_DWORD:
  196. return sizeof(DWORD);
  197. case PERF_SIZE_LARGE:
  198. return sizeof(__int64);
  199. case PERF_SIZE_ZERO:
  200. return 0;
  201. default:
  202. return (pThisCounter->CounterSize);
  203. }
  204. }
  205. __inline
  206. static
  207. PERF_INSTANCE_DEFINITION *
  208. FirstInstance(
  209. PERF_OBJECT_TYPE * pObjectDef)
  210. {
  211. return (PERF_INSTANCE_DEFINITION * )
  212. ((PCHAR) pObjectDef + pObjectDef->DefinitionLength);
  213. }
  214. __inline
  215. static
  216. PERF_INSTANCE_DEFINITION *
  217. NextInstance(
  218. PERF_INSTANCE_DEFINITION * pInstDef)
  219. {
  220. PERF_COUNTER_BLOCK *pCounterBlock;
  221. pCounterBlock = (PERF_COUNTER_BLOCK *)
  222. ((PCHAR) pInstDef + pInstDef->ByteLength);
  223. return (PERF_INSTANCE_DEFINITION * )
  224. ((PCHAR) pCounterBlock + pCounterBlock->ByteLength);
  225. }
  226. __inline
  227. static
  228. LPCWSTR
  229. GetInstanceName(
  230. PERF_INSTANCE_DEFINITION *pInstDef
  231. )
  232. {
  233. static WCHAR szLocalName[MAX_PATH];
  234. LPWSTR szSrc, szDest;
  235. assert ((pInstDef->NameLength) < (MAX_PATH * sizeof(WCHAR)));
  236. szDest = &szLocalName[0];
  237. szSrc = (LPWSTR) ((PCHAR) pInstDef + pInstDef->NameOffset);
  238. while (*szSrc != 0) {
  239. switch (*szSrc) {
  240. case '\\':
  241. *szDest++ = *szSrc;
  242. *szDest++ = *szSrc++;
  243. break;
  244. default:
  245. *szDest++ = *szSrc++;
  246. };
  247. }
  248. *szDest++ = 0;
  249. return (LPCWSTR)&szLocalName[0];
  250. }
  251. void
  252. PrintMofHeader ()
  253. {
  254. WCHAR szPrintBuffer[8192];
  255. DWORD dwLength = 8192;
  256. DWORD dwStatus;
  257. dwStatus = GenerateMofHeader (szPrintBuffer, szComputerName, &dwLength);
  258. if (dwStatus == ERROR_SUCCESS) {
  259. printf ("%ls", szPrintBuffer);
  260. }
  261. }
  262. void
  263. PrintMofObject (
  264. PERF_OBJECT_TYPE *pPerfObject,
  265. BOOL bRawDefinition,
  266. BOOL bCostlyObject,
  267. BOOL bDefaultObject
  268. )
  269. {
  270. WCHAR szPrintBuffer[8192*2];
  271. DWORD dwLength = 8192*2;
  272. DWORD dwStatus;
  273. DWORD dwFlags;
  274. dwFlags = 0;
  275. dwFlags |= (bRawDefinition ? WM_GMO_RAW_DEFINITION : 0);
  276. dwFlags |= (bCostlyObject ? WM_GMO_COSTLY_OBJECT : 0);
  277. dwFlags |= (bDefaultObject ? WM_GMO_DEFAULT_OBJECT : 0);
  278. dwStatus = GenerateMofObject (
  279. szPrintBuffer,
  280. &dwLength,
  281. NULL,
  282. pPerfObject,
  283. lpCounterText,
  284. lpDisplayText,
  285. dwFlags);
  286. if (dwStatus == ERROR_SUCCESS) {
  287. printf ("%ls", szPrintBuffer);
  288. }
  289. }
  290. void
  291. PrintMofCounter (
  292. PERF_COUNTER_DEFINITION *pPerfCounter,
  293. BOOL bRawDefinition,
  294. BOOL bDefaultCounter
  295. )
  296. {
  297. WCHAR szPrintBuffer[8192*2];
  298. DWORD dwLength = 8192*2;
  299. DWORD dwStatus;
  300. DWORD dwFlags;
  301. dwFlags = 0;
  302. dwFlags |= (bRawDefinition ? WM_GMO_RAW_DEFINITION : 0);
  303. dwFlags |= (bDefaultCounter ? WM_GMO_DEFAULT_COUNTER : 0);
  304. dwStatus = GenerateMofCounter (
  305. szPrintBuffer,
  306. &dwLength,
  307. pPerfCounter,
  308. lpCounterText,
  309. lpDisplayText,
  310. dwFlags);
  311. if (dwStatus == ERROR_SUCCESS) {
  312. printf ("%ls", szPrintBuffer);
  313. }
  314. }
  315. void
  316. PrintMofInstances (
  317. PERF_DATA_BLOCK * pPerfDataBlock,
  318. PERF_OBJECT_TYPE * pPerfObject,
  319. BOOL bRawDefinition
  320. )
  321. {
  322. WCHAR szPrintBuffer[8192*2];
  323. DWORD dwLength = 8192*2;
  324. DWORD dwStatus;
  325. DWORD dwFlags;
  326. dwFlags = 0;
  327. dwFlags |= (bRawDefinition ? WM_GMO_RAW_DEFINITION : 0);
  328. dwStatus = GenerateMofInstances (
  329. szPrintBuffer,
  330. &dwLength,
  331. pPerfDataBlock,
  332. pPerfObject,
  333. lpCounterText, // name strings array
  334. lpDisplayText,
  335. dwFlags);
  336. if (dwStatus == ERROR_SUCCESS) {
  337. printf ("%ls", szPrintBuffer);
  338. }
  339. }
  340. LPCSTR
  341. GetCounterType(
  342. DWORD CounterType
  343. )
  344. {
  345. switch (CounterType) {
  346. case PERF_COUNTER_COUNTER:
  347. return (PerfCounterCounter);
  348. case PERF_COUNTER_TIMER:
  349. return (PerfCounterTimer);
  350. case PERF_COUNTER_QUEUELEN_TYPE:
  351. return (PerfCounterQueueLen);
  352. case PERF_COUNTER_LARGE_QUEUELEN_TYPE:
  353. return (PerfCounterLargeQueueLen);
  354. case PERF_COUNTER_100NS_QUEUELEN_TYPE:
  355. return (PerfCounter100NsQueLenType);
  356. case PERF_COUNTER_OBJ_TIME_QUEUELEN_TYPE:
  357. return (PerfCounterObjTimeQueLenType);
  358. case PERF_COUNTER_BULK_COUNT:
  359. return (PerfCounterBulkCount);
  360. case PERF_COUNTER_TEXT:
  361. return (PerfCounterText);
  362. case PERF_COUNTER_RAWCOUNT:
  363. return (PerfCounterRawcount);
  364. case PERF_COUNTER_LARGE_RAWCOUNT:
  365. return (PerfCounterLargeRawcount);
  366. case PERF_COUNTER_RAWCOUNT_HEX:
  367. return (PerfCounterRawcountHex);
  368. case PERF_COUNTER_LARGE_RAWCOUNT_HEX:
  369. return (PerfCounterLargeRawcountHex);
  370. case PERF_SAMPLE_FRACTION:
  371. return (PerfSampleFraction);
  372. case PERF_SAMPLE_COUNTER:
  373. return (PerfSampleCounter);
  374. case PERF_COUNTER_NODATA:
  375. return (PerfCounterNodata);
  376. case PERF_COUNTER_TIMER_INV:
  377. return (PerfCounterTimerInv);
  378. case PERF_SAMPLE_BASE:
  379. return (PerfSampleBase);
  380. case PERF_AVERAGE_TIMER:
  381. return (PerfAverageTimer);
  382. case PERF_AVERAGE_BASE:
  383. return (PerfAverageBase);
  384. case PERF_AVERAGE_BULK:
  385. return (PerfAverageBulk);
  386. case PERF_OBJ_TIME_TIMER:
  387. return (PerfObjTimeTimer);
  388. case PERF_100NSEC_TIMER:
  389. return (Perf100nsecTimer);
  390. case PERF_100NSEC_TIMER_INV:
  391. return (Perf100nsecTimerInv);
  392. case PERF_COUNTER_MULTI_TIMER:
  393. return (PerfCounterMultiTimer);
  394. case PERF_COUNTER_MULTI_TIMER_INV:
  395. return (PerfCounterMultiTimerInv);
  396. case PERF_COUNTER_MULTI_BASE:
  397. return (PerfCounterMultiBase);
  398. case PERF_100NSEC_MULTI_TIMER:
  399. return (Perf100nsecMultiTimer);
  400. case PERF_100NSEC_MULTI_TIMER_INV:
  401. return (Perf100nsecMultiTimerInv);
  402. case PERF_RAW_FRACTION:
  403. return (PerfRawFraction);
  404. case PERF_LARGE_RAW_FRACTION:
  405. return (PerfLargeRawFraction);
  406. case PERF_RAW_BASE:
  407. return (PerfRawBase);
  408. case PERF_LARGE_RAW_BASE:
  409. return (PerfLargeRawBase);
  410. case PERF_ELAPSED_TIME:
  411. return (PerfElapsedTime);
  412. case PERF_COUNTER_HISTOGRAM_TYPE:
  413. return (PerfCounterHistogramType);
  414. case PERF_COUNTER_DELTA:
  415. return (PerfCounterDelta);
  416. case PERF_COUNTER_LARGE_DELTA:
  417. return (PerfCounterLargeDelta);
  418. case PERF_PRECISION_SYSTEM_TIMER:
  419. return (PerfPrecisionSystemTimer);
  420. case PERF_PRECISION_100NS_TIMER:
  421. return (PerfPrecision100NsTimer);
  422. case PERF_PRECISION_OBJECT_TIMER:
  423. return (PerfPrecisionObjectTimer);
  424. default:
  425. return (NotDefineCounterType);
  426. }
  427. }
  428. void
  429. DisplayUsage (
  430. void
  431. )
  432. {
  433. printf("\nCtrList - Lists all the objects and counters installed in\n");
  434. printf(" the system for the given language ID\n");
  435. printf("\nUsage: ctrlist [-cmd] [LangID] [\\\\machine] > <filename>\n");
  436. printf("\n -c prints data in a CSV format");
  437. printf("\n -m prints data as a WBEM MOF");
  438. printf("\n -d prints data as a WBEM MOF with perf data instances defined");
  439. printf("\n (note: only one of the above command switches may be used");
  440. printf("\n LangID - 009 for English (default)\n");
  441. printf(" - 007 for German\n");
  442. printf(" - 00A for Spanish\n");
  443. printf(" - 00C for French\n");
  444. printf(" \\\\machine may be specified to list counters on a\n");
  445. printf(" remote system\n\n");
  446. printf(" Example - \"ctrlist 00C > french.lst\" will get all the\n");
  447. printf(" objects and counters for the French system and put\n");
  448. printf(" them in the file french.lst\n");
  449. return;
  450. } /* DisplayUsage() */
  451. LPWSTR
  452. *BuildNameTable(
  453. HKEY hKeyRegistry, // handle to registry db with counter names
  454. LPWSTR lpszLangId, // unicode value of Language subkey
  455. PDWORD pdwLastItem // size of array in elements
  456. )
  457. /*++
  458. BuildNameTable
  459. Arguments:
  460. hKeyRegistry
  461. Handle to an open registry (this can be local or remote.) and
  462. is the value returned by RegConnectRegistry or a default key.
  463. lpszLangId
  464. The unicode id of the language to look up. (default is 409)
  465. Return Value:
  466. pointer to an allocated table. (the caller must free it when finished!)
  467. the table is an array of pointers to zero terminated strings. NULL is
  468. returned if an error occured.
  469. --*/
  470. {
  471. LPWSTR *lpReturnValue;
  472. LPWSTR *lpCounterId;
  473. LPWSTR lpCounterNames;
  474. LPWSTR lpHelpText;
  475. LPWSTR lpThisName;
  476. LONG lWin32Status;
  477. DWORD dwLastError;
  478. DWORD dwValueType;
  479. DWORD dwArraySize;
  480. DWORD dwBufferSize;
  481. DWORD dwCounterSize;
  482. DWORD dwHelpSize;
  483. DWORD dwThisCounter;
  484. DWORD dwSystemVersion;
  485. DWORD dwLastId;
  486. DWORD dwLastHelpId;
  487. HKEY hKeyValue;
  488. HKEY hKeyNames;
  489. LPWSTR lpValueNameString;
  490. WCHAR CounterNameBuffer [50];
  491. WCHAR HelpNameBuffer [50];
  492. lpValueNameString = NULL; //initialize to NULL
  493. lpReturnValue = NULL;
  494. hKeyValue = NULL;
  495. hKeyNames = NULL;
  496. // check for null arguments and insert defaults if necessary
  497. if (!lpszLangId) {
  498. lpszLangId = (LPWSTR)DefaultLangId;
  499. }
  500. // open registry to get number of items for computing array size
  501. lWin32Status = RegOpenKeyEx (
  502. hKeyRegistry,
  503. NamesKey,
  504. RESERVED,
  505. KEY_READ,
  506. &hKeyValue);
  507. if (lWin32Status != ERROR_SUCCESS) {
  508. goto BNT_BAILOUT;
  509. }
  510. // get number of items
  511. dwBufferSize = sizeof (dwLastHelpId);
  512. lWin32Status = RegQueryValueEx (
  513. hKeyValue,
  514. LastHelp,
  515. RESERVED,
  516. &dwValueType,
  517. (LPBYTE)&dwLastHelpId,
  518. &dwBufferSize);
  519. if ((lWin32Status != ERROR_SUCCESS) || (dwValueType != REG_DWORD)) {
  520. goto BNT_BAILOUT;
  521. }
  522. // get number of items
  523. dwBufferSize = sizeof (dwLastId);
  524. lWin32Status = RegQueryValueEx (
  525. hKeyValue,
  526. LastCounter,
  527. RESERVED,
  528. &dwValueType,
  529. (LPBYTE)&dwLastId,
  530. &dwBufferSize);
  531. if ((lWin32Status != ERROR_SUCCESS) || (dwValueType != REG_DWORD)) {
  532. goto BNT_BAILOUT;
  533. }
  534. if (dwLastId < dwLastHelpId)
  535. dwLastId = dwLastHelpId;
  536. dwArraySize = dwLastId * sizeof(LPWSTR);
  537. // get Perflib system version
  538. dwBufferSize = sizeof (dwSystemVersion);
  539. lWin32Status = RegQueryValueEx (
  540. hKeyValue,
  541. VersionName,
  542. RESERVED,
  543. &dwValueType,
  544. (LPBYTE)&dwSystemVersion,
  545. &dwBufferSize);
  546. if ((lWin32Status != ERROR_SUCCESS) || (dwValueType != REG_DWORD)) {
  547. dwSystemVersion = OLD_VERSION;
  548. }
  549. if (dwSystemVersion == OLD_VERSION) {
  550. // get names from registry
  551. lpValueNameString = MemoryAllocate (
  552. lstrlen(NamesKey) * sizeof (WCHAR) +
  553. lstrlen(Slash) * sizeof (WCHAR) +
  554. lstrlen(lpszLangId) * sizeof (WCHAR) +
  555. sizeof (UNICODE_NULL));
  556. if (!lpValueNameString) goto BNT_BAILOUT;
  557. lstrcpy (lpValueNameString, NamesKey);
  558. lstrcat (lpValueNameString, Slash);
  559. lstrcat (lpValueNameString, lpszLangId);
  560. lWin32Status = RegOpenKeyEx (
  561. hKeyRegistry,
  562. lpValueNameString,
  563. RESERVED,
  564. KEY_READ,
  565. &hKeyNames);
  566. } else {
  567. if (szComputerName[0] == 0) {
  568. hKeyNames = HKEY_PERFORMANCE_DATA;
  569. } else {
  570. lWin32Status = RegConnectRegistry (szComputerName,
  571. HKEY_PERFORMANCE_DATA,
  572. &hKeyNames);
  573. }
  574. lstrcpy (CounterNameBuffer, CounterName);
  575. lstrcat (CounterNameBuffer, lpszLangId);
  576. lstrcpy (HelpNameBuffer, HelpName);
  577. lstrcat (HelpNameBuffer, lpszLangId);
  578. }
  579. // get size of counter names and add that to the arrays
  580. if (lWin32Status != ERROR_SUCCESS) goto BNT_BAILOUT;
  581. dwBufferSize = 0;
  582. lWin32Status = RegQueryValueEx (
  583. hKeyNames,
  584. dwSystemVersion == OLD_VERSION ? Counters : CounterNameBuffer,
  585. RESERVED,
  586. &dwValueType,
  587. NULL,
  588. &dwBufferSize);
  589. if (lWin32Status != ERROR_SUCCESS) goto BNT_BAILOUT;
  590. dwCounterSize = dwBufferSize;
  591. // get size of counter names and add that to the arrays
  592. if (lWin32Status != ERROR_SUCCESS) goto BNT_BAILOUT;
  593. dwBufferSize = 0;
  594. lWin32Status = RegQueryValueEx (
  595. hKeyNames,
  596. dwSystemVersion == OLD_VERSION ? Help : HelpNameBuffer,
  597. RESERVED,
  598. &dwValueType,
  599. NULL,
  600. &dwBufferSize);
  601. if (lWin32Status != ERROR_SUCCESS) goto BNT_BAILOUT;
  602. dwHelpSize = dwBufferSize;
  603. lpReturnValue = MemoryAllocate (dwArraySize + dwCounterSize + dwHelpSize);
  604. if (!lpReturnValue) goto BNT_BAILOUT;
  605. // initialize pointers into buffer
  606. lpCounterId = lpReturnValue;
  607. lpCounterNames = (LPWSTR)((LPBYTE)lpCounterId + dwArraySize);
  608. lpHelpText = (LPWSTR)((LPBYTE)lpCounterNames + dwCounterSize);
  609. // read counters into memory
  610. dwBufferSize = dwCounterSize;
  611. lWin32Status = RegQueryValueEx (
  612. hKeyNames,
  613. dwSystemVersion == OLD_VERSION ? Counters : CounterNameBuffer,
  614. RESERVED,
  615. &dwValueType,
  616. (LPVOID)lpCounterNames,
  617. &dwBufferSize);
  618. if (!lpReturnValue) goto BNT_BAILOUT;
  619. dwBufferSize = dwHelpSize;
  620. lWin32Status = RegQueryValueEx (
  621. hKeyNames,
  622. dwSystemVersion == OLD_VERSION ? Help : HelpNameBuffer,
  623. RESERVED,
  624. &dwValueType,
  625. (LPVOID)lpHelpText,
  626. &dwBufferSize);
  627. if (!lpReturnValue) goto BNT_BAILOUT;
  628. // load counter array items
  629. for (lpThisName = lpCounterNames;
  630. *lpThisName;
  631. lpThisName += (lstrlen(lpThisName)+1) ) {
  632. // first string should be an integer (in decimal unicode digits)
  633. dwThisCounter = wcstoul (lpThisName, NULL, 10);
  634. if (dwThisCounter == 0) goto BNT_BAILOUT; // bad entry
  635. // point to corresponding counter name
  636. lpThisName += (lstrlen(lpThisName)+1);
  637. // and load array element;
  638. lpCounterId[dwThisCounter] = lpThisName;
  639. }
  640. for (lpThisName = lpHelpText;
  641. *lpThisName;
  642. lpThisName += (lstrlen(lpThisName)+1) ) {
  643. // first string should be an integer (in decimal unicode digits)
  644. dwThisCounter = wcstoul (lpThisName, NULL, 10);
  645. if (dwThisCounter == 0) goto BNT_BAILOUT; // bad entry
  646. // point to corresponding counter name
  647. lpThisName += (lstrlen(lpThisName)+1);
  648. // and load array element;
  649. lpCounterId[dwThisCounter] = lpThisName;
  650. }
  651. if (pdwLastItem) *pdwLastItem = dwLastId;
  652. MemoryFree ((LPVOID)lpValueNameString);
  653. RegCloseKey (hKeyValue);
  654. // if (dwSystemVersion == OLD_VERSION)
  655. RegCloseKey (hKeyNames);
  656. return lpReturnValue;
  657. BNT_BAILOUT:
  658. if (lWin32Status != ERROR_SUCCESS) {
  659. dwLastError = GetLastError();
  660. }
  661. if (lpValueNameString) {
  662. MemoryFree ((LPVOID)lpValueNameString);
  663. }
  664. if (lpReturnValue) {
  665. MemoryFree ((LPVOID)lpReturnValue);
  666. }
  667. if (hKeyValue) RegCloseKey (hKeyValue);
  668. // if (dwSystemVersion == OLD_VERSION &&
  669. // hKeyNames)
  670. RegCloseKey (hKeyNames);
  671. return NULL;
  672. }
  673. LONG
  674. GetEnumPerfData (
  675. IN HKEY hKeySystem,
  676. IN DWORD dwIndex,
  677. IN PPERF_DATA_BLOCK *pPerfData
  678. )
  679. { // GetSystemPerfData
  680. LONG lError ;
  681. DWORD Size;
  682. DWORD Type;
  683. if (dwIndex >= 2)
  684. return !ERROR_SUCCESS;
  685. if (*pPerfData == NULL) {
  686. *pPerfData = MemoryAllocate (INITIAL_SIZE);
  687. if (*pPerfData == NULL) {
  688. return ERROR_OUTOFMEMORY;
  689. }
  690. }
  691. #pragma warning ( disable : 4127 )
  692. while (TRUE) {
  693. Size = MemorySize (*pPerfData);
  694. lError = RegQueryValueEx (
  695. hKeySystem,
  696. dwIndex == 0 ?
  697. (LPCWSTR)L"Global" :
  698. (LPCWSTR)L"Costly",
  699. RESERVED,
  700. &Type,
  701. (LPBYTE)*pPerfData,
  702. &Size);
  703. if ((!lError) &&
  704. (Size > 0) &&
  705. (*pPerfData)->Signature[0] == (WCHAR)'P' &&
  706. (*pPerfData)->Signature[1] == (WCHAR)'E' &&
  707. (*pPerfData)->Signature[2] == (WCHAR)'R' &&
  708. (*pPerfData)->Signature[3] == (WCHAR)'F' ) {
  709. return (ERROR_SUCCESS);
  710. }
  711. if (lError == ERROR_MORE_DATA) {
  712. *pPerfData = MemoryResize (
  713. *pPerfData,
  714. MemorySize (*pPerfData) +
  715. EXTEND_SIZE);
  716. if (!*pPerfData) {
  717. return (lError);
  718. }
  719. } else {
  720. return (lError);
  721. } // else
  722. }
  723. #pragma warning ( default : 4127 )
  724. } // GetSystemPerfData
  725. LONG
  726. PrintHelpText(
  727. DWORD Indent,
  728. DWORD dwID,
  729. LPWSTR szTextString
  730. )
  731. {
  732. LPWSTR szThisChar;
  733. BOOL bNewLine;
  734. DWORD dwThisPos;
  735. DWORD dwLinesUsed;
  736. szThisChar = szTextString;
  737. dwLinesUsed = 0;
  738. // check arguments
  739. if (!szTextString) {
  740. return dwLinesUsed;
  741. }
  742. if (Indent > WRAP_POINT) {
  743. return dwLinesUsed; // can't do this
  744. }
  745. // display id number
  746. for (dwThisPos = 0; dwThisPos < Indent - 6; dwThisPos++) {
  747. putchar (' ');
  748. }
  749. dwThisPos += printf ("[%3.3d] ", dwID);
  750. bNewLine = FALSE;
  751. // print text
  752. while (*szThisChar) {
  753. if (bNewLine){
  754. for (dwThisPos = 0; dwThisPos < Indent; dwThisPos++) {
  755. putchar (' ');
  756. }
  757. bNewLine = FALSE;
  758. }
  759. if ((*szThisChar == L' ') && (dwThisPos >= WRAP_POINT)) {
  760. putchar ('\n');
  761. bNewLine = TRUE;
  762. // go to next printable character
  763. while (*szThisChar <= L' ') {
  764. szThisChar++;
  765. }
  766. dwLinesUsed++;
  767. } else {
  768. putchar (*szThisChar);
  769. szThisChar++;
  770. }
  771. dwThisPos++;
  772. }
  773. putchar ('\n');
  774. bNewLine = TRUE;
  775. dwLinesUsed++;
  776. return dwLinesUsed;
  777. }
  778. #pragma warning ( disable : 4706 )
  779. int
  780. __cdecl main(
  781. int argc,
  782. char *argv[]
  783. )
  784. {
  785. int ArgNo;
  786. DWORD dwLastElement;
  787. DWORD dwIndex;
  788. DWORD dwDisplayLevel;
  789. PPERF_DATA_BLOCK pDataBlock; // pointer to perfdata block
  790. BOOL bError;
  791. DWORD dwThisObject;
  792. DWORD dwThisCounter;
  793. CHAR LangID[10];
  794. WCHAR wLangID[10];
  795. BOOL UseDefaultID = FALSE;
  796. LPSTR szComputerNameArg = NULL;
  797. DWORD dwLoop;
  798. DWORD dwLoopEnd;
  799. DWORD dwErrorCount;
  800. DWORD dwStatus;
  801. PPERF_OBJECT_TYPE pThisObject;
  802. PPERF_COUNTER_DEFINITION pThisCounter;
  803. HKEY hKeyMachine = HKEY_LOCAL_MACHINE;
  804. HKEY hKeyPerformance = HKEY_PERFORMANCE_DATA;
  805. dwDisplayLevel = PERF_DETAIL_WIZARD;
  806. // open key to registry or use default
  807. if (argc >= 2) {
  808. if ((argv[1][0] == '-' || argv[1][0] == '/') &&
  809. argv[1][1] == '?') {
  810. DisplayUsage();
  811. return 0;
  812. }
  813. if (argv[1][0] != '\\') {
  814. if ((argv[1][0] == '-') || (argv[1][0] == '/')) {
  815. // then this is a command switch
  816. if ((argv[1][1] == 'c') || (argv[1][1] == 'C')) {
  817. // then format is a CSV
  818. bFormatCSV = TRUE;
  819. } else if ((argv[1][1] == 'm') || (argv[1][1] == 'M')) {
  820. // then format is a MOF
  821. bFormatMOF = TRUE;
  822. } else if ((argv[1][1] == 'd') || (argv[1][1] == 'D')) {
  823. // then format is a MOF w/ data
  824. bFormatMOF = TRUE;
  825. bPrintMOFData = TRUE;
  826. } else if ((argv[1][1] == 'e') || (argv[1][1] == 'E')) {
  827. bCheckCtrType = TRUE;
  828. }
  829. ArgNo = 2;
  830. } else {
  831. ArgNo = 1;
  832. }
  833. if (argc > ArgNo) {
  834. // get the lang ID
  835. if (argv[ArgNo][0] != '\\') {
  836. LangID[0] = argv[ArgNo][0];
  837. LangID[1] = argv[ArgNo][1];
  838. LangID[2] = argv[ArgNo][2];
  839. LangID[3] = '\0';
  840. mbstowcs(wLangID, LangID, 4);
  841. ++ArgNo;
  842. } else {
  843. lstrcpyW (wLangID, (LPCWSTR)L"009");
  844. }
  845. if (argc > (ArgNo)) {
  846. // see if the next arg is a computer name
  847. if (argv[ArgNo][0] == '\\') {
  848. mbstowcs (szComputerName, argv[ArgNo],
  849. MAX_COMPUTERNAME_LENGTH);
  850. szComputerNameArg = argv[ArgNo];
  851. } else {
  852. szComputerName[0] = 0;
  853. }
  854. }
  855. }
  856. } else {
  857. // 1st arg is a computer name
  858. mbstowcs (szComputerName, argv[1], MAX_COMPUTERNAME_LENGTH);
  859. szComputerNameArg = argv[1];
  860. }
  861. #if 0
  862. // get user level from command line
  863. if (argc > 2 && sscanf(argv[2], " %d", &dwDisplayLevel) == 1) {
  864. if (dwDisplayLevel <= PERF_DETAIL_NOVICE) {
  865. dwDisplayLevel = PERF_DETAIL_NOVICE;
  866. } else if (dwDisplayLevel <= PERF_DETAIL_ADVANCED) {
  867. dwDisplayLevel = PERF_DETAIL_ADVANCED;
  868. } else if (dwDisplayLevel <= PERF_DETAIL_EXPERT) {
  869. dwDisplayLevel = PERF_DETAIL_EXPERT;
  870. } else {
  871. dwDisplayLevel = PERF_DETAIL_WIZARD;
  872. }
  873. } else {
  874. dwDisplayLevel = PERF_DETAIL_WIZARD;
  875. }
  876. #endif
  877. } else {
  878. UseDefaultID = TRUE;
  879. szComputerName[0] = 0;
  880. }
  881. if (szComputerName[0] != 0) {
  882. if (RegConnectRegistry (szComputerName, HKEY_LOCAL_MACHINE,
  883. &hKeyMachine) != ERROR_SUCCESS) {
  884. printf ("\nUnable to connect to %s", szComputerNameArg);
  885. return 0;
  886. }
  887. dwStatus = RegConnectRegistry (szComputerName, HKEY_PERFORMANCE_DATA,
  888. &hKeyPerformance);
  889. if (dwStatus != ERROR_SUCCESS) {
  890. printf ("\nUnable to connect to %s", szComputerNameArg);
  891. return 0;
  892. }
  893. } else {
  894. // use default initializations
  895. }
  896. lpCounterText = BuildNameTable (
  897. hKeyMachine,
  898. (LPWSTR)(DefaultLangId), // counter text is in ENGLISH always
  899. &dwLastElement);
  900. if (!lpCounterText) {
  901. printf("***FAILure*** Cannot open the registry\n");
  902. return 0;
  903. }
  904. lpDisplayText = BuildNameTable (
  905. hKeyMachine,
  906. (LPWSTR)(UseDefaultID ? DefaultLangId : wLangID),
  907. &dwLastElement);
  908. if (!lpDisplayText) {
  909. printf("***FAILure*** Cannot open the registry\n");
  910. return 0;
  911. }
  912. if (bFormatMOF) {
  913. // then print the header block
  914. PrintMofHeader ();
  915. }
  916. // get a performance data buffer with counters
  917. pDataBlock = 0;
  918. for (dwIndex = 0; (bError = GetEnumPerfData (
  919. hKeyPerformance,
  920. dwIndex,
  921. &pDataBlock) == ERROR_SUCCESS); dwIndex++) {
  922. for (dwThisObject = 0, pThisObject = FirstObject (pDataBlock);
  923. dwThisObject < pDataBlock->NumObjectTypes;
  924. dwThisObject++, pThisObject = NextObject(pThisObject)) {
  925. if (bFormatMOF) {
  926. if (bPrintMOFData) {
  927. dwLoopEnd = 2;
  928. } else {
  929. dwLoopEnd = 1;
  930. }
  931. } else {
  932. dwLoopEnd = 0;
  933. }
  934. dwLoop = 0;
  935. do {
  936. if (bFormatCSV) {
  937. printf (fmtObjectRecord,
  938. pThisObject->ObjectNameTitleIndex,
  939. lpDisplayText[pThisObject->ObjectNameTitleIndex],
  940. pThisObject->DetailLevel <= MAX_LEVEL ?
  941. DetailLevelStr[pThisObject->DetailLevel/100-1] :
  942. "<N\\A>",
  943. pThisObject->NumInstances == PERF_NO_INSTANCES ?
  944. 0 : 1,
  945. pThisObject->CodePage,
  946. pThisObject->ObjectHelpTitleIndex,
  947. lpDisplayText[pThisObject->ObjectHelpTitleIndex]);
  948. } else if (bFormatMOF) {
  949. if (dwLoop < 2) PrintMofObject (pThisObject,
  950. (dwLoop == 0 ? FALSE : TRUE),
  951. (dwIndex == 0 ? FALSE : TRUE),
  952. ((DWORD)pDataBlock->DefaultObject ==
  953. pThisObject->ObjectNameTitleIndex ? TRUE : FALSE));
  954. } else {
  955. printf ("\nObject: \"%ws\" [%3.3d]",
  956. lpDisplayText[pThisObject->ObjectNameTitleIndex],
  957. pThisObject->ObjectNameTitleIndex);
  958. if (!bCheckCtrType) {
  959. printf ("\n Detail Level: %s\n",
  960. pThisObject->DetailLevel <= MAX_LEVEL ?
  961. DetailLevelStr[pThisObject->DetailLevel/100-1] :
  962. "<N\\A>");
  963. PrintHelpText (9,
  964. pThisObject->ObjectHelpTitleIndex,
  965. lpDisplayText[pThisObject->ObjectHelpTitleIndex]);
  966. }
  967. }
  968. dwErrorCount = 0;
  969. for (dwThisCounter = 0, pThisCounter = FirstCounter(pThisObject);
  970. dwThisCounter < pThisObject->NumCounters;
  971. dwThisCounter++, pThisCounter = NextCounter(pThisCounter)) {
  972. __try {
  973. if (pThisCounter->DetailLevel <= dwDisplayLevel) {
  974. if (bFormatCSV) {
  975. printf (fmtCounterRecord,
  976. pThisObject->ObjectNameTitleIndex,
  977. lpDisplayText[pThisObject->ObjectNameTitleIndex],
  978. pThisCounter->CounterNameTitleIndex,
  979. lpDisplayText[pThisCounter->CounterNameTitleIndex],
  980. ((pThisCounter->DetailLevel <= MAX_LEVEL) &&
  981. (pThisCounter->DetailLevel > 0 )) ?
  982. DetailLevelStr[pThisCounter->DetailLevel/100-1] :
  983. "<N\\A>",
  984. pThisCounter->CounterType,
  985. GetCounterType(pThisCounter->CounterType),
  986. pThisCounter->CounterSize,
  987. IsDisplayableType(pThisCounter->CounterType) ?
  988. 1 : 0,
  989. pThisCounter->CounterHelpTitleIndex,
  990. lpDisplayText[pThisCounter->CounterHelpTitleIndex]);
  991. } else if (bFormatMOF) {
  992. if (dwLoop < 2) {
  993. PrintMofCounter (pThisCounter,
  994. (dwLoop == 0 ? FALSE : TRUE),
  995. (dwThisCounter == (DWORD)pThisObject->DefaultCounter ? TRUE : FALSE));
  996. }
  997. } else if (bCheckCtrType) {
  998. if (!ValidCtrSizeDef(pThisCounter)) {
  999. printf ("\n [%3.3d] \"%ws\" data size should be %d bytes, but reports a size of %d bytes",
  1000. pThisCounter->CounterNameTitleIndex,
  1001. lpDisplayText[pThisCounter->CounterNameTitleIndex],
  1002. CtrTypeSize (pThisCounter),
  1003. pThisCounter->CounterSize);
  1004. dwErrorCount++;
  1005. }
  1006. } else {
  1007. printf ("\n <%ws> [%3.3d]",
  1008. lpDisplayText[pThisCounter->CounterNameTitleIndex],
  1009. pThisCounter->CounterNameTitleIndex);
  1010. printf ("\n Default Scale: %d",
  1011. pThisCounter->DefaultScale);
  1012. printf ("\n Detail Level: %s",
  1013. ((pThisCounter->DetailLevel <= MAX_LEVEL) &&
  1014. (pThisCounter->DetailLevel > 0 ))?
  1015. DetailLevelStr[pThisCounter->DetailLevel/100-1] :
  1016. "<N\\A>");
  1017. printf ("\n Counter Type: 0x%x, %s",
  1018. pThisCounter->CounterType,
  1019. GetCounterType(pThisCounter->CounterType));
  1020. printf ("\n Counter Size: %d bytes",
  1021. pThisCounter->CounterSize);
  1022. printf ("\n");
  1023. PrintHelpText (16,
  1024. pThisCounter->CounterHelpTitleIndex,
  1025. lpDisplayText[pThisCounter->CounterHelpTitleIndex]);
  1026. }
  1027. } // end if the right detail level
  1028. } __except (EXCEPTION_EXECUTE_HANDLER) {
  1029. if (!bFormatCSV) {
  1030. printf ("\n Error (%d) reading this counter",
  1031. GetExceptionCode());
  1032. }
  1033. }
  1034. } // end for each counter
  1035. if ((dwLoop == 2) && bFormatMOF) {
  1036. // dump data for raw classes only
  1037. PrintMofInstances (pDataBlock, pThisObject, TRUE);
  1038. }
  1039. // close up object text
  1040. if ((bFormatMOF) && (dwLoop != 2)) {
  1041. //{ brace inserted to not throw off the brace counter
  1042. printf("\n};\n");
  1043. }
  1044. if (bCheckCtrType) {
  1045. printf ("\n %d bad counters in this object.\n",
  1046. dwErrorCount);
  1047. } else {
  1048. printf ("\n");
  1049. }
  1050. } while (dwLoop++ < dwLoopEnd); // end while
  1051. }
  1052. RegCloseKey (hKeyPerformance);
  1053. if (szComputerName[0] != 0) {
  1054. RegCloseKey (hKeyMachine);
  1055. }
  1056. }
  1057. if (lpDisplayText != NULL) MemoryFree (lpDisplayText);
  1058. if (lpCounterText != NULL) MemoryFree (lpCounterText);
  1059. return 0;
  1060. }
  1061. #pragma warning ( default : 4706)