Figure 2   OBJLIST

OBJLIST.H

 #ifndef __Objlist_h__
#define __Objlist_h__

#ifndef _WINDOWS_
#include <windows.h>
#endif
#ifndef _WINPERF_
#include <winperf.h>
#endif
#ifndef __Perfsnap_h__
#include "perfsnap.h"
#endif

class CPerfObject;

class CPerfObjectList
{
    public:
        
    CPerfObjectList(CPerfSnapshot * const pPerfSnapshot,
                    CPerfTitleDatabase * const pPerfTitleDatabase );

    ~CPerfObjectList( void ){ };

    // Functions that return CPerfObject pointers.  Caller is responsible
    // for deleting the CPerfObject * when done with it.

    CPerfObject * GetFirstPerfObject( void );

    CPerfObject * GetNextPerfObject( void );
    
    CPerfObject * GetPerfObject( PTSTR const pszObjListName );

    protected:

    CPerfSnapshot * m_pPerfSnapshot;

    CPerfTitleDatabase * m_pPerfCounterTitles;

    unsigned m_currentObjectListIndex;

    PPERF_OBJECT_TYPE m_pCurrObjectType;    // current first/next object ptr
};

typedef CPerfObjectList * PCPerfObjectList;
#endif

OBJLIST.CPP

 //====================================
// File: OBJLIST.CPP
// Author: Matt Pietrek
// From: Microsoft Systems Journal
//       "Under the Hood", April 1996
//====================================
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include <winperf.h>
#include <stdlib.h>
#pragma hdrstop
#include "ctitledb.h"
#include "objlist.h"
#include "perfobj.h"
#include "makeptr.h"

CPerfObjectList::CPerfObjectList(
        CPerfSnapshot * const pPerfSnapshot,
        CPerfTitleDatabase * const pPerfTitleDatabase )
{
    m_pPerfSnapshot = pPerfSnapshot;
    m_pPerfCounterTitles = pPerfTitleDatabase;
}

CPerfObject *
CPerfObjectList::GetFirstPerfObject( void )
{
    m_currentObjectListIndex = 0;
    if ( m_currentObjectListIndex >= m_pPerfSnapshot->GetNumObjectTypes() )
        return 0;

    m_pCurrObjectType = 
        (PPERF_OBJECT_TYPE)m_pPerfSnapshot->GetPostHeaderPointer();

    return new CPerfObject( m_pCurrObjectType, m_pPerfCounterTitles );
}

CPerfObject *
CPerfObjectList::GetNextPerfObject( void )
{
    // Are we at the last object in the list?  Return NULL if so.
    if ( ++m_currentObjectListIndex >= m_pPerfSnapshot->GetNumObjectTypes() )
        return 0;

    // Advance to the next PERF_OBJECT_TYPE structure
    m_pCurrObjectType = MakePtr(PPERF_OBJECT_TYPE,
                                m_pCurrObjectType,
                                m_pCurrObjectType->TotalByteLength );
                                
    return new CPerfObject( m_pCurrObjectType, m_pPerfCounterTitles );
}
    
CPerfObject *
CPerfObjectList::GetPerfObject( PTSTR const pszObjListName )
{
    DWORD objListIdx
        = m_pPerfCounterTitles->GetIndexFromTitleString( pszObjListName );
    if ( 0 == objListIdx )
        return 0;

    // Point at first PERF_OBJECT_TYPE, and loop through the list, looking
    // for one that matches.
    PPERF_OBJECT_TYPE pCurrObjectType = 
            (PPERF_OBJECT_TYPE)m_pPerfSnapshot->GetPostHeaderPointer();

    for ( unsigned i=0; i < m_pPerfSnapshot->GetNumObjectTypes(); i++ )
    {
        // Is this the one that matches?
        if ( pCurrObjectType->ObjectNameTitleIndex == objListIdx )
            return new CPerfObject(pCurrObjectType, m_pPerfCounterTitles);

        // Nope... try the next object type
        pCurrObjectType = MakePtr(  PPERF_OBJECT_TYPE,
                                    pCurrObjectType,
                                    pCurrObjectType->TotalByteLength );
    }
    
    return 0;
}

