home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The World of Computer Software
/
World_Of_Computer_Software-02-385-Vol-1of3.iso
/
v
/
v12n02.zip
/
PROCMO.ZIP
/
PROCMON.C
< prev
next >
Wrap
Text File
|
1992-12-20
|
32KB
|
855 lines
// ProcMon - Simple Process Performance Monitor for Windows/NT
// Demonstrates use of process information block in System Registry.
// Tested with October 92 (beta) Release of Windows/NT.
// Copyright (C) 1992 Ray Duncan
// PC Magazine * Ziff Davis Publishing
//
// Because the current version of Microsoft C does not contain support
// for 64 bit integers, I chose to keep this example program simple by
// just dumping the raw 64 bit counter data instead of building my own
// math routines to "interpret" the counter data.
//
// Known bugs or malfeatures in this version:
//
// If there are two processes with the same name running, PROCMON
// will only let you display counters for the first instance.
//
#define dim(x) (sizeof(x) / sizeof(x[0])) // returns no. of elements
#define MALLOCINCR 4096
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include <winperf.h>
#include "procmon.h"
HANDLE hInst; // module instance handle
HWND hFrame; // handle for frame window
HWND hLeft; // handle for left child window
HWND hRight; // handle for right child window
HFONT hFont; // handle for nonprop. font
INT CharX, CharY; // character dimensions
char szFrameClass[] = "ProcMon"; // classname for frame window
char szAppName[] = "Process Monitor"; // long application name
char szMenuName[] = "ProcMonMenu"; // name of menu resource
char szIcon[] = "ProcMonIcon"; // name of icon resource
char szIni[] = "ProcMon.ini"; // name of private INI file
DWORD dwPerfDataLen = 0; // size of performance data
PPERFDATA pPerfData; // addr of perf data block
PPERFGROUP pFirstGroup; // addr of first object group
INT iTotGroups; // total object groups
PPERFGROUP pProcessGroup; // address of process group
PSTR pTitles; // addr of object title database
char szCurProcess[256]; // name of current process here
//
// Table of window messages supported by FrameWndProc()
// and the functions which correspond to each message.
//
struct decodeMsg frameMsgs[] = {
WM_CREATE, DoCreate,
WM_SIZE, DoSize,
WM_COMMAND, DoCommand,
WM_CLOSE, DoClose,
WM_DESTROY, DoDestroy, } ;
//
// Table of menubar item IDs and their corresponding functions.
//
struct decodeMsg menuitems[] = {
IDM_EXIT, DoMenuExit,
IDM_ABOUT, DoMenuAbout,
IDM_REFRESH, DoRefresh, } ;
//
// Table of magic numbers for counter types and corresponding
// descriptive strings and counter data sizes. Where the PERFMON.H
// file does not declare a counter as a specific size, I have assumed
// that the counter is 32-bits and marked the counter with ???.
//
struct decodeCounter counterNames[] = {
0, "Unknown Counter Type", PERF_CTR_NODATA,
PERF_COUNTER_COUNTER, "PERF_COUNTER_COUNTER", PERF_CTR_32BIT,
PERF_COUNTER_TIMER, "PERF_COUNTER_TIMER", PERF_CTR_64BIT,
PERF_COUNTER_QUEUELEN, "PERF_COUNTER_QUEUELEN", PERF_CTR_32BIT, // ???
PERF_COUNTER_BULK_COUNT, "PERF_COUNTER_BULK_COUNT", PERF_CTR_64BIT,
PERF_COUNTER_TEXT, "PERF_COUNTER_TEXT", PERF_CTR_TEXT,
PERF_COUNTER_RAWCOUNT, "PERF_COUNTER_RAWCOUNT", PERF_CTR_32BIT,
PERF_SAMPLE_FRACTION, "PERF_SAMPLE_FRACTION", PERF_CTR_32BIT,
PERF_SAMPLE_COUNTER, "PERF_SAMPLE_COUNTER", PERF_CTR_32BIT, // ???
PERF_COUNTER_NODATA, "PERF_COUNTER_NODATA", PERF_CTR_NODATA,
PERF_COUNTER_TIMER_INV, "PERF_COUNTER_TIMER_INV", PERF_CTR_64BIT,
PERF_SAMPLE_BASE, "PERF_SAMPLE_BASE", PERF_CTR_NODATA,
PERF_AVERAGE_TIMER, "PERF_AVERAGE_TIMER", PERF_CTR_32BIT, // ???
PERF_AVERAGE_BASE, "PERF_AVERAGE_BASE", PERF_CTR_NODATA,
PERF_AVERAGE_BULK, "PERF_AVERAGE_BULK", PERF_CTR_NODATA,
PERF_100NSEC_TIMER, "PERF_100NSEC_TIMER", PERF_CTR_64BIT,
PERF_100NSEC_TIMER_INV, "PERF_100NSEC_TIMER_INV", PERF_CTR_64BIT,
PERF_COUNTER_MULTI_TIMER, "PERF_COUNTER_MULTI_TIMER", PERF_CTR_64BIT,
PERF_COUNTER_MULTI_TIMER_INV, "PERF_COUNTER_MULTI_TIMER_INV", PERF_CTR_64BIT,
PERF_COUNTER_MULTI_BASE, "PERF_COUNTER_MULTI_BASE", PERF_CTR_NODATA,
PERF_100NSEC_MULTI_TIMER, "PERF_100NSEC_MULTI_TIMER", PERF_CTR_64BIT,
PERF_100NSEC_MULTI_TIMER_INV, "PERF_100NSEC_MULTI_TIMER_INV", PERF_CTR_64BIT,
PERF_RAW_FRACTION, "PERF_RAW_FRACTION", PERF_CTR_32BIT, // ???
PERF_RAW_BASE, "PERF_RAW_BASE", PERF_CTR_NODATA, // ???
PERF_COUNTER_HISTOGRAM, "PERF_COUNTER_HISTOGRAM", PERF_CTR_NODATA, } ;
//
// WinMain -- entry point for this application from Windows.
//
int APIENTRY WinMain(HANDLE hInstance,
HANDLE hPrevInstance, PSTR lpCmdLine, int nCmdShow)
{
MSG msg; // scratch message storage
hInst = hInstance; // save this instance handle
if(!InitApp(hInstance, nCmdShow)) // initialize everything
{
MessageBox(hFrame, "Initialization failed!", szAppName,
MB_ICONSTOP | MB_OK);
return(FALSE);
}
while(GetMessage(&msg, NULL, 0, 0)) // while message != WM_QUIT
{
TranslateMessage(&msg); // translate virtual key codes
DispatchMessage(&msg); // dispatch message to window
}
TermApp(hInstance); // clean up everything
return(msg.wParam); // return code = WM_QUIT value
}
//
// InitApp --- global initialization code for this application
//
BOOL InitApp(HANDLE hInstance, int nCmdShow)
{
HDC hdc; // handle for device context
RECT rect; // window position & size
TEXTMETRIC tm; // info about font
WNDCLASS wc; // window class info
// set parameters for frame window class
wc.style = CS_HREDRAW|CS_VREDRAW; // class style
wc.lpfnWndProc = FrameWndProc; // class callback function
wc.cbClsExtra = 0; // extra per-class data
wc.cbWndExtra = 0; // extra per-window data
wc.hInstance = hInstance; // handle of class owner
wc.hIcon = LoadIcon(hInst, szIcon); // application icon
wc.hCursor = LoadCursor(NULL, IDC_ARROW); // default cursor
wc.hbrBackground = GetStockObject(WHITE_BRUSH); // background color
wc.lpszMenuName = szMenuName; // name of menu resource
wc.lpszClassName = szFrameClass; // name of window class
// register frame window class for this app
if(!RegisterClass(&wc))
return(FALSE);
hFrame = CreateWindow( // create frame window
szFrameClass, // window class name
szAppName, // text for title bar
WS_OVERLAPPEDWINDOW, // window style
CW_USEDEFAULT, CW_USEDEFAULT, // default position
CW_USEDEFAULT, CW_USEDEFAULT, // default size
NULL, // no parent window
NULL, // use class default menu
hInstance, // window owner
NULL); // unused pointer
if(!hFrame) return(FALSE); // error, can't create window
hdc = GetDC(hFrame); // get device context
hFont = GetStockObject(SYSTEM_FIXED_FONT); // handle for nonprop. font
SelectObject(hdc, hFont); // realize the font and get
GetTextMetrics(hdc, &tm); // the character dimensions
CharX = tm.tmAveCharWidth;
CharY = tm.tmHeight + tm.tmExternalLeading;
ReleaseDC(hFrame, hdc); // release device context
// force nonproportional system font for both child windows
SendMessage(hLeft, WM_SETFONT, (UINT) hFont, 0);
SendMessage(hRight, WM_SETFONT, (UINT) hFont, 0);
GetWindowRect(hFrame, &rect); // current window pos & size
// read profile for frame window from previous invocation, if any
rect.left = GetPrivateProfileInt("Frame", "xul", rect.left, szIni);
rect.top = GetPrivateProfileInt("Frame", "yul", rect.top, szIni);
rect.right = GetPrivateProfileInt("Frame", "xlr", rect.right, szIni);
rect.bottom = GetPrivateProfileInt("Frame", "ylr", rect.bottom, szIni);
MoveWindow(hFrame, rect.left, rect.top, // force window size & position
rect.right-rect.left, rect.bottom-rect.top, TRUE);
// allocate initial buffer to receive performance data
// this buffer will be grown as necessary by GetPerfData
dwPerfDataLen = MALLOCINCR;
pPerfData = (PPERFDATA) malloc(dwPerfDataLen);
if(pPerfData == NULL)
return(FALSE);
// fetch names of object types from system registry
if(!GetObjectTitles())
return(FALSE);
// fetch system performance data from system registry
if(!GetPerfData())
return(FALSE);
// set up our 10 sec. (10,000 msec) timer callback
if (!SetTimer(hFrame, 1, 10000, (WNDPROC) TimerProc))
return(FALSE);
ShowWindow(hFrame, nCmdShow); // make frame window visible
// initialize current process name, display process list
szCurProcess[0] = 0;
SendMessage(hFrame, WM_COMMAND, IDM_REFRESH, 0);
return(TRUE); // return success flag
}
//
// TermApp -- centralized application clean-up code
// which does nothing in this particular case
//
BOOL TermApp(HANDLE hinstance)
{
return(TRUE); // return success flag
}
//
// FrameWndProc --- callback function for application frame window.
// Searches frameMsgs[] for message match, runs corresponding function.
//
LONG CALLBACK FrameWndProc(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam)
{
int i; // scratch variable
for(i = 0; i < dim(frameMsgs); i++) // decode window message and
{ // run corresponding function
if(wMsg == frameMsgs[i].Code)
return((*frameMsgs[i].Fxn)(hWnd, wMsg, wParam, lParam));
}
return(DefWindowProc(hWnd, wMsg, wParam, lParam));
}
//
// DoCommand -- process WM_COMMAND message for frame window by
// decoding the menubar item with the menuitems[] array, then
// running the corresponding function to process the command.
//
LONG DoCommand(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam)
{
int i; // scratch variables
int iSel;
PPERFINSTANCE pCurInst;
for(i = 0; i < dim(menuitems); i++) // decode menu command and
{ // run corresponding function
if(wParam == menuitems[i].Code)
return((*menuitems[i].Fxn)(hWnd, wMsg, wParam, lParam));
}
// Check for user's selection of a process name in the left listbox.
// If new selection, display counters for process. Otherwise,
// pass message to DefWindowProc().
if(((HWND) lParam == hLeft) && (HIWORD(wParam) == LBN_SELCHANGE))
{
// retrieve selected process name from left listbox
iSel = SendMessage(hLeft, LB_GETCURSEL, 0, 0);
SendMessage(hLeft, LB_GETTEXT, iSel, (LONG) szCurProcess);
// find instance data for this process name and display it
pCurInst = FindProcess(szCurProcess);
ShowCounters(pCurInst);
return(FALSE);
}
else
return(DefWindowProc(hWnd, wMsg, wParam, lParam));
}
//
// DoDestroy -- process WM_DESTROY message for frame window.
//
LONG DoDestroy(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam)
{
PostQuitMessage(0); // force WM_QUIT message to
return(0); // terminate the event loop
}
//
// DoClose -- process WM_CLOSE message for frame window.
//
LONG DoClose(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam)
{
UpdateProfile(); // save window size & position
DestroyWindow(hWnd); // then close down app
return(FALSE);
}
//
// DoCreate -- process WM_CREATE message for frame window. Create two
// listbox controls that are tiled vertically inside the frame window.
// These controls will be used as child windows for listing of processes
// and their counters.
//
LONG DoCreate(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam)
{
// create left-hand child window as a listbox control
hLeft = CreateWindow(
"listbox", // window class name
NULL, // text for title bar
WS_CHILD | WS_VISIBLE | // window style
WS_VSCROLL | WS_BORDER | LBS_NOTIFY | LBS_DISABLENOSCROLL,
0, 0, 0, 0, // position and size
hWnd, // frame window is parent
0, // child window identifier
hInst, // window owner
NULL); // unused pointer
// create right-hand child window as a listbox control
hRight = CreateWindow(
"listbox", // window class name
NULL, // text for title bar
WS_CHILD | WS_VISIBLE | // window style
WS_VSCROLL | WS_BORDER | LBS_NOTIFY | LBS_DISABLENOSCROLL,
0, 0, 0, 0, // position and size
hWnd, // frame window is parent
0, // child window identifier
hInst, // window owner
NULL); // unused pointer
return(FALSE);
}
//
// DoSize -- process WM_SIZE message for frame window. Recalculate
// lines per page, if window has grown and at end of file may need to
// change first line in window and refresh it.
//
LONG DoSize(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam)
{
INT i, j;
INT NonClientY;
RECT rect;
// if the new window client height is not an integral multiple of the
// character height, adjust it so that the listboxes will fit neatly.
if(HIWORD(lParam) % CharY)
{
NonClientY = GetSystemMetrics(SM_CYCAPTION) + // caption bar
(GetSystemMetrics(SM_CYFRAME)*2) + // sizable frame
GetSystemMetrics(SM_CYMENU); // menu bar
GetWindowRect(hWnd, &rect);
i = (HIWORD(lParam) / CharY) * CharY;
MoveWindow(hWnd, rect.left, rect.top, rect.right-rect.left,
i + NonClientY, TRUE);
return(FALSE);
}
// make left window just wide enough for longest process name
i = (CharX * 10) + GetSystemMetrics(SM_CXVSCROLL);
j = LOWORD(lParam) - i;
MoveWindow(hLeft, 0, 0, i, HIWORD(lParam), TRUE);
// resize right child window to use remainder of client area
MoveWindow(hRight, i, 0, j, HIWORD(lParam), TRUE);
return(FALSE);
}
//
// DoMenuExit -- process File-Exit command from menu bar.
//
LONG DoMenuExit(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam)
{
SendMessage (hWnd, WM_CLOSE, 0, 0L); // send window close message
return(FALSE); // to shut down the app
}
//
// DoRefresh -- rebuild the information for display according to
// the currently selected display type, then refresh the window.
//
LONG DoRefresh(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam)
{
EmptyLeftLines(); // discard old output
EmptyRightLines();
szCurProcess[0] = 0; // no process selected
// fetch fresh copy of system performance data block
GetPerfData();
// display process list in the left listbox control
ShowProcesses();
return(FALSE);
}
//
// DoMenuAbout -- process File-About command from menu bar.
//
LONG DoMenuAbout(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam)
{
DialogBox(hInst, "AboutBox", hWnd, (WNDPROC) AboutDlgProc);
return(FALSE);
}
//
// AboutDlgProc -- callback routine for About... dialog. Basically
// ignores all messages except for the OK button, which dismisses dialog.
//
BOOL CALLBACK AboutDlgProc (HWND hwnd, UINT msg, UINT wParam, LONG lParam)
{
if((msg == WM_COMMAND) && (wParam == IDOK))
EndDialog(hwnd, 0); // if OK button, destroy dialog
else return(FALSE); // otherwise ignore message
}
//
// ShowProcesses -- displays list of process instances from system registry
//
VOID ShowProcesses(VOID)
{
char temp[256];
PPERFINSTANCE pCurInst;
PPERFCOUNTER pCurCounter;
INT iCurInst;
INT iTotInst;
// bail out now if there is nothing to display
if(pProcessGroup == NULL)
{
MessageBox(hFrame, "No process object group found!", szAppName,
MB_ICONSTOP | MB_OK);
exit(1);
}
// calculate pointer to first process instance, get total number
// of process instances from the process object group header.
pCurInst = (PPERFINSTANCE) ((PBYTE) pProcessGroup +
pProcessGroup->DefinitionLength);
iTotInst = pProcessGroup->NumInstances;
for(iCurInst = 0; iCurInst < iTotInst; iCurInst++)
{
// convert UNICODE process name to ASCIIZ and display it
wcstombs(temp, (LPWSTR) ((PBYTE) pCurInst + pCurInst->NameOffset),
pCurInst->NameLength/sizeof (WCHAR));
AddLeftLine(temp);
// advance to next process instance
pCurCounter = (PPERFCOUNTER) ((PBYTE) pCurInst +
pCurInst->ByteLength);
pCurInst = (PPERFINSTANCE) ((PBYTE) pCurCounter +
pCurCounter->ByteLength);
}
}
//
// ShowCounters -- display counters in right child window in response
// to selection of a process name in the left window. This routine
// is called when a WM_COMMAND message of type LBN_SELCHANGE is
// received. In order to keep the code simple, we just display the
// raw counter values along with the counter name and the counter type.
//
VOID ShowCounters(PPERFINSTANCE pCurInst)
{
char temp[256];
INT i, j;
PPERFCOUNTERDEF pCurCounterDef;
INT iTotCounters;
PUINT pCurCounter;
EmptyRightLines(); // discard old output
// this routine might get called either at the time of process
// selection or on a timer message. If the pointer to process instance
// info is NULL, the process has disappeared since it was originally
// selected, and we need to refresh the process list.
if(pCurInst == NULL)
{
SendMessage(hFrame, WM_COMMAND, IDM_REFRESH, 0);
return;
}
// calculate pointer to first counter definition for process
// objects, save number of counters per process instance
pCurCounterDef = (PPERFCOUNTERDEF) ((PBYTE) pProcessGroup +
pProcessGroup->HeaderLength);
iTotCounters = pProcessGroup->NumCounters;
// loop through counters and display each one in raw form
for(i = 0; i < iTotCounters; i++)
{
// calculate address of counter value
pCurCounter = (PINT) ((PBYTE) pCurInst + pCurInst->ByteLength
+ pCurCounterDef->CounterOffset);
j = FindCounterType(pCurCounterDef->CounterType);
// format counter name, raw value, and type for display
switch(counterNames[j].Size)
{
case PERF_CTR_32BIT:
wsprintf(temp, "%-32s %08Xh %s",
FindTitle(pCurCounterDef->CounterNameTitleIndex),
*pCurCounter,
counterNames[j].Name);
AddRightLine(temp);
break;
case PERF_CTR_64BIT:
wsprintf(temp, "%-32s %08X%08Xh %s",
FindTitle(pCurCounterDef->CounterNameTitleIndex),
*(pCurCounter+1), *pCurCounter,
counterNames[j].Name);
AddRightLine(temp);
break;
case PERF_CTR_TEXT:
case PERF_CTR_NODATA:
wsprintf(temp, "%-32s %s",
FindTitle(pCurCounterDef->CounterNameTitleIndex),
counterNames[j].Name);
AddRightLine(temp);
break;
default:
break;
}
// advance to next counter definition
pCurCounterDef = (PPERFCOUNTERDEF) ((PBYTE) pCurCounterDef +
pCurCounterDef->ByteLength);
}
}
//
// AddLeftLine -- called with a pointer to an ASCIIZ string,
// adds the string to the left (process) listbox.
//
VOID AddLeftLine(char * p)
{
SendMessage(hLeft, LB_ADDSTRING, 0, (LONG) p);
}
//
// EmptyLeftLines - clears out the process instance listbox.
//
VOID EmptyLeftLines(VOID)
{
SendMessage(hLeft, LB_RESETCONTENT, 0, 0);
}
//
// AddRightLine -- called with a pointer to an ASCIIZ string,
// adds the string to the right (counter) listbox.
//
VOID AddRightLine(char * p)
{
SendMessage(hRight, LB_ADDSTRING, 0, (LONG) p);
}
//
// EmptyRightLines - clears out the process counter listbox.
//
VOID EmptyRightLines(VOID)
{
SendMessage(hRight, LB_RESETCONTENT, 0, 0);
}
//
// UpdateProfile() -- saves the current window size and position
// and display type in the application's private INI file.
//
VOID UpdateProfile(VOID)
{
RECT rect;
char temp[20];
if(IsIconic(hFrame) || IsZoomed(hFrame)) return;
GetWindowRect(hFrame, &rect);
wsprintf(temp,"%d", rect.left);
WritePrivateProfileString("Frame", "xul", temp, szIni);
wsprintf(temp,"%d", rect.top);
WritePrivateProfileString("Frame", "yul", temp, szIni);
wsprintf(temp,"%d", rect.right);
WritePrivateProfileString("Frame", "xlr", temp, szIni);
wsprintf(temp,"%d", rect.bottom);
WritePrivateProfileString("Frame", "ylr", temp, szIni);
}
//
// TimerProc() -- Callback for 10 second timer. Refresh display
// of counters for currently selected process else refresh the list
// of process names.
//
WORD CALLBACK TimerProc(HWND hwnd, UINT message, UINT wParam, LONG lParam)
{
PPERFINSTANCE pCurInst;
// fetch fresh copy of system performance data block
GetPerfData();
// if any process has been selected, just refresh counter display,
// otherwise refresh the list of process names.
if(szCurProcess[0])
{
pCurInst = FindProcess(szCurProcess);
ShowCounters(pCurInst);
}
else SendMessage(hFrame, WM_COMMAND, IDM_REFRESH, 0);
return(FALSE);
}
//
// GetPerfData() - obtain performance data block from the
// system registry. The size of the data cannot be known in advance
// so the buffer is expanded incrementally until it is big enough.
//
BOOL GetPerfData(VOID)
{
INT iCurGroup;
PPERFGROUP pCurGroup;
DWORD dwBufferSize = dwPerfDataLen;
while(ERROR_MORE_DATA ==
RegQueryValueEx(HKEY_PERFORMANCE_DATA, "Global",
NULL, NULL, (PSTR) pPerfData, &dwBufferSize))
{
dwPerfDataLen += MALLOCINCR;
dwBufferSize = dwPerfDataLen;
pPerfData = (PPERFDATA) realloc(pPerfData, dwPerfDataLen);
if(pPerfData == NULL)
{
MessageBox(hFrame, "GetPerfData malloc failed!", szAppName,
MB_ICONSTOP | MB_OK);
return(FALSE);
}
}
// point to first object group within the data block and
// save total number of object groups
pFirstGroup = (PPERFGROUP) ((PBYTE) pPerfData + pPerfData->HeaderLength);
iTotGroups = pPerfData->NumObjectTypes;
// point to the first group of objects
pCurGroup = pFirstGroup;
// look up titles for each object type and save pointer
// within the object group's header structure
for(iCurGroup = 0; iCurGroup < iTotGroups; iCurGroup++)
{
pCurGroup->ObjectNameTitle = (LPWSTR)
FindTitle(pCurGroup->ObjectNameTitleIndex);
// advance to next group of objects
pCurGroup = (PPERFGROUP) ((PBYTE) pCurGroup +
pCurGroup->TotalByteLength);
}
// find process object group within the performance data
pProcessGroup = FindGroup("Process");
return(TRUE);
}
//
// GetObjectTitles() - retrieve titles for each of the object
// types from the system registry. The retrieved data, which is
// referred to as the title database, is in the form of a series of
// pairs of ASCIIZ strings. The first string of a pair is the object
// type index in decimal, the second string is the title. The entire
// set of strings is terminated by an extra null byte.
//
BOOL GetObjectTitles(VOID)
{
HKEY hKey;
char chClass[10];
DWORD dwType;
DWORD cSubKeys;
DWORD cbMaxSubkey;
DWORD cbMaxClass;
DWORD cValues;
DWORD cbMaxValueName;
DWORD cbMaxValueData;
DWORD cbSecurityDescriptor;
DWORD cbClassSize = 10 ; // sizeof(chClass);
FILETIME ftLastWriteTime;
// get handle for subkey holding object type indexes and titles
if(ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE,
"Software\\Microsoft\\Windows NT\\CurrentVersion\\Perflib\\409",
0, KEY_QUERY_VALUE, &hKey))
{
MessageBox(hFrame, "RegOpenKeyEx failed!", szAppName,
MB_ICONSTOP | MB_OK);
return(FALSE);
}
// get maximum size of value data for values reached thru this subkey
if(ERROR_SUCCESS != RegQueryInfoKey(hKey, chClass, &cbClassSize, NULL,
&cSubKeys, &cbMaxSubkey, &cbMaxClass, &cValues, &cbMaxValueName,
&cbMaxValueData, &cbSecurityDescriptor, &ftLastWriteTime))
{
MessageBox(hFrame, "RegQueryInfoKey failed!", szAppName,
MB_ICONSTOP | MB_OK);
RegCloseKey(hKey);
return(FALSE);
}
// bump maximum data size value for safety
cbMaxValueData++;
// allocate memory to hold the incoming data
pTitles = malloc(cbMaxValueData * sizeof(TCHAR));
if(pTitles == NULL)
{
MessageBox(hFrame, "GetObjectTitles malloc failed!", szAppName,
MB_ICONSTOP | MB_OK);
RegCloseKey(hKey);
return(FALSE);
}
// now retrieve the index and title data
if(ERROR_SUCCESS != RegQueryValueEx(hKey, "Counters", NULL, &dwType,
(LPBYTE) pTitles, &cbMaxValueData))
{
MessageBox(hFrame, "RegQueryValueEx failed!", szAppName,
MB_ICONSTOP | MB_OK);
RegCloseKey(hKey);
return(FALSE);
}
// release the handle for the subkey
RegCloseKey(hKey);
return(TRUE);
}
//
// FindTitle() -- look up the object type index in the title database
// that was read by GetObjectTitles(). Return a pointer to the title
// string if a match is found, otherwise return a pointer to "Unknown".
//
PSTR FindTitle(INT TitleIndex)
{
INT i; // scratch object index
PSTR p = pTitles; // start of title database
while(*p)
{
i = atoi(p); // convert index string
p += strlen(p) + 1; // point to title string
if(i == TitleIndex) // is this desired index?
return(p); // yes, return addr of title
p += strlen(p) + 1; // no, go to next index
}
return("Unknown"); // no match was found
}
//
// FindGroup() -- Searches for the object group which has the
// specified title. Returns pointer to the beginning of the group's
// instance storage if match is found, otherwise a NULL pointer.
//
PPERFGROUP FindGroup(PSTR GroupName)
{
INT iCurGroup;
PPERFGROUP pCurGroup;
// point to the first group of objects
pCurGroup = pFirstGroup;
// compare title for each object type against supplied string
for(iCurGroup = 0; iCurGroup < iTotGroups; iCurGroup++)
{
// if titles match, return pointer to first instance
if(!strcmp((PSTR) pCurGroup->ObjectNameTitle, GroupName))
return(pCurGroup);
// advance to next group of objects
pCurGroup = (PPERFGROUP) ((PBYTE) pCurGroup +
pCurGroup->TotalByteLength);
}
return(NULL); // no match was found
}
//
// FindCounterType() -- look up the magic number for the counter type
// in the structure counterNames[], return an index to the structure.
// Returns 0 if no match.
//
INT FindCounterType(DWORD CounterType)
{
INT i;
for(i = 0; i < dim(counterNames); i++) // look up counter type
{
if(counterNames[i].Code == CounterType)
return(i); // match was found
}
return(0); // no match was found
}
//
// FindProcess() -- find process instance by name, return pointer.
// Assumes that pProcessGroup was already set by GetPerfData().
//
PPERFINSTANCE FindProcess(PSTR szProcessName)
{
PPERFINSTANCE pCurInst;
PPERFCOUNTER pCurCounter;
INT iCurInst;
INT iTotInst;
char temp[256];
// calculate pointer to first process instance, extract total number
// of instances from the header for the process object group
pCurInst = (PPERFINSTANCE) ((PBYTE) pProcessGroup +
pProcessGroup->DefinitionLength);
iTotInst = pProcessGroup->NumInstances;
for(iCurInst = 0; iCurInst < iTotInst; iCurInst++)
{
// convert UNICODE process name to ASCIIZ, compare it to target,
// if they match return pointer to process instance data
wcstombs(temp, (LPWSTR) ((PBYTE) pCurInst + pCurInst->NameOffset),
pCurInst->NameLength/sizeof (WCHAR));
if(!strcmp(temp, szProcessName))
return(pCurInst);
// advance to next process instance
pCurCounter = (PPERFCOUNTER) ((PBYTE) pCurInst +
pCurInst->ByteLength);
pCurInst = (PPERFINSTANCE) ((PBYTE) pCurCounter +
pCurCounter->ByteLength);
}
// search failed, return null pointer as error indicator
return(NULL);
}