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;
}