Figure 3   PERFOBJ

PERFOBJ.H

 #ifndef __Perfobj_h__
#define __Perfobj_h__

#ifndef _WINDOWS_
#include <windows.h>
#endif
#ifndef _WINPERF_
#include <winperf.h>
#endif

class CPerfObjectInstance;

class CPerfObject
{
    public:
        
    CPerfObject(    PPERF_OBJECT_TYPE const pObjectList,
                    CPerfTitleDatabase * const pPerfTitleDatabase );

    ~CPerfObject( void ){ }
    
    // Functions that return CPerfObjectInstance pointers.  Caller is
    // responsible for deleting the CPerfObjectInstance * when done with it.

    CPerfObjectInstance * GetFirstObjectInstance( void );

    CPerfObjectInstance * GetNextObjectInstance( void );    

    unsigned GetObjectInstanceCount(void){return m_pObjectList->NumInstances;}

    BOOL GetObjectTypeName( PTSTR pszObjTypeName, DWORD nSize );

    protected:
        
    PPERF_OBJECT_TYPE m_pObjectList;

    unsigned m_currentObjectInstance;

    PPERF_INSTANCE_DEFINITION m_pCurrentObjectInstanceDefinition;
        
    CPerfTitleDatabase * m_pPerfCounterTitles;
};

typedef CPerfObject * PCPerfObject;
#endif

PERFOBJ.CPP

 //====================================
// File: PERFOBJ.CPP
// Author: Matt Pietrek
// From: Microsoft Systems Journal
//       "Under the Hood", APRIL 1996
//====================================
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include <winperf.h>
#include <stdlib.h>
#pragma hdrstop
#include "ctitledb.h"
#include "perfobj.h"
#include "objinst.h"
#include "makeptr.h"

CPerfObject::CPerfObject(   PPERF_OBJECT_TYPE const pObjectList,
                            CPerfTitleDatabase * const pPerfCounterTitles)
{
    m_pObjectList = pObjectList;
    m_pPerfCounterTitles = pPerfCounterTitles;
}

CPerfObjectInstance *
CPerfObject::GetFirstObjectInstance( void )
{
    m_currentObjectInstance = 0;
    if ( m_currentObjectInstance >= GetObjectInstanceCount() )
        return 0;

    // Point at the first PERF_INSTANCE_DEFINITION
    m_pCurrentObjectInstanceDefinition = 
        MakePtr( PPERF_INSTANCE_DEFINITION, m_pObjectList,
                m_pObjectList->DefinitionLength );

    return new CPerfObjectInstance(
                m_pCurrentObjectInstanceDefinition,
                MakePtr(PPERF_COUNTER_DEFINITION,
                        m_pObjectList, m_pObjectList->HeaderLength),
                m_pObjectList->NumCounters,
                m_pPerfCounterTitles,
                m_pObjectList->NumInstances ==
                    PERF_NO_INSTANCES ? TRUE : FALSE );
}

CPerfObjectInstance *
CPerfObject::GetNextObjectInstance( void )
{
    if ( m_pObjectList->NumInstances == PERF_NO_INSTANCES )
        return 0;

    if ( ++m_currentObjectInstance >= GetObjectInstanceCount() )
        return 0;

    // Advance to the next PERF_INSTANCE_DEFINITION in the list.  However,
    // following the current PERF_INSTANCE_DEFINITION is the counter data,
    // which is also of variable length.  So, we gotta take that into
    // account when finding the next PERF_INSTANCE_DEFINITION
        
    // First, get a pointer to the counter data size field
    PDWORD pCounterDataSize
        = MakePtr(PDWORD, m_pCurrentObjectInstanceDefinition,
                    m_pCurrentObjectInstanceDefinition->ByteLength);

    // Now we can point at the next PPERF_INSTANCE_DEFINITION
    m_pCurrentObjectInstanceDefinition = MakePtr(PPERF_INSTANCE_DEFINITION,
                m_pCurrentObjectInstanceDefinition,
                m_pCurrentObjectInstanceDefinition->ByteLength
                + *pCounterDataSize);
            
    // Create a CPerfObjectInstance based around the PPERF_INSTANCE_DEFINITION
    return new CPerfObjectInstance(m_pCurrentObjectInstanceDefinition,
                                   MakePtr(PPERF_COUNTER_DEFINITION,
                                           m_pObjectList, 
                                           m_pObjectList->HeaderLength),
                                   m_pObjectList->NumCounters,
                                   m_pPerfCounterTitles,
                                   FALSE );
}

