Displaying Object, Instance, and Counter Names

The following example displays the index and name of each object, along with the indices and names of its counters.

The object and counter names are stored in the registry, by index. This example creates a function, GetNameStrings, to load the indices and names of each object and counter from the registry into an array, so that they can be easily accessed. GetNameStrings uses the following standard registry functions to access the data: RegOpenKey, RegCloseKey, RegQueryInfoKey, and RegQueryValueEx.

This example creates the following functions for navigating the performance data: FirstObject, FirstInstance, FirstCounter, NextCounter, NextInstance, and NextCounter. These functions navigate the performance data by using the offsets stored in the performance structures.

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>

#define TOTALBYTES    8192
#define BYTEINCREMENT 1024

LPSTR lpNameStrings;
LPSTR *lpNamesArray;

/*****************************************************************
 *                                                               *
 * Functions used to navigate through the performance data.      *
 *                                                               *
 *****************************************************************/

PPERF_OBJECT_TYPE FirstObject( PPERF_DATA_BLOCK PerfData )
{
    return( (PPERF_OBJECT_TYPE)((PBYTE)PerfData + 
        PerfData->HeaderLength) );
}

PPERF_OBJECT_TYPE NextObject( PPERF_OBJECT_TYPE PerfObj )
{
    return( (PPERF_OBJECT_TYPE)((PBYTE)PerfObj + 
        PerfObj->TotalByteLength) );
}

PPERF_INSTANCE_DEFINITION FirstInstance( PPERF_OBJECT_TYPE PerfObj )
{
    return( (PPERF_INSTANCE_DEFINITION)((PBYTE)PerfObj + 
        PerfObj->DefinitionLength) );
}

PPERF_INSTANCE_DEFINITION NextInstance( 
    PPERF_INSTANCE_DEFINITION PerfInst )
{
    PPERF_COUNTER_BLOCK PerfCntrBlk;

    PerfCntrBlk = (PPERF_COUNTER_BLOCK)((PBYTE)PerfInst + 
        PerfInst->ByteLength);

    return( (PPERF_INSTANCE_DEFINITION)((PBYTE)PerfCntrBlk + 
        PerfCntrBlk->ByteLength) );
}

PPERF_COUNTER_DEFINITION FirstCounter( PPERF_OBJECT_TYPE PerfObj )
{
    return( (PPERF_COUNTER_DEFINITION) ((PBYTE)PerfObj + 
        PerfObj->HeaderLength) );
}

PPERF_COUNTER_DEFINITION NextCounter( 
    PPERF_COUNTER_DEFINITION PerfCntr )
{
    return( (PPERF_COUNTER_DEFINITION)((PBYTE)PerfCntr + 
        PerfCntr->ByteLength) );
}

/*****************************************************************
 *                                                               *
 * Load the counter and object names from the registry to the    *
 * global variable lpNamesArray.                                 *
 *                                                               *
 *****************************************************************/

void GetNameStrings( )
{
    HKEY hKeyPerflib;      // handle to registry key
    HKEY hKeyPerflib009;   // handle to registry key
    DWORD dwMaxValueLen;   // maximum size of key values
    DWORD dwBuffer;        // bytes to allocate for buffers
    DWORD dwBufferSize;    // size of dwBuffer
    LPSTR lpCurrentString; // pointer for enumerating data strings
    DWORD dwCounter;       // current counter index

// Get the number of Counter items.

    RegOpenKeyEx( HKEY_LOCAL_MACHINE,
        "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib",
        0,
        KEY_READ,
        &hKeyPerflib);

    dwBufferSize = sizeof(dwBuffer);

    RegQueryValueEx( hKeyPerflib,
        "Last Counter",
        NULL,
        NULL,
        (LPBYTE) &dwBuffer,
        &dwBufferSize );

    RegCloseKey( hKeyPerflib );

// Allocate memory for the names array.

    lpNamesArray = malloc( (dwBuffer+1) * sizeof(LPSTR) );

// Open key containing counter and object names.

    RegOpenKeyEx( HKEY_LOCAL_MACHINE,
    "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib\\009",
        0,
        KEY_READ,
        &hKeyPerflib009);

// Get the size of the largest value in the key (Counter or Help).

    RegQueryInfoKey( hKeyPerflib009,
        NULL,
        NULL,
        NULL,
        NULL,
        NULL,
        NULL,
        NULL,
        NULL,
        &dwMaxValueLen,
        NULL,
        NULL);

// Allocate memory for the counter and object names.

    dwBuffer = dwMaxValueLen + 1;

    lpNameStrings = malloc( dwBuffer * sizeof(CHAR) );

// Read Counter value.

    RegQueryValueEx( hKeyPerflib009,
        "Counter",
        NULL,
        NULL,
        lpNameStrings, &dwBuffer );

// Load names into an array, by index.

    for( lpCurrentString = lpNameStrings; *lpCurrentString;
         lpCurrentString += (lstrlen(lpCurrentString)+1) )
    {
        dwCounter = atol( lpCurrentString );

        lpCurrentString += (lstrlen(lpCurrentString)+1);

        lpNamesArray[dwCounter] = (LPSTR) lpCurrentString;
    }
}

