Category : Files from Magazines
Archive   : V12N02.ZIP
Filename : PROCMON.C

 
Output of file : PROCMON.C contained in archive : V12N02.ZIP
// 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
#include
#include
#include
#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);
}




  3 Responses to “Category : Files from Magazines
Archive   : V12N02.ZIP
Filename : PROCMON.C

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/