BOOL
CPerfObject::GetObjectTypeName( PTSTR pszObjTypeName, DWORD nSize )
{
    PTSTR pszName = m_pPerfCounterTitles->GetTitleStringFromIndex(
                                    m_pObjectList->ObjectNameTitleIndex );
        
    if ( !pszName )
        return FALSE;
    
    lstrcpyn( pszObjTypeName, pszName, nSize );
    return TRUE;
}

Figure 4   OBJINST

OBJINST.H

 #ifndef __Obinst_h__
#define __Objinst_h__

#ifndef _WINDOWS_
#include <windows.h>
#endif
#ifndef _WINPERF_
#include <winperf.h>
#endif

class CPerfTitleDatabase;
class CPerfCounter;

class CPerfObjectInstance
{
    public:
        
    CPerfObjectInstance(
            PPERF_INSTANCE_DEFINITION const pPerfInstDef,
            PPERF_COUNTER_DEFINITION const pPerfCntrDef, DWORD nCounters,
            CPerfTitleDatabase * const pPerfTitleDatabase, BOOL fDummy );

    ~CPerfObjectInstance( void ){ }
    
    BOOL GetObjectInstanceName( PTSTR pszObjInstName, DWORD nSize );
    
    // Functions that return CPerfCounter pointers.  Caller is
    // responsible for deleting the CPerfCounter * when done with it.

    CPerfCounter * GetFirstCounter( void );

    CPerfCounter * GetNextCounter( void );

    CPerfCounter * GetCounterByName( PTSTR const pszName );

    protected:
        
    PPERF_INSTANCE_DEFINITION m_pPerfInstDef;

    unsigned m_nCounters;
    
    unsigned m_currentCounter;
    
    PPERF_COUNTER_DEFINITION m_pPerfCntrDef;

    CPerfTitleDatabase * m_pPerfCounterTitles;

    CPerfCounter * MakeCounter( PPERF_COUNTER_DEFINITION const pCounter );

    CPerfCounter * GetCounterByIndex( DWORD index );

    CPerfTitleDatabase *m_pCounterTitleDatabase;

    BOOL m_fDummy;  // FALSE normally, TRUE when an object with no instances
};

typedef CPerfObjectInstance * PCPerfObjectInstance;

#endif

OBJINST.CPP

 //====================================
// File: OBJINST.CPP
// Author: Matt Pietrek
// From: Microsoft Systems Journal
//       "Under the Hood", April 1996
//====================================
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include <winperf.h>
#include <stdlib.h>
#pragma hdrstop
#include "ctitledb.h"
#include "objinst.h"
#include "perfcntr.h"
#include "makeptr.h"

CPerfObjectInstance::CPerfObjectInstance(
        PPERF_INSTANCE_DEFINITION const pPerfInstDef,
        PPERF_COUNTER_DEFINITION const pPerfCntrDef,
        DWORD nCounters, CPerfTitleDatabase * const pPerfCounterTitles,
        BOOL fDummy)
{
    m_pPerfInstDef = pPerfInstDef;
    m_pPerfCntrDef = pPerfCntrDef;
    m_nCounters = nCounters;
    m_pPerfCounterTitles = pPerfCounterTitles;
    
    m_fDummy = fDummy;
}

BOOL
CPerfObjectInstance::GetObjectInstanceName(
    PTSTR pszObjInstName, DWORD nSize )
{
    if ( m_fDummy )
    {
        *pszObjInstName = 0;    // Return an empty string
        return FALSE;
    }
    
    if ( nSize < (m_pPerfInstDef->NameLength / sizeof(TCHAR)) )
        return FALSE;

    PWSTR pszName = MakePtr(PWSTR, m_pPerfInstDef, m_pPerfInstDef->NameOffset);
    
    #ifdef UNICODE
    lstrcpy( pszObjInstName, pszName );
    #else
    wcstombs( pszObjInstName, pszName, nSize );
    #endif
        
    return TRUE;
}

