//==================================================
// PDHCounters - Matt Pietrek 1998
// Microsoft Systems Journal, May 1998
// FILE: PDHCounters.CPP
//==================================================
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <conio.h>
#pragma hdrstop
#include "pdh.h"
//================================ Function prototypes ======================
void ChangeCounter( void );
void ShowCounterHelp( HCOUNTER hCounter );
BOOL CheckForKeystrokes( void );
//=================================== Global Variables ======================
HQUERY g_hQuery = 0;
HCOUNTER g_hCounter = 0;
TCHAR g_szCounterPath[256];
//===================================== Code ================================
int main()
{
// Get a query handle
PdhOpenQuery( NULL, 0, &g_hQuery );
// Change the titlebar of the app console to provide a minimum of
// "online" help.
SetConsoleTitle(
_T("PDHCounters - 'h' for help, 'c' to change counter, 'e' to exit") );
// Bring up the dialog to select the initial counter
ChangeCounter( );
// Loop forever, or until the user hits 'e' (or CTRL-C)
while ( 1 )
{
PDH_FMT_COUNTERVALUE fmtValue;
PDH_RAW_COUNTER rawCtr;
if ( g_hCounter )
{
// Go update the data in the counters
PdhCollectQueryData( g_hQuery );
// Get the formatted version of the counter value
PdhGetFormattedCounterValue(g_hCounter,PDH_FMT_LONG,0, &fmtValue);
// Get the "raw" counter value.
PdhGetRawCounterValue( g_hCounter, 0, &rawCtr );
// Print out the counter path, the formatted value, and the
// raw value. (Note the use of %I64u to print a 64 bit number)
_tprintf( _T("%s %8u raw:%I64u\n"), g_szCounterPath,
fmtValue.longValue, (LONG)rawCtr.FirstValue );
}
// See if the user has hit a key command. Break out of the loop if
// the 'e' key is pressed.
if ( CheckForKeystrokes() )
break;
// Sleep for 1 second
Sleep( 1000 );
}
return 0;
}
// Function that lets the user change the current counter (g_hCounter).
// First, the function uses the PDH API that displays the counter browsing
// dialog. If a counter was selected, it is added to the query (g_hQuery),
// displacing the previous counter.
//
void ChangeCounter( void )
{
PDH_BROWSE_DLG_CONFIG brwDlgCfg;
TCHAR szCounterPath[256];
// Initialize all the fields of a PDH_BROWSE_DLG_CONFIG structure, in
// preparation for calling PdhBrowseCounters
brwDlgCfg.bIncludeInstanceIndex = FALSE;
brwDlgCfg.bSingleCounterPerAdd = FALSE;
brwDlgCfg.bSingleCounterPerDialog = 1;
brwDlgCfg.bLocalCountersOnly = 1;
brwDlgCfg.bWildCardInstances = 0;
brwDlgCfg.bHideDetailBox = 0;
brwDlgCfg.bInitializePath = 0;
brwDlgCfg.bReserved = 0;
brwDlgCfg.hWndOwner = 0;
brwDlgCfg.szReserved = 0;
brwDlgCfg.szReturnPathBuffer = szCounterPath;
brwDlgCfg.cchReturnPathLength = sizeof(szCounterPath);
brwDlgCfg.pCallBack = 0;
brwDlgCfg.dwCallBackArg = 0;
brwDlgCfg.CallBackStatus = 0;
brwDlgCfg.dwDefaultDetailLevel = PERF_DETAIL_WIZARD;
brwDlgCfg.szDialogBoxCaption = _T("PDHCounters - MSJ May 1998");
// Bring up the counter browsing dialog
if ( ERROR_SUCCESS != PdhBrowseCounters( &brwDlgCfg ) )
return;
// If there's already a counter in use, remove it from the query.
if ( g_hCounter )
PdhRemoveCounter( g_hCounter );
// Add the counter whose path was obtained via PdhBrowseCounters
PdhAddCounter( g_hQuery, szCounterPath, 0, &g_hCounter );
// Copy the counter path to a global variable copy of the string
lstrcpy( g_szCounterPath, szCounterPath );
}
// Given a counter value, this function calls the PDH API that retrieves the
// help text associated with a counter. The resulting string is displayed
// in a message box.
//
void ShowCounterHelp( HCOUNTER hCounter )
{
// If explain text is returned, it will immediately follow the
// formal PDH_COUNTER_INFO structure. Make a BYTE array big enough
// to contain the structure and the string buffer at the end.
BYTE counterBuff[ sizeof(PDH_COUNTER_INFO) + sizeof(TCHAR)*2048 ];
DWORD cbCounterBuff = sizeof(counterBuff);
if ( ERROR_SUCCESS != PdhGetCounterInfo( hCounter,
TRUE,
&cbCounterBuff,
(PPDH_COUNTER_INFO)counterBuff) )
{
MessageBox( 0, _T("PdhGetCounterInfo failed"), 0, MB_OK );
return;
}
// Make a pointer of the proper type to easily access the structure members
PPDH_COUNTER_INFO pCounterInfo = (PPDH_COUNTER_INFO)counterBuff;
MessageBox( 0, pCounterInfo->szExplainText, g_szCounterPath, MB_OK );
}
// Function that checks if a key was hit. If so, the key code is retrieved,
// and compared against a list of keys assigned to specific actions.
//
BOOL CheckForKeystrokes( void )
{
if ( _kbhit() ) // Bet you haven't seen this guy in a long time!
{
char chKeystroke = _getch(); // Or this one either!
if ( 'h' == chKeystroke ) // 'h' for help
ShowCounterHelp( g_hCounter );
else if ( 'c' == chKeystroke ) // 'c' for "change counter"
ChangeCounter();
else if ( 'e' == chKeystroke ) // 'e' for exit
return TRUE;
}
return FALSE;
}
Figure 3 PDHObjects
PDHObjects.h
#define IDD_PDHOBJECTS 1
#define IDC_TREE1 1000
PDHObjects.cpp
//==================================================
// PDHObjects - Matt Pietrek 1998
// Microsoft Systems Journal, May 1998
// FILE: PDHOBJECTS.CPP
//==================================================
#include <windows.h>
#include <stdio.h>
#include <COMMCTRL.H>
#include <tchar.h>
#pragma hdrstop
#include "pdh.h"
#include "PDHObjects.h"
// Helper function prototypes
void Handle_WM_INITDIALOG(HWND hDlg);
void Handle_WM_CLOSE( HWND hDlg );
BOOL CALLBACK PDHObjectsDlgProc(HWND,UINT,WPARAM,LPARAM);
void GetSetPositionInfoFromRegistry( BOOL fSave, POINT *lppt );
void PopulateTree( HWND hWndTree );
HTREEITEM AddTreeviewSubItem( HWND hWndTree, HTREEITEM hTreeItem,
LPTSTR pszItemText );
void AddObjectInstancesAndCounters( HWND hWndTree, HTREEITEM hTreeItem,
LPTSTR pszObject );
// ======================= String literals ===============================
TCHAR gszRegistryKey[]
= _T("Software\\WheatyProductions\\PDHObjects");
// ============================== Start of code ===============================
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpszCmdLine, int nCmdShow )
{
InitCommonControls();
// Bring up the user interface
DialogBox( hInstance, MAKEINTRESOURCE(IDD_PDHOBJECTS),
0, (DLGPROC)PDHObjectsDlgProc );
GetLastError();
return 0;
}
BOOL CALLBACK PDHObjectsDlgProc(HWND hDlg,UINT msg,WPARAM wParam,
LPARAM lParam )
{
//
// The dialog procedure for the main window
//
switch ( msg )
{
case WM_INITDIALOG:
Handle_WM_INITDIALOG( hDlg ); return TRUE;
case WM_CLOSE:
Handle_WM_CLOSE( hDlg ); break;
// let everything else fall through
}
return FALSE;
}
//============================================================================
// Walk through the list of objects, adding each object name to the root of
// the treeview
//============================================================================
void PopulateTree( HWND hWndTree )
{
PDH_STATUS status;
TCHAR mszObjects[2048];
DWORD sizeObjects = sizeof(mszObjects) / sizeof(TCHAR);
status = PdhEnumObjects(NULL,
NULL,
mszObjects,
&sizeObjects,
PERF_DETAIL_WIZARD,
TRUE );
if ( ERROR_SUCCESS != status )
{
_tprintf( _T("PdhEnumObjects failed - code:%u"), status );
return;
}
LPTSTR pszObject = mszObjects;
while ( *pszObject )
{
HTREEITEM hTreeItem = AddTreeviewSubItem( hWndTree, NULL, pszObject );
AddObjectInstancesAndCounters( hWndTree, hTreeItem, pszObject );
pszObject += lstrlen(pszObject) + 1;
}
}
//============================================================================
// Get all the object instances and counters for the named object, and add
// them as subitems in the treeview control
//============================================================================
void AddObjectInstancesAndCounters( HWND hWndTree, HTREEITEM hTreeItem,
LPTSTR pszObject )
{
PDH_STATUS status;
TCHAR mszCounterList[4096];
DWORD cchCounterList = sizeof(mszCounterList) / sizeof(TCHAR);
TCHAR mszInstanceList[4096];
DWORD cchInstanceList = sizeof(mszInstanceList) / sizeof(TCHAR);
status = PdhEnumObjectItems(
NULL,
NULL,
pszObject,
mszCounterList,
&cchCounterList,
mszInstanceList,
&cchInstanceList,
PERF_DETAIL_WIZARD,
0 );
if ( ERROR_SUCCESS != status )
return;
if ( cchInstanceList > 2 )
{
HTREEITEM hTreeInstances = AddTreeviewSubItem( hWndTree, hTreeItem,
_T("Instances") );
LPTSTR pszInstance = mszInstanceList;
while ( *pszInstance )
{
AddTreeviewSubItem( hWndTree, hTreeInstances, pszInstance );
pszInstance += lstrlen(pszInstance) + 1;
}
}
if ( cchCounterList > 2 )
{
HTREEITEM hTreeCounters = AddTreeviewSubItem( hWndTree, hTreeItem,
_T("Counters") );
LPTSTR pszCounter = mszCounterList;
while ( *pszCounter )
{
AddTreeviewSubItem(hWndTree, hTreeCounters, pszCounter);
pszCounter += lstrlen(pszCounter) + 1;
}
}
}
void Handle_WM_INITDIALOG(HWND hDlg)
{
// Get the window coordinates where the program was last running,
// and move the window to that spot.
POINT pt;
GetSetPositionInfoFromRegistry( FALSE, &pt );
SetWindowPos(hDlg, 0, pt.x, pt.y, 0, 0,
SWP_NOSIZE | SWP_NOREDRAW | SWP_NOZORDER | SWP_NOACTIVATE);
PopulateTree( GetDlgItem(hDlg, IDC_TREE1) );
}
void Handle_WM_CLOSE( HWND hDlg )
{
// Save off the window's X,Y coordinates for next time
RECT rect;
if ( GetWindowRect( hDlg, &rect ) )
GetSetPositionInfoFromRegistry( TRUE, (LPPOINT)&rect );
EndDialog(hDlg, 0);
}
void GetSetPositionInfoFromRegistry( BOOL fSave, POINT *lppt )
{
//
// Function that saves or restores the coordinates of a dialog box
// in the system registry. Handles the case where there's nothing there.
//
HKEY hKey;
DWORD dataSize, err, disposition;
TCHAR szKeyName[] = _T("DlgCoordinates");
if ( !fSave ) // In case the key's not there yet, we'll
lppt->x = lppt->y = 0; // return 0,0 for the coordinates
// Open the registry key (or create it if the first time being used)
err = RegCreateKeyEx( HKEY_CURRENT_USER, gszRegistryKey, 0, 0,
REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
0, &hKey, &disposition );
if ( ERROR_SUCCESS != err )
return;
if ( fSave ) // Save out coordinates
{
RegSetValueEx(hKey,szKeyName, 0, REG_BINARY,(PBYTE)lppt,sizeof(*lppt));
}
else // read in coordinates
{
dataSize = sizeof(*lppt);
RegQueryValueEx( hKey, szKeyName, 0, 0, (PBYTE)lppt, &dataSize );
}
RegCloseKey( hKey );
}
HTREEITEM AddTreeviewSubItem( HWND hWndTree, HTREEITEM hTreeItem,
LPTSTR pszItemText )
{
TVINSERTSTRUCT tvi;
tvi.hParent = hTreeItem;
tvi.hInsertAfter = TVI_LAST;
tvi.item.mask = TVIF_TEXT;
tvi.item.pszText = pszItemText;
tvi.item.cchTextMax = lstrlen( pszItemText );
return TreeView_InsertItem( hWndTree, &tvi );
}