MAINWND.C

//THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF 
//ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
//THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright 1996 - 1997 Microsoft Corporation. All Rights Reserved.
//
// Mainwnd: mainwnd.c
//
// PURPOSE: main window functions
//
// PLATFORMS: Windows NT (only)
//
// FUNCTIONS:
// DeleteAllCounters() clears counters from query
// On_WM_CREATE() processes WM_CREATE message
// On_IDM_GET_DATA() gets the current perf data and updates window
// On_IDM_ADD_COUNTERS() displays browser & adds perf. counter to display
// On_IDM_CLEAR_ALL() clear all counters & refresh display
// On_WM_COMMAND() processes WM_COMMAND messages
// On_WM_RBUTTONDOWN() processes Right Mouse button clicks
// On_WM_PAINT() draws the current data in the main window
// On_WM_DESTROY() closes any open interfaces & memory allocations
// WndProc() main window procedure for this app's window
//
// SPECIAL INSTRUCTIONS: N/A
//
#define WIN32_LEAN_AND_MEAN 1
#include <windows.h>
#include <winperf.h>
#include <stdio.h>
#include <pdh.h>
#include <pdhmsg.h>

#include "statlist.h"
#include "winutils.h"
#include "mainwnd.h"
#include "aboutdlg.h"

// font for text in window
static HFONT hFinePrint = NULL;

// PDH Query Handle for these counters
static HQUERY hQuery = NULL;

// pointer to first item in counter list
static PCIB pFirstCib = NULL;

int nTabStops[] = {300, 400, 500, 600, 700};
int nNumTabStops = sizeof(nTabStops) / sizeof(int);

#define NUM_STAT_SAMPLES 100

static
void
DeleteAllCounters ()
{
PCIB pCib, pCibOld;

// close PDH Query
// this removes all counters from the query as well as
// removes the query item itself
if (hQuery != NULL) {
PdhCloseQuery (hQuery);
hQuery = NULL;
}

// clean up any memory allocations
pCib = pFirstCib;
while ( pCib != NULL) {
pCibOld = pCib;
if (pCibOld->pCounterArray != NULL) {
HeapFree (GetProcessHeap(), 0, pCibOld->pCounterArray);
}
pCib = pCib->pNext;
HeapFree (GetProcessHeap(), 0, pCibOld);
}
pFirstCib = NULL;
}

// windows message functions
static
LRESULT
On_WM_CREATE (
HWND hWnd,
WPARAM wParam,
LPARAM lParam)
{
PDH_STATUS pdhStatus;

if (hQuery == NULL) {
pdhStatus = PdhOpenQuery (NULL, 0, &hQuery);
}
if (hFinePrint == NULL) {
hFinePrint = CreateFont(11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
VARIABLE_PITCH | FF_SWISS, "");
}
return ERROR_SUCCESS;
}

static
LRESULT
On_IDM_GET_DATA (
HWND hWnd,
WPARAM wParam,
LPARAM lParam)
{
PDH_STATUS pdhStatus;
DWORD dwType;
PCIB pCib;
PDH_FMT_COUNTERVALUE pValue;
PDH_RAW_COUNTER pRaw;

if (hQuery != NULL) {
// get the current values of the query data
pdhStatus = PdhCollectQueryData (hQuery);
if (pdhStatus == ERROR_SUCCESS) {
// loop through all counters and update the display values
// and statistics
for (pCib = pFirstCib; pCib != NULL; pCib = pCib->pNext) {
// update "Last value"
pdhStatus = PdhGetFormattedCounterValue (
pCib->hCounter, PDH_FMT_DOUBLE, &dwType, &pValue);
pCib->dLastValue = pValue.doubleValue;
// update "Raw Value" and statistics
pdhStatus = PdhGetRawCounterValue (
pCib->hCounter, &dwType, &pRaw);
pCib->pCounterArray[pCib->dwNextIndex] = pRaw;
pdhStatus = PdhComputeCounterStatistics (
pCib->hCounter,
PDH_FMT_DOUBLE,
pCib->dwFirstIndex,
++pCib->dwLastIndex,
pCib->pCounterArray,
&pCib->pdhCurrentStats);
// update pointers & indeces
if (pCib->dwLastIndex < NUM_STAT_SAMPLES) {
pCib->dwNextIndex = ++pCib->dwNextIndex % NUM_STAT_SAMPLES;
} else {
--pCib->dwLastIndex;
pCib->dwNextIndex = pCib->dwFirstIndex;
pCib->dwFirstIndex = ++pCib->dwFirstIndex % NUM_STAT_SAMPLES;
}
}
// cause the window to be repainted with the new values
// (NOTE: This isn't the most efficient method of
// display updating.)
InvalidateRect (hWnd, NULL, TRUE);
}
}
return ERROR_SUCCESS;
}