CPerfCounter *
CPerfObjectInstance::MakeCounter( PPERF_COUNTER_DEFINITION const pCounterDef )
{
    // Look up the name of this counter in the title database
    PTSTR pszName = m_pPerfCounterTitles->GetTitleStringFromIndex(
                                pCounterDef->CounterNameTitleIndex );
        
    DWORD nInstanceDefSize = m_fDummy ? 0 : m_pPerfInstDef->ByteLength;

    // Create a new CPerfCounter.  The caller is responsible for deleting it.
    return new CPerfCounter(pszName,
                            pCounterDef->CounterType,
                            MakePtr( PBYTE, m_pPerfInstDef,
                                    nInstanceDefSize +
                                    pCounterDef->CounterOffset ),
                            pCounterDef->CounterSize );
}

CPerfCounter *
CPerfObjectInstance::GetCounterByIndex( DWORD index )
{
    PPERF_COUNTER_DEFINITION pCurrentCounter;
    
    if ( index >= m_nCounters )
        return 0;
    
    pCurrentCounter = m_pPerfCntrDef;

    // Find the correct PERF_COUNTER_DEFINITION by looping
    for ( DWORD i = 0; i < index; i++ )
    {
        pCurrentCounter = MakePtr( PPERF_COUNTER_DEFINITION,
                                    pCurrentCounter,
                                    pCurrentCounter->ByteLength );
    }

    if ( pCurrentCounter->ByteLength == 0 )
        return 0;

    return MakeCounter( pCurrentCounter );
}

CPerfCounter *
CPerfObjectInstance::GetFirstCounter( void )
{
    m_currentCounter = 0;
    return GetCounterByIndex( m_currentCounter );
}

CPerfCounter *
CPerfObjectInstance::GetNextCounter( void )
{
    m_currentCounter++;
    return GetCounterByIndex( m_currentCounter );
}

CPerfCounter *
CPerfObjectInstance::GetCounterByName( PTSTR const pszName )
{
    DWORD cntrIdx = m_pPerfCounterTitles->GetIndexFromTitleString(pszName);
    if ( cntrIdx == 0 )
        return 0;
    
    PPERF_COUNTER_DEFINITION pCurrentCounter = m_pPerfCntrDef;

    // Find the correct PERF_COUNTER_DEFINITION by looping and comparing
    for ( DWORD i = 0; i < m_nCounters; i++ )
    {
        if ( pCurrentCounter->CounterNameTitleIndex == cntrIdx )
            return MakeCounter( pCurrentCounter );
        
        // Nope.  Not this one.  Advance to the next counter
        pCurrentCounter = MakePtr( PPERF_COUNTER_DEFINITION,
                                    pCurrentCounter,
                                    pCurrentCounter->ByteLength );
    }

    return 0;
}

Figure 5   PERFCNTR

PERFCNTR.H

 #ifndef __Perfcntr_h__
#define __Perfcntr_h__

class CPerfCounter
{
    public:

    CPerfCounter(   PTSTR const pszName, DWORD type,
                    PBYTE const pData, DWORD cbData );

    ~CPerfCounter( void );

    PTSTR GetName( void ) { return m_pszName; }

    DWORD GetType( void ) { return m_type; }
    
    BOOL GetData( PBYTE pBuffer, DWORD cbBuffer, DWORD *pType );
    
    BOOL Format( PTSTR pszBuffer, DWORD nSize, BOOL fHex = FALSE );

    protected:
        
    PTSTR m_pszName;

    DWORD m_type;

    PBYTE m_pData;
    
    DWORD m_cbData;
};

typedef CPerfCounter * PCPerfCounter;
#endif

PERFCNTR.CPP

 //====================================
