mirror of https://github.com/lianthony/NT4.0
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.
1013 lines
29 KiB
1013 lines
29 KiB
/*++
|
|
|
|
Copyright (c) 1991-1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
ctrlist.c
|
|
|
|
Abstract:
|
|
|
|
Program to read the current perfmon counters and dump a list of
|
|
objects and counters returned by the registry
|
|
|
|
Author:
|
|
|
|
Bob Watson (a-robw) 4 Dec 92
|
|
|
|
Revision History:
|
|
HonWah Chan May 22, 93 - added more features
|
|
HonWah Chan Oct 18, 93 - added check for perflib version.
|
|
Old version --> get names from registry
|
|
New version --> get names from PerfLib thru HKEY_PERFORMANCE_DATA
|
|
Bob Watson (a-robw) 1 Dec 95 added new counter types
|
|
|
|
--*/
|
|
#define UNICODE 1
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <windows.h>
|
|
#include <winperf.h>
|
|
|
|
#define MAX_LEVEL 400
|
|
LPSTR DetailLevelStr[] = { "Novice", "Advanced", "Expert", "Wizard"};
|
|
// const LPWSTR lpwszDiskPerfKey = L"SYSTEM\\CurrentControlSet\\Services\\Diskperf";
|
|
const LPWSTR NamesKey = L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib";
|
|
const LPWSTR DefaultLangId = L"009";
|
|
const LPWSTR Counters = L"Counters";
|
|
const LPWSTR Help = L"Help";
|
|
const LPWSTR LastHelp = L"Last Help";
|
|
const LPWSTR LastCounter = L"Last Counter";
|
|
const LPWSTR Slash = L"\\";
|
|
|
|
// the following strings are for getting texts from perflib
|
|
#define OLD_VERSION 0x010000
|
|
const LPWSTR VersionName = L"Version";
|
|
const LPWSTR CounterName = L"Counter ";
|
|
const LPWSTR HelpName = L"Explain ";
|
|
|
|
#define RESERVED 0L
|
|
#define INITIAL_SIZE 1024L
|
|
#define EXTEND_SIZE 4096L
|
|
#define LINE_LENGTH 80
|
|
#define WRAP_POINT LINE_LENGTH-12
|
|
|
|
typedef LPVOID LPMEMORY;
|
|
typedef HGLOBAL HMEMORY;
|
|
|
|
#define MemoryAllocate(x) ((LPMEMORY)GlobalAlloc(GPTR, x))
|
|
#define MemoryFree(x) ((VOID)GlobalFree(x))
|
|
#define MemorySize(x) ((x != NULL) ? (DWORD)GlobalSize(x) : (DWORD)0)
|
|
#define MemoryResize(x,y) ((LPMEMORY)GlobalReAlloc(x,y,GMEM_MOVEABLE));
|
|
|
|
|
|
TCHAR szComputerName[MAX_COMPUTERNAME_LENGTH+1];
|
|
|
|
const CHAR PerfCounterCounter[] = "PERF_COUNTER_COUNTER";
|
|
const CHAR PerfCounterTimer[] = "PERF_COUNTER_TIMER";
|
|
const CHAR PerfCounterQueueLen[] = "PERF_COUNTER_QUEUELEN_TYPE";
|
|
const CHAR PerfCounterLargeQueueLen[] = "PERF_COUNTER_LARGE_QUEUELEN_TYPE";
|
|
const CHAR PerfCounterBulkCount[] = "PERF_COUNTER_BULK_COUNT";
|
|
const CHAR PerfCounterText[] = "PERF_COUNTER_TEXT";
|
|
const CHAR PerfCounterRawcount[] = "PERF_COUNTER_RAWCOUNT";
|
|
const CHAR PerfCounterLargeRawcount[] = "PERF_COUNTER_LARGE_RAWCOUNT";
|
|
const CHAR PerfSampleFraction[] = "PERF_SAMPLE_FRACTION";
|
|
const CHAR PerfSampleCounter[] = "PERF_SAMPLE_COUNTER";
|
|
const CHAR PerfCounterNodata[] = "PERF_COUNTER_NODATA";
|
|
const CHAR PerfCounterTimerInv[] = "PERF_COUNTER_TIMER_INV";
|
|
const CHAR PerfSampleBase[] = "PERF_SAMPLE_BASE";
|
|
const CHAR PerfAverageTimer[] = "PERF_AVERAGE_TIMER";
|
|
const CHAR PerfAverageBase[] = "PERF_AVERAGE_BASE";
|
|
const CHAR PerfAverageBulk[] = "PERF_AVERAGE_BULK";
|
|
const CHAR Perf100nsecTimer[] = "PERF_100NSEC_TIMER";
|
|
const CHAR Perf100nsecTimerInv[] = "PERF_100NSEC_TIMER_INV";
|
|
const CHAR PerfCounterMultiTimer[] = "PERF_COUNTER_MULTI_TIMER";
|
|
const CHAR PerfCounterMultiTimerInv[] = "PERF_COUNTER_MULTI_TIMER_INV";
|
|
const CHAR PerfCounterMultiBase[] = "PERF_COUNTER_MULTI_BASE";
|
|
const CHAR Perf100nsecMultiTimer[] = "PERF_100NSEC_MULTI_TIMER";
|
|
const CHAR Perf100nsecMultiTimerInv[] = "PERF_100NSEC_MULTI_TIMER_INV";
|
|
const CHAR PerfRawFraction[] = "PERF_RAW_FRACTION";
|
|
const CHAR PerfRawBase[] = "PERF_RAW_BASE";
|
|
const CHAR PerfElapsedTime[] = "PERF_ELAPSED_TIME";
|
|
const CHAR PerfCounterHistogramType[] = "PERF_COUNTER_HISTOGRAM_TYPE";
|
|
const CHAR PerfCounterDelta[] = "PERF_COUNTER_DELTA";
|
|
const CHAR PerfCounterLargeDelta[] = "PERF_COUNTER_LARGE_DELTA";
|
|
const CHAR NotDefineCounterType[] = " ";
|
|
|
|
BOOL bFormatCSV = FALSE;
|
|
//
|
|
// Object Record Fields are:
|
|
// Record Type = "O" for Object Record
|
|
// Object name string ID
|
|
// Object Name in selected language
|
|
// Object Detail Level string (in english)
|
|
// has Instance Records [1= yes, 0= no]
|
|
// Object Instance Code Page [0 = unicode]
|
|
// Help text ID
|
|
// Help text
|
|
//
|
|
const CHAR fmtObjectRecord[] =
|
|
"\n\"O\",\"%d\",\"%ws\",\"%s\",\"%d\",\"%d\",\"%d\",\"%ws\"";
|
|
//
|
|
// Counter Record Fields are:
|
|
// Record Type = "C" for Counter Record
|
|
// Object name string ID { these fields are used as links
|
|
// Object Name in selected language { to object info records
|
|
// Counter name string ID
|
|
// Counter name text in selected language
|
|
// Counter Detail Level string (in english)
|
|
// Counter Type value as a HEX string
|
|
// Counter Type Name
|
|
// Counter Data field size in bytes
|
|
// Counter Visibility [1= listed in list box, 0=hidden]
|
|
// Counter Help text ID
|
|
// Counter Help text
|
|
//
|
|
const CHAR fmtCounterRecord[] =
|
|
"\n\"C\",\"%d\",\"%ws\",\"%d\",\"%ws\",\"%s\",\"0x%8.8x\",\"%s\",\"%d\",\"%d\",\"%d\",\"%ws\"";
|
|
|
|
|
|
LPCSTR
|
|
GetCounterType(
|
|
DWORD CounterType
|
|
)
|
|
{
|
|
switch (CounterType) {
|
|
case PERF_COUNTER_COUNTER:
|
|
return (PerfCounterCounter);
|
|
break;
|
|
|
|
case PERF_COUNTER_TIMER:
|
|
return (PerfCounterTimer);
|
|
break;
|
|
|
|
case PERF_COUNTER_QUEUELEN_TYPE:
|
|
return (PerfCounterQueueLen);
|
|
break;
|
|
|
|
case PERF_COUNTER_LARGE_QUEUELEN_TYPE:
|
|
return (PerfCounterLargeQueueLen);
|
|
break;
|
|
|
|
case PERF_COUNTER_BULK_COUNT:
|
|
return (PerfCounterBulkCount);
|
|
break;
|
|
|
|
case PERF_COUNTER_TEXT:
|
|
return (PerfCounterText);
|
|
break;
|
|
|
|
case PERF_COUNTER_RAWCOUNT:
|
|
return (PerfCounterRawcount);
|
|
break;
|
|
|
|
case PERF_COUNTER_LARGE_RAWCOUNT:
|
|
return (PerfCounterLargeRawcount);
|
|
break;
|
|
|
|
case PERF_SAMPLE_FRACTION:
|
|
return (PerfSampleFraction);
|
|
break;
|
|
|
|
case PERF_SAMPLE_COUNTER:
|
|
return (PerfSampleCounter);
|
|
break;
|
|
|
|
case PERF_COUNTER_NODATA:
|
|
return (PerfCounterNodata);
|
|
break;
|
|
|
|
case PERF_COUNTER_TIMER_INV:
|
|
return (PerfCounterTimerInv);
|
|
break;
|
|
|
|
case PERF_SAMPLE_BASE:
|
|
return (PerfSampleBase);
|
|
break;
|
|
|
|
case PERF_AVERAGE_TIMER:
|
|
return (PerfAverageTimer);
|
|
break;
|
|
|
|
case PERF_AVERAGE_BASE:
|
|
return (PerfAverageBase);
|
|
break;
|
|
|
|
case PERF_AVERAGE_BULK:
|
|
return (PerfAverageBulk);
|
|
break;
|
|
|
|
case PERF_100NSEC_TIMER:
|
|
return (Perf100nsecTimer);
|
|
break;
|
|
|
|
case PERF_100NSEC_TIMER_INV:
|
|
return (Perf100nsecTimerInv);
|
|
break;
|
|
|
|
case PERF_COUNTER_MULTI_TIMER:
|
|
return (PerfCounterMultiTimer);
|
|
break;
|
|
|
|
case PERF_COUNTER_MULTI_TIMER_INV:
|
|
return (PerfCounterMultiTimerInv);
|
|
break;
|
|
|
|
case PERF_COUNTER_MULTI_BASE:
|
|
return (PerfCounterMultiBase);
|
|
break;
|
|
|
|
case PERF_100NSEC_MULTI_TIMER:
|
|
return (Perf100nsecMultiTimer);
|
|
break;
|
|
|
|
case PERF_100NSEC_MULTI_TIMER_INV:
|
|
return (Perf100nsecMultiTimerInv);
|
|
break;
|
|
|
|
case PERF_RAW_FRACTION:
|
|
return (PerfRawFraction);
|
|
break;
|
|
|
|
case PERF_RAW_BASE:
|
|
return (PerfRawBase);
|
|
break;
|
|
|
|
case PERF_ELAPSED_TIME:
|
|
return (PerfElapsedTime);
|
|
break;
|
|
|
|
case PERF_COUNTER_HISTOGRAM_TYPE:
|
|
return (PerfCounterHistogramType);
|
|
break;
|
|
|
|
case PERF_COUNTER_DELTA:
|
|
return (PerfCounterDelta);
|
|
break;
|
|
|
|
case PERF_COUNTER_LARGE_DELTA:
|
|
return (PerfCounterLargeDelta);
|
|
break;
|
|
|
|
default:
|
|
return (NotDefineCounterType);
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
void
|
|
DisplayUsage (
|
|
void
|
|
)
|
|
{
|
|
|
|
printf("\nCtrList - Lists all the objects and counters installed in\n");
|
|
printf(" the system for the given language ID\n");
|
|
printf("\nUsage: ctrlist [/c] [LangID] [\\\\machine] > <filename>\n");
|
|
printf("\n -c prints data in a CSV format");
|
|
printf(" LangID - 009 for English (default)\n");
|
|
printf(" - 007 for German\n");
|
|
printf(" - 00A for Spanish\n");
|
|
printf(" - 00C for French\n");
|
|
printf(" \\\\machine may be specified to list counters on a\n");
|
|
printf(" remote system\n\n");
|
|
printf(" Example - \"ctrlist 00C > french.lst\" will get all the\n");
|
|
printf(" objects and counters for the French system and put\n");
|
|
printf(" them in the file french.lst\n");
|
|
|
|
|
|
return;
|
|
|
|
} /* DisplayUsage() */
|
|
|
|
LPWSTR
|
|
*BuildNameTable(
|
|
HKEY hKeyRegistry, // handle to registry db with counter names
|
|
LPWSTR lpszLangId, // unicode value of Language subkey
|
|
PDWORD pdwLastItem // size of array in elements
|
|
)
|
|
/*++
|
|
|
|
BuildNameTable
|
|
|
|
Arguments:
|
|
|
|
hKeyRegistry
|
|
Handle to an open registry (this can be local or remote.) and
|
|
is the value returned by RegConnectRegistry or a default key.
|
|
|
|
lpszLangId
|
|
The unicode id of the language to look up. (default is 409)
|
|
|
|
Return Value:
|
|
|
|
pointer to an allocated table. (the caller must free it when finished!)
|
|
the table is an array of pointers to zero terminated strings. NULL is
|
|
returned if an error occured.
|
|
|
|
--*/
|
|
{
|
|
|
|
LPWSTR *lpReturnValue;
|
|
|
|
LPWSTR *lpCounterId;
|
|
LPWSTR lpCounterNames;
|
|
LPWSTR lpHelpText;
|
|
|
|
LPWSTR lpThisName;
|
|
|
|
LONG lWin32Status;
|
|
DWORD dwLastError;
|
|
DWORD dwValueType;
|
|
DWORD dwArraySize;
|
|
DWORD dwBufferSize;
|
|
DWORD dwCounterSize;
|
|
DWORD dwHelpSize;
|
|
DWORD dwThisCounter;
|
|
|
|
UNICODE_STRING usTemp;
|
|
|
|
NTSTATUS Status;
|
|
|
|
DWORD dwSystemVersion;
|
|
DWORD dwLastId;
|
|
DWORD dwLastHelpId;
|
|
|
|
HKEY hKeyValue;
|
|
HKEY hKeyNames;
|
|
|
|
LPWSTR lpValueNameString;
|
|
WCHAR CounterNameBuffer [50];
|
|
WCHAR HelpNameBuffer [50];
|
|
|
|
|
|
|
|
lpValueNameString = NULL; //initialize to NULL
|
|
lpReturnValue = NULL;
|
|
hKeyValue = NULL;
|
|
hKeyNames = NULL;
|
|
|
|
// check for null arguments and insert defaults if necessary
|
|
|
|
if (!lpszLangId) {
|
|
lpszLangId = DefaultLangId;
|
|
}
|
|
|
|
// open registry to get number of items for computing array size
|
|
|
|
lWin32Status = RegOpenKeyEx (
|
|
hKeyRegistry,
|
|
NamesKey,
|
|
RESERVED,
|
|
KEY_READ,
|
|
&hKeyValue);
|
|
|
|
if (lWin32Status != ERROR_SUCCESS) {
|
|
goto BNT_BAILOUT;
|
|
}
|
|
|
|
// get number of items
|
|
|
|
dwBufferSize = sizeof (dwLastHelpId);
|
|
lWin32Status = RegQueryValueEx (
|
|
hKeyValue,
|
|
LastHelp,
|
|
RESERVED,
|
|
&dwValueType,
|
|
(LPBYTE)&dwLastHelpId,
|
|
&dwBufferSize);
|
|
|
|
if ((lWin32Status != ERROR_SUCCESS) || (dwValueType != REG_DWORD)) {
|
|
goto BNT_BAILOUT;
|
|
}
|
|
|
|
// get number of items
|
|
|
|
dwBufferSize = sizeof (dwLastId);
|
|
lWin32Status = RegQueryValueEx (
|
|
hKeyValue,
|
|
LastCounter,
|
|
RESERVED,
|
|
&dwValueType,
|
|
(LPBYTE)&dwLastId,
|
|
&dwBufferSize);
|
|
|
|
if ((lWin32Status != ERROR_SUCCESS) || (dwValueType != REG_DWORD)) {
|
|
goto BNT_BAILOUT;
|
|
}
|
|
|
|
|
|
if (dwLastId < dwLastHelpId)
|
|
dwLastId = dwLastHelpId;
|
|
|
|
dwArraySize = dwLastId * sizeof(LPWSTR);
|
|
|
|
// get Perflib system version
|
|
dwBufferSize = sizeof (dwSystemVersion);
|
|
lWin32Status = RegQueryValueEx (
|
|
hKeyValue,
|
|
VersionName,
|
|
RESERVED,
|
|
&dwValueType,
|
|
(LPBYTE)&dwSystemVersion,
|
|
&dwBufferSize);
|
|
|
|
if ((lWin32Status != ERROR_SUCCESS) || (dwValueType != REG_DWORD)) {
|
|
dwSystemVersion = OLD_VERSION;
|
|
}
|
|
|
|
if (dwSystemVersion == OLD_VERSION) {
|
|
// get names from registry
|
|
lpValueNameString = MemoryAllocate (
|
|
lstrlen(NamesKey) * sizeof (WCHAR) +
|
|
lstrlen(Slash) * sizeof (WCHAR) +
|
|
lstrlen(lpszLangId) * sizeof (WCHAR) +
|
|
sizeof (UNICODE_NULL));
|
|
|
|
if (!lpValueNameString) goto BNT_BAILOUT;
|
|
|
|
lstrcpy (lpValueNameString, NamesKey);
|
|
lstrcat (lpValueNameString, Slash);
|
|
lstrcat (lpValueNameString, lpszLangId);
|
|
|
|
lWin32Status = RegOpenKeyEx (
|
|
hKeyRegistry,
|
|
lpValueNameString,
|
|
RESERVED,
|
|
KEY_READ,
|
|
&hKeyNames);
|
|
} else {
|
|
if (szComputerName[0] == 0) {
|
|
hKeyNames = HKEY_PERFORMANCE_DATA;
|
|
} else {
|
|
lWin32Status = RegConnectRegistry (szComputerName,
|
|
HKEY_PERFORMANCE_DATA,
|
|
&hKeyNames);
|
|
}
|
|
lstrcpy (CounterNameBuffer, CounterName);
|
|
lstrcat (CounterNameBuffer, lpszLangId);
|
|
|
|
lstrcpy (HelpNameBuffer, HelpName);
|
|
lstrcat (HelpNameBuffer, lpszLangId);
|
|
}
|
|
|
|
// get size of counter names and add that to the arrays
|
|
|
|
if (lWin32Status != ERROR_SUCCESS) goto BNT_BAILOUT;
|
|
|
|
dwBufferSize = 0;
|
|
lWin32Status = RegQueryValueEx (
|
|
hKeyNames,
|
|
dwSystemVersion == OLD_VERSION ? Counters : CounterNameBuffer,
|
|
RESERVED,
|
|
&dwValueType,
|
|
NULL,
|
|
&dwBufferSize);
|
|
|
|
if (lWin32Status != ERROR_SUCCESS) goto BNT_BAILOUT;
|
|
|
|
dwCounterSize = dwBufferSize;
|
|
|
|
// get size of counter names and add that to the arrays
|
|
|
|
if (lWin32Status != ERROR_SUCCESS) goto BNT_BAILOUT;
|
|
|
|
dwBufferSize = 0;
|
|
lWin32Status = RegQueryValueEx (
|
|
hKeyNames,
|
|
dwSystemVersion == OLD_VERSION ? Help : HelpNameBuffer,
|
|
RESERVED,
|
|
&dwValueType,
|
|
NULL,
|
|
&dwBufferSize);
|
|
|
|
if (lWin32Status != ERROR_SUCCESS) goto BNT_BAILOUT;
|
|
|
|
dwHelpSize = dwBufferSize;
|
|
|
|
lpReturnValue = MemoryAllocate (dwArraySize + dwCounterSize + dwHelpSize);
|
|
|
|
if (!lpReturnValue) goto BNT_BAILOUT;
|
|
|
|
// initialize pointers into buffer
|
|
|
|
lpCounterId = lpReturnValue;
|
|
lpCounterNames = (LPWSTR)((LPBYTE)lpCounterId + dwArraySize);
|
|
lpHelpText = (LPWSTR)((LPBYTE)lpCounterNames + dwCounterSize);
|
|
|
|
// read counters into memory
|
|
|
|
dwBufferSize = dwCounterSize;
|
|
lWin32Status = RegQueryValueEx (
|
|
hKeyNames,
|
|
dwSystemVersion == OLD_VERSION ? Counters : CounterNameBuffer,
|
|
RESERVED,
|
|
&dwValueType,
|
|
(LPVOID)lpCounterNames,
|
|
&dwBufferSize);
|
|
|
|
if (!lpReturnValue) goto BNT_BAILOUT;
|
|
|
|
dwBufferSize = dwHelpSize;
|
|
lWin32Status = RegQueryValueEx (
|
|
hKeyNames,
|
|
dwSystemVersion == OLD_VERSION ? Help : HelpNameBuffer,
|
|
RESERVED,
|
|
&dwValueType,
|
|
(LPVOID)lpHelpText,
|
|
&dwBufferSize);
|
|
|
|
if (!lpReturnValue) goto BNT_BAILOUT;
|
|
|
|
// load counter array items
|
|
|
|
for (lpThisName = lpCounterNames;
|
|
*lpThisName;
|
|
lpThisName += (lstrlen(lpThisName)+1) ) {
|
|
|
|
// first string should be an integer (in decimal unicode digits)
|
|
|
|
usTemp.Length = lstrlen(lpThisName) * sizeof (WCHAR);
|
|
usTemp.MaximumLength = usTemp.Length + sizeof (UNICODE_NULL);
|
|
usTemp.Buffer = lpThisName;
|
|
|
|
Status = RtlUnicodeStringToInteger (
|
|
&usTemp,
|
|
10L,
|
|
&dwThisCounter);
|
|
|
|
if (Status != ERROR_SUCCESS) goto BNT_BAILOUT; // bad entry
|
|
|
|
// point to corresponding counter name
|
|
|
|
lpThisName += (lstrlen(lpThisName)+1);
|
|
|
|
// and load array element;
|
|
|
|
lpCounterId[dwThisCounter] = lpThisName;
|
|
|
|
}
|
|
|
|
for (lpThisName = lpHelpText;
|
|
*lpThisName;
|
|
lpThisName += (lstrlen(lpThisName)+1) ) {
|
|
|
|
// first string should be an integer (in decimal unicode digits)
|
|
|
|
usTemp.Length = lstrlen(lpThisName) * sizeof (WCHAR);
|
|
usTemp.MaximumLength = usTemp.Length + sizeof (UNICODE_NULL);
|
|
usTemp.Buffer = lpThisName;
|
|
|
|
Status = RtlUnicodeStringToInteger (
|
|
&usTemp,
|
|
10L,
|
|
&dwThisCounter);
|
|
|
|
if (Status != ERROR_SUCCESS) goto BNT_BAILOUT; // bad entry
|
|
|
|
// point to corresponding counter name
|
|
|
|
lpThisName += (lstrlen(lpThisName)+1);
|
|
|
|
// and load array element;
|
|
|
|
lpCounterId[dwThisCounter] = lpThisName;
|
|
|
|
}
|
|
|
|
if (pdwLastItem) *pdwLastItem = dwLastId;
|
|
|
|
MemoryFree ((LPVOID)lpValueNameString);
|
|
RegCloseKey (hKeyValue);
|
|
// if (dwSystemVersion == OLD_VERSION)
|
|
RegCloseKey (hKeyNames);
|
|
|
|
return lpReturnValue;
|
|
|
|
BNT_BAILOUT:
|
|
if (lWin32Status != ERROR_SUCCESS) {
|
|
dwLastError = GetLastError();
|
|
}
|
|
|
|
if (lpValueNameString) {
|
|
MemoryFree ((LPVOID)lpValueNameString);
|
|
}
|
|
|
|
if (lpReturnValue) {
|
|
MemoryFree ((LPVOID)lpReturnValue);
|
|
}
|
|
|
|
if (hKeyValue) RegCloseKey (hKeyValue);
|
|
|
|
// if (dwSystemVersion == OLD_VERSION &&
|
|
// hKeyNames)
|
|
RegCloseKey (hKeyNames);
|
|
|
|
|
|
return NULL;
|
|
}
|
|
|
|
NTSTATUS
|
|
GetEnumPerfData (
|
|
IN HKEY hKeySystem,
|
|
IN DWORD dwIndex,
|
|
IN PPERF_DATA_BLOCK *pPerfData
|
|
)
|
|
{ // GetSystemPerfData
|
|
LONG lError ;
|
|
DWORD Size;
|
|
DWORD Type;
|
|
DWORD ValueBufferLen;
|
|
|
|
WCHAR wcValueBuffer[64];
|
|
|
|
if (dwIndex >= 2)
|
|
return !ERROR_SUCCESS;
|
|
|
|
if (*pPerfData == NULL) {
|
|
*pPerfData = MemoryAllocate (INITIAL_SIZE);
|
|
if (*pPerfData == NULL) return ERROR_OUTOFMEMORY;
|
|
}
|
|
|
|
while (TRUE) {
|
|
Size = MemorySize (*pPerfData);
|
|
ValueBufferLen = sizeof (wcValueBuffer);
|
|
|
|
lError = RegQueryValueEx (
|
|
hKeySystem,
|
|
dwIndex == 0 ?
|
|
L"Global" :
|
|
L"Costly",
|
|
RESERVED,
|
|
&Type,
|
|
(LPSTR)*pPerfData,
|
|
&Size);
|
|
|
|
if ((!lError) &&
|
|
(Size > 0) &&
|
|
(*pPerfData)->Signature[0] == (WCHAR)'P' &&
|
|
(*pPerfData)->Signature[1] == (WCHAR)'E' &&
|
|
(*pPerfData)->Signature[2] == (WCHAR)'R' &&
|
|
(*pPerfData)->Signature[3] == (WCHAR)'F' ) {
|
|
|
|
return (ERROR_SUCCESS);
|
|
}
|
|
|
|
if (lError == ERROR_MORE_DATA) {
|
|
*pPerfData = MemoryResize (
|
|
*pPerfData,
|
|
MemorySize (*pPerfData) +
|
|
EXTEND_SIZE);
|
|
|
|
if (!*pPerfData) {
|
|
return (lError);
|
|
}
|
|
} else {
|
|
return (lError);
|
|
} // else
|
|
}
|
|
} // GetSystemPerfData
|
|
|
|
PPERF_OBJECT_TYPE
|
|
FirstObject (
|
|
PPERF_DATA_BLOCK pPerfData
|
|
)
|
|
{
|
|
return ((PPERF_OBJECT_TYPE) ((PBYTE) pPerfData + pPerfData->HeaderLength));
|
|
}
|
|
|
|
|
|
PPERF_OBJECT_TYPE
|
|
NextObject (
|
|
PPERF_OBJECT_TYPE pObject
|
|
)
|
|
{ // NextObject
|
|
return ((PPERF_OBJECT_TYPE) ((PBYTE) pObject + pObject->TotalByteLength));
|
|
} // NextObject
|
|
|
|
PERF_COUNTER_DEFINITION *
|
|
FirstCounter(
|
|
PERF_OBJECT_TYPE *pObjectDef
|
|
)
|
|
{
|
|
return (PERF_COUNTER_DEFINITION *)
|
|
((PCHAR) pObjectDef + pObjectDef->HeaderLength);
|
|
}
|
|
|
|
|
|
PERF_COUNTER_DEFINITION *
|
|
NextCounter(
|
|
PERF_COUNTER_DEFINITION *pCounterDef
|
|
)
|
|
{
|
|
return (PERF_COUNTER_DEFINITION *)
|
|
((PCHAR) pCounterDef + pCounterDef->ByteLength);
|
|
}
|
|
|
|
LONG
|
|
PrintHelpText(
|
|
DWORD Indent,
|
|
DWORD dwID,
|
|
LPWSTR szTextString
|
|
)
|
|
{
|
|
LPWSTR szThisChar;
|
|
|
|
BOOL bNewLine;
|
|
|
|
DWORD dwThisPos;
|
|
DWORD dwLinesUsed;
|
|
|
|
szThisChar = szTextString;
|
|
dwLinesUsed = 0;
|
|
|
|
// check arguments
|
|
|
|
if (!szTextString) {
|
|
return dwLinesUsed;
|
|
}
|
|
|
|
if (Indent > WRAP_POINT) {
|
|
return dwLinesUsed; // can't do this
|
|
}
|
|
|
|
// display id number
|
|
|
|
for (dwThisPos = 0; dwThisPos < Indent - 6; dwThisPos++) {
|
|
putchar (' ');
|
|
}
|
|
|
|
dwThisPos += printf ("[%3.3d] ", dwID);
|
|
bNewLine = FALSE;
|
|
|
|
// print text
|
|
|
|
while (*szThisChar) {
|
|
|
|
if (bNewLine){
|
|
for (dwThisPos = 0; dwThisPos < Indent; dwThisPos++) {
|
|
putchar (' ');
|
|
}
|
|
|
|
bNewLine = FALSE;
|
|
}
|
|
if ((*szThisChar == L' ') && (dwThisPos >= WRAP_POINT)) {
|
|
putchar ('\n');
|
|
bNewLine = TRUE;
|
|
// go to next printable character
|
|
while (*szThisChar <= L' ') {
|
|
szThisChar++;
|
|
}
|
|
dwLinesUsed++;
|
|
} else {
|
|
putchar (*szThisChar);
|
|
szThisChar++;
|
|
}
|
|
|
|
dwThisPos++;
|
|
}
|
|
|
|
putchar ('\n');
|
|
bNewLine = TRUE;
|
|
dwLinesUsed++;
|
|
|
|
return dwLinesUsed;
|
|
}
|
|
|
|
int
|
|
_CRTAPI1 main(
|
|
int argc,
|
|
char *argv[]
|
|
)
|
|
{
|
|
int ArgNo;
|
|
|
|
LPWSTR *lpCounterText;
|
|
|
|
DWORD dwLastElement;
|
|
|
|
DWORD dwIndex;
|
|
|
|
DWORD dwDisplayLevel;
|
|
|
|
PPERF_DATA_BLOCK pDataBlock; // pointer to perfdata block
|
|
BOOL bError;
|
|
|
|
DWORD dwThisObject;
|
|
DWORD dwThisCounter;
|
|
CHAR LangID[10];
|
|
WCHAR wLangID[10];
|
|
BOOL UseDefaultID = FALSE;
|
|
LPSTR szComputerNameArg;
|
|
|
|
PPERF_OBJECT_TYPE pThisObject;
|
|
PPERF_COUNTER_DEFINITION pThisCounter;
|
|
|
|
HKEY hKeyMachine = HKEY_LOCAL_MACHINE;
|
|
HKEY hKeyPerformance = HKEY_PERFORMANCE_DATA;
|
|
|
|
dwDisplayLevel = PERF_DETAIL_WIZARD;
|
|
|
|
// open key to registry or use default
|
|
|
|
if (argc >= 2) {
|
|
if ((argv[1][0] == '-' || argv[1][0] == '\\') &&
|
|
argv[1][1] == '?') {
|
|
DisplayUsage();
|
|
return 0;
|
|
}
|
|
|
|
if (argv[1][0] != '\\') {
|
|
if ((argv[1][0] == '-') || (argv[1][0] == '/')) {
|
|
// then this is a command switch
|
|
if ((argv[1][1] == 'c') || (argv[1][1] == 'C')) {
|
|
// then format is a CSV
|
|
bFormatCSV = TRUE;
|
|
}
|
|
ArgNo = 2;
|
|
} else {
|
|
ArgNo = 1;
|
|
}
|
|
if (argc > ArgNo) {
|
|
// get the lang ID
|
|
LangID[0] = argv[ArgNo][0];
|
|
LangID[1] = argv[ArgNo][1];
|
|
LangID[2] = argv[ArgNo][2];
|
|
LangID[3] = '\0';
|
|
mbstowcs(wLangID, LangID, 4);
|
|
if (argc > (++ArgNo)) {
|
|
// see if the next arg is a computer name
|
|
if (argv[ArgNo][0] == '\\') {
|
|
mbstowcs (szComputerName, argv[ArgNo],
|
|
MAX_COMPUTERNAME_LENGTH);
|
|
szComputerNameArg = argv[ArgNo];
|
|
} else {
|
|
szComputerName[0] = 0;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
// 1st arg is a computer name
|
|
mbstowcs (szComputerName, argv[1], MAX_COMPUTERNAME_LENGTH);
|
|
szComputerNameArg = argv[1];
|
|
}
|
|
|
|
#if 0
|
|
// get user level from command line
|
|
if (argc > 2 && sscanf(argv[2], " %d", &dwDisplayLevel) == 1) {
|
|
if (dwDisplayLevel <= PERF_DETAIL_NOVICE) {
|
|
dwDisplayLevel = PERF_DETAIL_NOVICE;
|
|
} else if (dwDisplayLevel <= PERF_DETAIL_ADVANCED) {
|
|
dwDisplayLevel = PERF_DETAIL_ADVANCED;
|
|
} else if (dwDisplayLevel <= PERF_DETAIL_EXPERT) {
|
|
dwDisplayLevel = PERF_DETAIL_EXPERT;
|
|
} else {
|
|
dwDisplayLevel = PERF_DETAIL_WIZARD;
|
|
}
|
|
} else {
|
|
dwDisplayLevel = PERF_DETAIL_WIZARD;
|
|
}
|
|
#endif
|
|
|
|
} else {
|
|
UseDefaultID = TRUE;
|
|
szComputerName[0] = 0;
|
|
}
|
|
|
|
if (szComputerName[0] != 0) {
|
|
if (RegConnectRegistry (szComputerName, HKEY_LOCAL_MACHINE,
|
|
&hKeyMachine) != ERROR_SUCCESS) {
|
|
printf ("\nUnable to connect to %s", szComputerNameArg);
|
|
return 0;
|
|
}
|
|
if (RegConnectRegistry (szComputerName, HKEY_PERFORMANCE_DATA,
|
|
&hKeyPerformance) != ERROR_SUCCESS) {
|
|
printf ("\nUnable to connect to %s", szComputerNameArg);
|
|
return 0;
|
|
}
|
|
} else {
|
|
// use default initializations
|
|
}
|
|
|
|
lpCounterText = BuildNameTable (
|
|
hKeyMachine,
|
|
UseDefaultID ? DefaultLangId : wLangID,
|
|
&dwLastElement);
|
|
|
|
if (!lpCounterText) {
|
|
printf("***FAILure*** Cannot open the registry\n");
|
|
return 0;
|
|
}
|
|
|
|
// get a performance data buffer with counters
|
|
|
|
pDataBlock = 0;
|
|
|
|
for (dwIndex = 0; (bError = GetEnumPerfData (
|
|
hKeyPerformance,
|
|
dwIndex,
|
|
&pDataBlock) == ERROR_SUCCESS); dwIndex++) {
|
|
|
|
for (dwThisObject = 0, pThisObject = FirstObject (pDataBlock);
|
|
dwThisObject < pDataBlock->NumObjectTypes;
|
|
dwThisObject++, pThisObject = NextObject(pThisObject)) {
|
|
|
|
if (pThisObject->DetailLevel <= dwDisplayLevel) {
|
|
|
|
if (!bFormatCSV) {
|
|
printf ("\nObject: \"%ws\" [%3.3d] \n",
|
|
lpCounterText[pThisObject->ObjectNameTitleIndex],
|
|
pThisObject->ObjectNameTitleIndex);
|
|
printf (" Detail Level: %s\n",
|
|
pThisObject->DetailLevel <= MAX_LEVEL ?
|
|
DetailLevelStr[pThisObject->DetailLevel/100-1] :
|
|
"<N\\A>");
|
|
|
|
PrintHelpText (9,
|
|
pThisObject->ObjectHelpTitleIndex,
|
|
lpCounterText[pThisObject->ObjectHelpTitleIndex]);
|
|
} else {
|
|
printf (fmtObjectRecord,
|
|
pThisObject->ObjectNameTitleIndex,
|
|
lpCounterText[pThisObject->ObjectNameTitleIndex],
|
|
pThisObject->DetailLevel <= MAX_LEVEL ?
|
|
DetailLevelStr[pThisObject->DetailLevel/100-1] :
|
|
"<N\\A>",
|
|
pThisObject->NumInstances == PERF_NO_INSTANCES ?
|
|
0 : 1,
|
|
pThisObject->CodePage,
|
|
pThisObject->ObjectHelpTitleIndex,
|
|
lpCounterText[pThisObject->ObjectHelpTitleIndex]);
|
|
}
|
|
|
|
for (dwThisCounter = 0, pThisCounter = FirstCounter(pThisObject);
|
|
dwThisCounter < pThisObject->NumCounters;
|
|
dwThisCounter++, pThisCounter = NextCounter(pThisCounter)) {
|
|
|
|
try {
|
|
if (pThisCounter->DetailLevel <= dwDisplayLevel) {
|
|
if (!bFormatCSV) {
|
|
printf ("\n <%ws> [%3.3d]",
|
|
lpCounterText[pThisCounter->CounterNameTitleIndex],
|
|
pThisCounter->CounterNameTitleIndex);
|
|
printf ("\n Default Scale: %d",
|
|
pThisCounter->DefaultScale);
|
|
printf ("\n Detail Level: %s",
|
|
((pThisCounter->DetailLevel <= MAX_LEVEL) &&
|
|
(pThisCounter->DetailLevel > 0 ))?
|
|
DetailLevelStr[pThisCounter->DetailLevel/100-1] :
|
|
"<N\\A>");
|
|
printf ("\n Counter Type: 0x%x, %s",
|
|
pThisCounter->CounterType,
|
|
GetCounterType(pThisCounter->CounterType));
|
|
printf ("\n Counter Size: %d bytes",
|
|
pThisCounter->CounterSize);
|
|
|
|
printf ("\n");
|
|
PrintHelpText (16,
|
|
pThisCounter->CounterHelpTitleIndex,
|
|
lpCounterText[pThisCounter->CounterHelpTitleIndex]);
|
|
} else {
|
|
printf (fmtCounterRecord,
|
|
pThisObject->ObjectNameTitleIndex,
|
|
lpCounterText[pThisObject->ObjectNameTitleIndex],
|
|
pThisCounter->CounterNameTitleIndex,
|
|
lpCounterText[pThisCounter->CounterNameTitleIndex],
|
|
((pThisCounter->DetailLevel <= MAX_LEVEL) &&
|
|
(pThisCounter->DetailLevel > 0 )) ?
|
|
DetailLevelStr[pThisCounter->DetailLevel/100-1] :
|
|
"<N\\A>",
|
|
pThisCounter->CounterType,
|
|
GetCounterType(pThisCounter->CounterType),
|
|
pThisCounter->CounterSize,
|
|
(pThisCounter->CounterType & PERF_DISPLAY_NOSHOW) ?
|
|
0 : 1,
|
|
pThisCounter->CounterHelpTitleIndex,
|
|
lpCounterText[pThisCounter->CounterHelpTitleIndex]);
|
|
}
|
|
}
|
|
} except (EXCEPTION_EXECUTE_HANDLER) {
|
|
if (!bFormatCSV) {
|
|
printf ("\n Error (%d) reading this counter",
|
|
GetExceptionCode());
|
|
}
|
|
}
|
|
}
|
|
printf ("\n");
|
|
}
|
|
}
|
|
RegCloseKey (hKeyPerformance);
|
|
if (szComputerName[0] != 0) {
|
|
RegCloseKey (hKeyMachine);
|
|
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|