static
LRESULT
On_IDM_ADD_COUNTERS (
HWND hWnd,
WPARAM wParam,
LPARAM lParam)
{
PDH_BROWSE_DLG_CONFIG BrowseInfo;
CHAR szCounterBuffer[MAX_PATH];
PDH_STATUS pdhStatus;
PCIB pNewCib;

BrowseInfo.bIncludeInstanceIndex = FALSE;
BrowseInfo.bSingleCounterPerAdd = TRUE;
BrowseInfo.bSingleCounterPerDialog = TRUE;
BrowseInfo.bLocalCountersOnly = FALSE;
BrowseInfo.bWildCardInstances = FALSE;
BrowseInfo.bHideDetailBox = FALSE;
BrowseInfo.bDisableMachineSelection = FALSE;
BrowseInfo.bInitializePath = FALSE;
BrowseInfo.bIncludeCostlyObjects = TRUE;
BrowseInfo.hWndOwner = hWnd;
BrowseInfo.szReturnPathBuffer = szCounterBuffer;
BrowseInfo.cchReturnPathLength = MAX_PATH;
BrowseInfo.pCallBack = NULL;
BrowseInfo.dwCallBackArg = 0;
BrowseInfo.CallBackStatus = ERROR_SUCCESS;
BrowseInfo.dwDefaultDetailLevel = PERF_DETAIL_WIZARD;
BrowseInfo.szDialogBoxCaption = "Select a counter to monitor";


pdhStatus = PdhBrowseCounters (&BrowseInfo);

if (pdhStatus == ERROR_SUCCESS) {
// add counter to the list
pNewCib = (PCIB) HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY, sizeof(CIB));
if (pNewCib != NULL) {
// try to add the counter to the query
pdhStatus = PdhAddCounter (hQuery,
szCounterBuffer, 0, &pNewCib->hCounter);
if (pdhStatus == ERROR_SUCCESS) {
lstrcpy(pNewCib->szCounterPath, szCounterBuffer);
// allocate the raw data buffer here
pNewCib->pCounterArray = (PPDH_RAW_COUNTER)HeapAlloc (
GetProcessHeap(), HEAP_ZERO_MEMORY,
(sizeof(PDH_RAW_COUNTER) * NUM_STAT_SAMPLES));
pNewCib->dwFirstIndex = 0;
pNewCib->dwNextIndex = 0;
pNewCib->dwLastIndex = 0;
pNewCib->dLastValue = 0.0f;
pNewCib->pdhCurrentStats.dwFormat = 0;
pNewCib->pdhCurrentStats.count = 0;
pNewCib->pdhCurrentStats.min.CStatus = PDH_CSTATUS_INVALID_DATA;
pNewCib->pdhCurrentStats.min.largeValue = 0;
pNewCib->pdhCurrentStats.max.CStatus = PDH_CSTATUS_INVALID_DATA;
pNewCib->pdhCurrentStats.max.largeValue = 0;
pNewCib->pdhCurrentStats.mean.CStatus = PDH_CSTATUS_INVALID_DATA;
pNewCib->pdhCurrentStats.mean.largeValue = 0;

//add to the top of the list
pNewCib->pNext = pFirstCib;
pFirstCib = pNewCib;

// repaint window to get new entry
InvalidateRect (hWnd, NULL, TRUE);
} // else unable to add counter
} // else unable to allocate pointer
} // else user cancelled
return ERROR_SUCCESS;
}

static
LRESULT
On_IDM_CLEAR_ALL (
HWND hWnd,
WPARAM wParam,
LPARAM lParam)
{
PDH_STATUS pdhStatus;

// delete all current counters, then create a new query
DeleteAllCounters();

pdhStatus = PdhOpenQuery (NULL, 0, &hQuery);

InvalidateRect (hWnd, NULL, TRUE);

return ERROR_SUCCESS;
}