// File: PERFCNTR.CPP
// Author: Matt Pietrek
// From: Microsoft Systems Journal
//       "Under the Hood", APRIL 1996
//====================================
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include <winperf.h>
#include <stdlib.h>
#include <malloc.h>
#include <tchar.h>
#pragma hdrstop
#include "perfcntr.h"

CPerfCounter::CPerfCounter( PTSTR const pszName, DWORD type,
                            PBYTE const pData, DWORD cbData )
{
    m_pszName = _tcsdup( pszName );
    m_type = type;
    m_cbData = cbData;
    m_pData = new BYTE[m_cbData];
    memcpy( m_pData, pData, m_cbData );
}

CPerfCounter::~CPerfCounter( void )
{
    free( m_pszName );
    delete []m_pData;
}

BOOL
CPerfCounter::GetData( PBYTE pBuffer, DWORD cbBuffer, DWORD *pType )
{
    if ( cbBuffer < m_cbData )  // Make sure the buffer is big enough
        return FALSE;
    
    memcpy( pBuffer, m_pData, m_cbData );   // copy the data

    if ( pType )            // If the user wants the type, give it to them
        *pType = m_type;
    
    return TRUE;
}
    
BOOL
CPerfCounter::Format( PTSTR pszBuffer, DWORD nSize, BOOL fHex )
{
    // Do better formatting!!!  Check length!!!

    PTSTR pszPrefix = TEXT("");
    TCHAR szTemp[512];
    
    // First, ascertain the basic type (number, counter, text, or zero)
    switch ( m_type & 0x00000C00 )
    {
        case PERF_TYPE_ZERO:
        {
            wsprintf( pszBuffer, TEXT("ZERO") ); return TRUE;
        }
        case PERF_TYPE_TEXT:
        {
            wsprintf( pszBuffer, TEXT("text counter") ); return TRUE;
        }
        case PERF_TYPE_COUNTER:
        {
            switch( m_type & 0x00070000 )
            {
                case PERF_COUNTER_RATE:
                    pszPrefix = TEXT("counter rate "); break;
                case PERF_COUNTER_FRACTION:
                    pszPrefix = TEXT("counter fraction "); break;
                case PERF_COUNTER_BASE:
                    pszPrefix = TEXT("counter base "); break;
                case PERF_COUNTER_ELAPSED:
                    pszPrefix = TEXT("counter elapsed "); break;
                case PERF_COUNTER_QUEUELEN:
                    pszPrefix = TEXT("counter queuelen "); break;
                case PERF_COUNTER_HISTOGRAM:
                    pszPrefix = TEXT("counter histogram "); break;
                default:
                    pszPrefix = TEXT("counter value "); break;
            }
        }
    }
    
    PTSTR pszFmt = fHex ? TEXT("%s%Xh") : TEXT("%s%u");
    
    switch ( m_cbData )
    {
        case 1: wsprintf(szTemp, pszFmt, pszPrefix, *(PBYTE)m_pData);
                break;
        case 2: wsprintf(szTemp, pszFmt, pszPrefix, *(PWORD)m_pData);
                break;
        case 4: wsprintf(szTemp, pszFmt, pszPrefix, *(PDWORD)m_pData);
                break;
        case 8: // Danger!  Assumes little-endian (X86) byte ordering
                wsprintf( szTemp, TEXT("%s%X%X"), pszPrefix,
                        *(PDWORD)(m_pData+4), *(PDWORD)m_pData ); break;
        default: wsprintf( szTemp, TEXT("<unhandled size %u>"), m_cbData );
    }
    
    switch ( m_type & 0x70000000 )
    {
        case PERF_DISPLAY_SECONDS:
            _tcscat( szTemp, TEXT(" secs") ); break;
        case PERF_DISPLAY_PERCENT:
            _tcscat( szTemp, TEXT(" %%") ); break;
        case PERF_DISPLAY_PER_SEC:
            _tcscat( szTemp, TEXT(" /sec") ); break;
    }

    lstrcpyn( pszBuffer, szTemp, nSize );
        
    return TRUE;
}

Figure 6   PERFDATA

PERFDATA.H

 #ifndef __Perfdata_h__
#define __Perfdata_h__
#include "ctitledb.h"
#include "perfsnap.h"
#include "objlist.h"
#include "perfobj.h"
#include "objinst.h"
#include "perfcntr.h"
#endif