/*****************************************************************
 *                                                               *
 * Display the indices and/or names for all performance objects, *
 * instances, and counters.                                      *
 *                                                               *
 *****************************************************************/

void main()
{
    PPERF_DATA_BLOCK PerfData = NULL;
    PPERF_OBJECT_TYPE PerfObj;
    PPERF_INSTANCE_DEFINITION PerfInst;
    PPERF_COUNTER_DEFINITION PerfCntr, CurCntr;
    PPERF_COUNTER_BLOCK PtrToCntr;
    DWORD BufferSize = TOTALBYTES;
    DWORD i, j, k;

// Get the name strings through the registry.

    GetNameStrings( );

// Allocate the buffer for the performance data.

    PerfData = (PPERF_DATA_BLOCK) malloc( BufferSize );

    while( RegQueryValueEx( HKEY_PERFORMANCE_DATA,
                               "Global",
                               NULL,
                               NULL,
                               (LPBYTE) PerfData,
                               &BufferSize ) == ERROR_MORE_DATA )
    {
    // Get a buffer that is big enough.

        BufferSize += BYTEINCREMENT;
        PerfData = (PPERF_DATA_BLOCK) realloc( PerfData, BufferSize );
    }

// Get the first object type.

    PerfObj = FirstObject( PerfData );

// Process all objects.

    for( i=0; i < PerfData->NumObjectTypes; i++ )
    {
    // Display the object by index and name.

        printf( "\nObject %ld: %s\n", PerfObj->ObjectNameTitleIndex,
            lpNamesArray[PerfObj->ObjectNameTitleIndex] );

    // Get the first counter.

        PerfCntr = FirstCounter( PerfObj );

        if( PerfObj->NumInstances > 0 )
        {
        // Get the first instance.

            PerfInst = FirstInstance( PerfObj );

        // Retrieve all instances.

            for( k=0; k < PerfObj->NumInstances; k++ )
            {
            // Display the instance by name.

                printf( "\n\tInstance %S: \n", 
                    (char *)((PBYTE)PerfInst + PerfInst->NameOffset));
                CurCntr = PerfCntr;

            // Retrieve all counters.

                for( j=0; j < PerfObj->NumCounters; j++ )
                {
                // Display the counter by index and name.

                    printf("\t\tCounter %ld: %s\n", 
                        CurCntr->CounterNameTitleIndex,
                        lpNamesArray[CurCntr->CounterNameTitleIndex]);

                // Get the next counter.

                    CurCntr = NextCounter( CurCntr );
                }

            // Get the next instance.

                PerfInst = NextInstance( PerfInst );
            }
        }
        else
        {
        // Get the counter block.

            PtrToCntr = (PPERF_COUNTER_BLOCK) ((PBYTE)PerfObj +
                            PerfObj->DefinitionLength );

        // Retrieve all counters.

            for( j=0; j < PerfObj->NumCounters; j++ )
            {
            // Display the counter by index and name.

                printf( "\tCounter %ld: %s\n", PerfCntr->CounterNameTitleIndex,
                    lpNamesArray[PerfCntr->CounterNameTitleIndex] );

            // Get the next counter.

                PerfCntr = NextCounter( PerfCntr );
            }
        }

    // Get the next object type.

        PerfObj = NextObject( PerfObj );
    }
}