static
LRESULT
On_WM_COMMAND (
HWND hWnd,
WPARAM wParam,
LPARAM lParam)
{
int wmId, wmEvent;
char szHelpFileName[MAX_PATH];
BOOL bGotHelp;

wmId = LOWORD(wParam); // Remember, these are...
wmEvent = HIWORD(wParam); // ...different for Win32!

//Parse the menu selections:
switch (wmId) {
// File Menu Item
case IDM_NEW:
case IDM_OPEN:
case IDM_SAVE:
case IDM_SAVEAS:
return (DefWindowProc(hWnd, WM_COMMAND, wParam, lParam));

case IDM_EXIT:
DestroyWindow (hWnd);
return ERROR_SUCCESS;

// configure menu item
case IDM_ADD_COUNTERS:
return On_IDM_ADD_COUNTERS (hWnd, wParam, lParam);

case IDM_CLEAR_ALL:
return On_IDM_CLEAR_ALL (hWnd, wParam, lParam);

// get data menu item
case IDM_GET_DATA:
return On_IDM_GET_DATA (hWnd, wParam, lParam);


// Help Menu Item
case IDM_HELPTOPICS:
lstrcpy (szHelpFileName, APPNAME);
lstrcat (szHelpFileName, ".HLP");
bGotHelp = WinHelp (hWnd, szHelpFileName, HELP_FINDER,(DWORD)0);
if (!bGotHelp)
{
MessageBox (GetFocus(), GetStringRes(IDS_NO_HELP),
APPNAME, MB_OK|MB_ICONHAND);
}
return ERROR_SUCCESS;

case IDM_ABOUT:
DialogBox((HINSTANCE)(GetWindowLong(hWnd, GWL_HINSTANCE)),
"AboutBox", hWnd, (DLGPROC)About);
return ERROR_SUCCESS;

default:
return (DefWindowProc(hWnd, WM_COMMAND, wParam, lParam));
}
}

static LRESULT
On_WM_RBUTTONDOWN (
HWND hWnd,
WPARAM wParam,
LPARAM lParam)
{
POINT pnt;
HMENU hMenu;

pnt.x = LOWORD(lParam);
pnt.y = HIWORD(lParam);
ClientToScreen(hWnd, (LPPOINT) &pnt);
// This is where you would determine the appropriate 'context'
// menu to bring up. Since this app has no real functionality,
// we will just bring up the 'configure' menu:
hMenu = GetSubMenu (GetMenu (hWnd), 1);
if (hMenu) {
TrackPopupMenu (hMenu, 0, pnt.x, pnt.y, 0, hWnd, NULL);
} else {
// Couldn't find the menu...
MessageBeep(0);
}

return ERROR_SUCCESS;
}

static LRESULT
On_WM_PAINT (
HWND hWnd,
WPARAM wParam,
LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;
PCIB pCib;
int nX, nY;
LONG lTextOutReturn;
char szOutputString[MAX_PATH];
int nStringLength;

hdc = BeginPaint (hWnd, &ps);

nX = 0;
nY = 0;
// draw Title text
lstrcpy (szOutputString, "Performance Counter\tLast Value\tMinimum\tMaximum\tAverage");
nStringLength = lstrlen(szOutputString) * sizeof(TCHAR);
lTextOutReturn = TabbedTextOut (hdc, nX, nY,
szOutputString, nStringLength,
nNumTabStops, nTabStops, 0);
nY += HIWORD(lTextOutReturn);

// select the fine print font for this window
SelectObject(hdc, hFinePrint);

// for each CIB in the list draw the current text and value
for (pCib = pFirstCib; pCib != NULL; pCib = pCib->pNext) {
nStringLength = sprintf (szOutputString, "%s\t%f\t%f\t%f\t%f",
pCib->szCounterPath, pCib->dLastValue,
pCib->pdhCurrentStats.min.doubleValue,
pCib->pdhCurrentStats.max.doubleValue,
pCib->pdhCurrentStats.mean.doubleValue);
lTextOutReturn = TabbedTextOut (hdc, nX, nY,
szOutputString, nStringLength,
nNumTabStops, nTabStops, 0);
nY += HIWORD(lTextOutReturn);
}

EndPaint (hWnd, &ps);
return ERROR_SUCCESS;
}

static LRESULT
On_WM_DESTROY (
HWND hWnd,
WPARAM wParam,
LPARAM lParam)
{
char szHelpFileName[MAX_PATH];

lstrcpy (szHelpFileName, APPNAME);
lstrcat (szHelpFileName, ".HLP");
// Tell WinHelp we don't need it any more...
WinHelp (hWnd, szHelpFileName, HELP_QUIT,(DWORD)0);

DeleteAllCounters();

PostQuitMessage(0);
return ERROR_SUCCESS;
}

// FUNCTION: WndProc(HWND, unsigned, WORD, LONG)
//
// PURPOSE: Processes messages for the main window.
//
// MESSAGES:
//
// WM_COMMAND - process the application menu
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
// WM_RBUTTONDOWN - Right mouse click -- put up context menu here if appropriate
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) {
case WM_CREATE:
return On_WM_CREATE (hWnd, wParam, lParam);

case WM_COMMAND:
return On_WM_COMMAND (hWnd, wParam, lParam);

case WM_RBUTTONDOWN: // RightClick in windows client area...
return On_WM_RBUTTONDOWN (hWnd, wParam, lParam);

case WM_PAINT:
return On_WM_PAINT (hWnd, wParam, lParam);

case WM_DESTROY:
return On_WM_DESTROY (hWnd, wParam, lParam);

default:
return (DefWindowProc(hWnd, message, wParam, lParam));
}
return (0);
}