PERFDATA.MS

 PROJ = PERFDATA

OBJS = ctitledb.obj perfsnap.obj objlist.obj perfobj.obj \
       objinst.obj perfcntr.obj

!if "$(DEBUG)" == "1"
DEBUG_FLAGS = /Zi /Od
!else
DEBUG_FLAGS = /O2
!endif
!if "$(UNICODE)" == "1"
UNICODE_FLAGS = /DUNICODE /D_UNICODE
!endif

CFLAGS = /W3 /MT /D_X86_ /DWIN32_LEAN_AND_MEAN /D"_WINDOWS" /D"WIN32" \
         $(DEBUG_FLAGS) $(UNICODE_FLAGS) /Fd"$(PROJ).PDB" /Fp"$(PROJ).PCH"

$(PROJ).LIB: $(OBJS)
    LIB -OUT:$(PROJ).LIB $(OBJS)

.cpp.obj:
    CL $(CFLAGS) /c $<

Figure 7   DEMO PROGRAMS

PERFENUM.CPP

 //==========================================================================
// File: PERFENUM.CPP
// Author: Matt Pietrek
// From: Microsoft Systems Journal
//       "Under the Hood", April 1996
// To Build:
//  CL /MT /DUNICODE /D_UNICODE /DWIN32 PERFENUM.CPP \
//      PERFDATA.LIB ADVAPI32.LIB USER32.LIB
//==========================================================================
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <tchar.h>
#pragma hdrstop
#include "perfdata.h"
#define MY_BUFF_SIZE 256

CPerfTitleDatabase gCounterTitles( PERF_TITLE_COUNTER );

int main( )
{
    CPerfSnapshot snapshot( &gCounterTitles );
    
    PTSTR pszCmdLineArgs = GetCommandLine();
    
    while ( *pszCmdLineArgs && (*pszCmdLineArgs != ' ') )
        pszCmdLineArgs++;
    
    if ( !snapshot.TakeSnapshot( pszCmdLineArgs ) )
    {
        _tprintf( TEXT("TakeSnapshot failed\n") );
        return 1;
    }
    
    _tprintf( TEXT("Object count: %u\n"), snapshot.GetNumObjectTypes() );
    
    TCHAR szSystemName[256];
    
    if ( !snapshot.GetSystemName( szSystemName, sizeof(szSystemName) ) )
    {
        _tprintf( TEXT("GetSystemName failed\n") );
        return 1;
    }
        
    _tprintf( TEXT("SystemName: %s\n"), szSystemName );

    CPerfObjectList objList( &snapshot, &gCounterTitles );
    
    CPerfObject * pPerfObj;
    
    for (   pPerfObj = objList.GetFirstPerfObject();
            pPerfObj;
            pPerfObj = objList.GetNextPerfObject() )
    {
        CPerfObjectInstance *pObjInst;
        TCHAR szObjTypeName[MY_BUFF_SIZE];
        
        pPerfObj->GetObjectTypeName( szObjTypeName, MY_BUFF_SIZE );
        
        _tprintf( TEXT("----------- %s object --------------\n"),szObjTypeName );

        for (   pObjInst = pPerfObj->GetFirstObjectInstance();
                pObjInst;
                pObjInst = pPerfObj->GetNextObjectInstance() )
        {
            TCHAR szObjName[MY_BUFF_SIZE];
            
            pObjInst->GetObjectInstanceName( szObjName, MY_BUFF_SIZE );
            _tprintf( TEXT("Instance name: %s\n"), szObjName );

            CPerfCounter * pPerfCntr;
            
            for (   pPerfCntr = pObjInst->GetFirstCounter();
                    pPerfCntr;
                    pPerfCntr = pObjInst->GetNextCounter() )
            {
                TCHAR szCounterData[MY_BUFF_SIZE];
                
                pPerfCntr->Format( szCounterData, MY_BUFF_SIZE );

                _tprintf(   TEXT("  %s: %s\n"),
                            pPerfCntr->GetName(), szCounterData );
                    
                delete pPerfCntr;
            }
            
            delete pObjInst;
            
            _tprintf( TEXT("\n") );
        }

        delete pPerfObj;
    }
            
    return 0;
}

