Microsoft KB Archive/107728

{|
 * width="100%"|

INFO: Retrieving Counter Data from the Registry

 * }

Q107728

-

The information in this article applies to:


 * Microsoft Win32 Application Programming Interface (API), used with:
 * the operating system: Microsoft Windows NT, versions 3.1, 3.5, 3.51, 4.0

-

SUMMARY
The performance data begins with a structure of type PERF_DATA_BLOCK and is followed by PERF_DATA_BLOCK.NumObjectTypes data blocks. Each data block begins with a structure of type PERF_OBJECT_TYPE, followed by PERF_OBJECT_TYPE.NumCounters structures of type PERF_COUNTER_DEFINITION. Next, there are PERF_OBJECT_TYPE.NumInstances structures of type PERF_INSTANCE DEFINITION, each directly followed by an instance name, a structure of type PERF_COUNTER_BLOCK and PERF_OBJECT_TYPE.NumCounters counters. All of these data types are described in WINPERF.H.

On Windows NT 4.0 and Win2000, a simpler way to access performance data is to use the PDH.DLL (Performance Data Helper Library). For more information see the Platform SDK document in Base Service, Performance Monitoring, Performance Data, The PDH Interface.

MORE INFORMATION
The following steps are used to retrieve all of the counter information from the registry:


 * 1) Allocate a buffer to obtain the performance data. For single objects, you may need at little as 1.5K. For global objects, you may need as much as 50K. Call RegQueryValueEx to obtain the data. If the call returns ERROR_MORE_DATA, then the buffer size was not big enough. Increase the size of the buffer and try again. Repeat until the call is successful.
 * 2) Get the first object type in PerfObj.
 * 3) Get the first instance.
 * 4) Get the first counter and its data. At this point, if the object has no instances, the next thing will be a pointer to a single PERF_COUNTER_BLOCK; otherwise, the next thing will be a pointer to the first PERF_INSTANCE_DEFINITION. Check PerfObj->NumInstances to find out how many instances there are.
 * 5) Get the next counter and its data. Repeat for all PerfObj->NumCounters counters.
 * 6) After all counters are retrieved for the instance, get the next instance and all its counters. Repeat for all PerfObj->NumInstances instances.
 * 7) After all instances of the object type are retrieved, move to the next object type and repeat steps 3 - 7.

Sample Code
#include 
 * 1) include 
 * 2) include 


 * 1) define TOTALBYTES   8192
 * 2) define BYTEINCREMENT 1024

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;

// Allocate the buffer. 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 = (PPERF_OBJECT_TYPE)((PBYTE)PerfData +     PerfData->HeaderLength);

// Process all objects. for( i=0; i < PerfData->NumObjectTypes; i++ ) {     printf( "\nObject: %ld\n", PerfObj->ObjectNameTitleIndex );

// Get the counter block. PerfCntr = (PPERF_COUNTER_DEFINITION) ((PBYTE)PerfObj +                PerfObj->HeaderLength);

if( PerfObj->NumInstances > 0 ) {     // Get the first instance. PerfInst = (PPERF_INSTANCE_DEFINITION)((PBYTE)PerfObj +                   PerfObj->DefinitionLength);

// Retrieve all instances. for( k=0; k < PerfObj->NumInstances; k++ ) {           printf( "\n\tInstance: %S\n", (char *)((PBYTE)PerfInst + PerfInst->NameOffset) ); CurCntr = PerfCntr;

// Get the first counter. PtrToCntr = (PPERF_COUNTER_BLOCK)((PBYTE)PerfInst +                       PerfInst->ByteLength);

// Retrieve all counters. for( j=0; j < PerfObj->NumCounters; j++ ) {              printf("\t\tCounter: %ld\n",CurCntr->CounterNameTitleIndex); // Data is (LPVOID)((PBYTE)PtrToCntr + CurCntr->CounterOffset);

// Get next counter. CurCntr = (PPERF_COUNTER_DEFINITION)((PBYTE)CurCntr +                          CurCntr->ByteLength);

}

// Get the next instance. PerfInst = (PPERF_INSTANCE_DEFINITION)((PBYTE)PtrToCntr +                      PtrToCntr->ByteLength); }     }      else {     // Get the first counter. PtrToCntr = (PPERF_COUNTER_BLOCK) ((PBYTE)PerfObj +                    PerfObj->DefinitionLength );

// Retrieve all counters. for( j=0; j < PerfObj->NumCounters; j++ ) {           printf( "\tCounter: %ld\n", PerfCntr->CounterNameTitleIndex );

// Data is (LPVOID)((PBYTE)PtrToCntr + PerfCntr->CounterOffset);

PerfCntr = (PPERF_COUNTER_DEFINITION)((PBYTE)PerfCntr +                      PerfCntr->ByteLength); }     }

// Get the next object type. PerfObj = (PPERF_OBJECT_TYPE)((PBYTE)PerfObj +               PerfObj->TotalByteLength); } } Note that the instance names are retrieved in a fashion that is similar to retrieving the data.

The steps above showed how to obtain all of the counters. You can retrieve only the counters that pertain to a particular object by using the titles database. The information is stored in the registry in the format index, name, index, name, and so forth.

To retrieve the titles database and store it in TitlesDatabase:

  Open the key:      RegOpenKeyEx( HKEY_LOCAL_MACHINE,         "Software\\Microsoft\\Windows NT\\CurrentVersion\\Perflib\\009",                0,         KEY_READ,            &Hkey); Note that 009 is a language ID, so this value will be different on a non-English version of the operating system.   Query the information from the key:      RegQueryInfoKey(                   Hkey,         (LPTSTR) Class,             &ClassSize,                   NULL,                &Subkey,              MaxSubKey,              &MaxClass,                &Values,               &MaxName,               &MaxData,               &SecDesc,          &LastWriteTime );   Allocate a buffer to store the information:      TitlesDataBase = (PSTR) malloc( (MaxData+1) * sizeof(TCHAR) )   Retrieve the data:      RegQueryValueEx(     Hkey,            (LPTSTR) "Counters",                           NULL,                           NULL,        (LPBYTE) TitlesDataBase,                       &MaxData ); </li></ol>

Once you have the database, it is possible to write code that will go through all objects, searching by index (field ObjectNameTitleIndex) or by type (field ObjectNameTitle - which is initially NULL).

Or, you could obtain only the performance data for specified objects by changing the call to ReqQueryValueEx in step 1 of the SUMMARY section above to:

<pre class="FIXEDTEXT">  RegQueryValueEx( HKEY_PERFORMANCE_DATA,                           Indices,                              NULL,                              NULL,                          PerfData,                        &BufferSize ); Note that the only difference here is that instead of specifying "Global" as the second parameter, you specify a string that represents the decimal value(s) for the object(s) of interest that are obtained from the titles database.