Figure 1    PDHCounters.CPP


 //==================================================
 // 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 );
 }