WORKSET.CPP

 //==========================================================================
// File: WORKSET.CPP
// Author: Matt Pietrek
// From: Microsoft Systems Journal
//       "Under the Hood", April 1996
// To Build:
//  CL /MT /DUNICODE /D_UNICODE /DWIN32 WORKSET.CPP \
//      PERFDATA.LIB ADVAPI32.LIB USER32.LIB
//==========================================================================
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <winperf.h>
#include <tchar.h>
#pragma hdrstop
#include "perfdata.h"

int main( int argc, char *argv[] )
{
    BOOL fFoundProcess = FALSE; // Record if we found the specified process
    TCHAR szProgram[MAX_PATH];

    if ( argc != 2 ) // Make sure 1 argument was passed
    {
        _tprintf(   TEXT("WORKSET - Matt Pietrek 1996\n")
                    TEXT("Syntax:WORKSET <program name>\n") );
        return 1;
    }
    else // Store argv[1] into szProgram, converting from ANSI if need be
    {
        #ifdef UNICODE
        mbstowcs( szProgram, argv[1], sizeof(szProgram) );
        #else
        lstrcpyn( szProgram, argv[1], sizeof(szProgram) );
        #endif
    }
    
    // Make the title database and take a snapshot
    CPerfTitleDatabase gCounterTitles( PERF_TITLE_COUNTER );
    CPerfSnapshot snapshot( &gCounterTitles );
    
    if ( !snapshot.TakeSnapshot( TEXT("process") ) )
    {
        _tprintf( TEXT("Failed to take snapshot\n") ); return 1;
    }
    
    // Make the CPerfObjectList, and find the process object within it
    CPerfObjectList objectList( &snapshot, &gCounterTitles );
    
    PCPerfObject pPerfObj = objectList.GetPerfObject( TEXT("process") );
    if ( !pPerfObj )
    {
        _tprintf( TEXT("process performance object not found") ); return 1;
    }

    // Make an object instance pointer, and start iterating through instances
    // We'll go through all the instances, since there could be multiple
    // instances of a process running
    PCPerfObjectInstance pPerfObjInst;
    
    for (   pPerfObjInst = pPerfObj->GetFirstObjectInstance();
            pPerfObjInst;
            delete pPerfObjInst, pPerfObjInst =
                                 pPerfObj->GetNextObjectInstance() )
    {
        TCHAR szInstanceName[260];
        unsigned nSizeInstanceName = sizeof(szInstanceName) / sizeof(TCHAR);
        
        // Get the name of this instance.  Keep going if this fails.
        if ( !pPerfObjInst->GetObjectInstanceName(  szInstanceName,
                                                    nSizeInstanceName) )
            continue;
        
        // Is it the one specified on the command line?
        if ( lstrcmpi(szInstanceName, szProgram ) )
            continue;

        // Yes!  We found a matching process instance
        PCPerfCounter pCounter;
        pCounter = pPerfObjInst->GetCounterByName( TEXT("Working Set") );
                
        if ( !pCounter )    // Make sure we got the desired counter
        {
            _tprintf( TEXT("Working Set counter not found\n") ); return 0;
        }

        // Have the counter format a copy of its data, then print it out
        // Override the default 3rd argument to Format() to make the output
        // use hex, rather than decimal values.
        TCHAR szCounterDataStr[128];
        unsigned nSizeCounterDataStr = sizeof(szCounterDataStr)/sizeof(TCHAR);
        
        if (pCounter->Format(szCounterDataStr, nSizeCounterDataStr, TRUE))
            _tprintf( TEXT("Working set: %s bytes\n"), szCounterDataStr );

        delete pCounter;        // Don't need this counter object any more
        
        fFoundProcess = TRUE;   // Record that we found the desired process
    }
    
    delete pPerfObj;
    
    if ( FALSE == fFoundProcess )   // Let the user know if we didn't find it
        _tprintf( TEXT("process %s not found\n"), szProgram );
    
    return 0;
}