Microsoft KB Archive/287157

{|
 * width="100%"|

INFO: PDH Sample Code to Enumerate Performance Counters and Instances

 * }

Q287157

-

The information in this article applies to:


 * Microsoft Win32 Application Programming Interface (API), used with:
 * the operating system: Microsoft Windows 2000
 * the operating system: Microsoft Windows NT 4.0

-

SUMMARY
Performance Data Helper (PDH) APIs can be used to enumerate performance counters and instances of a specified object on a specified computer. This article explains the sequence of PDH API calls needed.

MORE INFORMATION
The sample code below demonstrates the how to obtain the performance counters and instances of a specified object. After the list is obtained, a counter path is constructed for each instance and the performance data value is obtained once.

#include 
 * 1) include 
 * 2) include 
 * 3) include 

void WINAPI GetCounterValues(LPTSTR serverName, LPTSTR objectName,                            LPTSTR counterList, LPTSTR instanceList); void WINAPI EnumerateExistingInstances(LPTSTR serverName, LPTSTR objectName);

void main(int argc, char *argv[]) {   if (argc > 1) {       // argv[1] - Server Name EnumerateExistingInstances(argv[1], &quot;Thread&quot;); }   else {       // Local System EnumerateExistingInstances(NULL, &quot;Thread&quot;); } }

/////////////////////////////////////////////////////////////////////////////// // // FUNCTION:     GetCounterValues - This function constructs a counter path //               from the counter and instance names obtained. The constructed //               counter path is then used to get the performance data using //               PdhCollectQueryData. // // RETURN VALUE: none // /////////////////////////////////////////////////////////////////////////////// void WINAPI GetCounterValues(LPTSTR serverName, LPTSTR objectName,                            LPTSTR counterList, LPTSTR instanceList) {   PDH_STATUS s;

HQUERY hQuery;

PDH_COUNTER_PATH_ELEMENTS *cpe = NULL; PDH_COUNTER_PATH_ELEMENTS *cpeBeg;

DWORD nCounters; DWORD nInstances;

HCOUNTER *hCounter = NULL; HCOUNTER *hCounterPtr;

char *counterPtr, *instancePtr;

char szFullPath[MAX_PATH]; DWORD cbPathSize; DWORD  i, j;

BOOL ret = FALSE;

PDH_FMT_COUNTERVALUE counterValue;

// Scan through the counter names to find the number of counters. nCounters = 0; counterPtr = counterList; while (*counterPtr) {       counterPtr += strlen(counterPtr) + 1; nCounters++; }

// Scan through the instance names to find the number of instances. nInstances = 0; instancePtr = instanceList; while (*instancePtr) {       instancePtr += strlen(instancePtr) + 1; nInstances++; }

if (!nCounters || !nInstances) return;

__try {       cpe = (PDH_COUNTER_PATH_ELEMENTS *)HeapAlloc(GetProcessHeap, 0,                     sizeof(PDH_COUNTER_PATH_ELEMENTS) * nCounters * nInstances); hCounter = (HCOUNTER *)HeapAlloc(GetProcessHeap, 0,                    sizeof(HCOUNTER) * nCounters * nInstances);

if (!cpe || !hCounter) __leave;

// Only do this once to create a query. if ((s = PdhOpenQuery(NULL, 0, &hQuery)) != ERROR_SUCCESS) {           fprintf(stderr, &quot;POQ failed %08x\n&quot;, s); __leave; }

// For each instance name in the list, construct a counter path. cpeBeg = cpe; hCounterPtr = hCounter; for (i = 0, counterPtr = counterList; i < nCounters;               i++, counterPtr += strlen(counterPtr) + 1) {           for (j = 0, instancePtr = instanceList; j < nInstances;                    j++,                    instancePtr += strlen(instancePtr) + 1,                    cpeBeg++,                    hCounterPtr++) {               cbPathSize = sizeof(szFullPath);

cpeBeg->szMachineName = serverName; cpeBeg->szObjectName = objectName; cpeBeg->szInstanceName = instancePtr; cpeBeg->szParentInstance = NULL; cpeBeg->dwInstanceIndex = -1; cpeBeg->szCounterName = counterPtr;

if ((s = PdhMakeCounterPath(cpeBeg,                   szFullPath, &cbPathSize, 0)) != ERROR_SUCCESS) {                   fprintf(stderr,&quot;MCP failed %08x\n&quot;, s); __leave; }

// Add the counter path to the query. if ((s = PdhAddCounter(hQuery, szFullPath, 0, hCounterPtr))                       != ERROR_SUCCESS) {                   fprintf(stderr, &quot;PAC failed %08x\n&quot;, s); __leave; }           }        }

for (i = 0; i < 2; i++) {           Sleep(100);

// Collect data as often as you need to. if ((s = PdhCollectQueryData(hQuery)) != ERROR_SUCCESS) {               fprintf(stderr, &quot;PCQD failed %08x\n&quot;, s); __leave; }

if (i == 0) continue;

// Display the performance data value corresponding to each instance. cpeBeg = cpe; hCounterPtr = hCounter; for (i = 0, counterPtr = counterList; i < nCounters;                   i++, counterPtr += strlen(counterPtr) + 1) {               for (j = 0, instancePtr = instanceList; j < nInstances;                        j++,                        instancePtr += strlen(instancePtr) + 1,                        cpeBeg++,                        hCounterPtr++) {                   if ((s = PdhGetFormattedCounterValue(*hCounterPtr,                        PDH_FMT_DOUBLE,                        NULL, &counterValue)) != ERROR_SUCCESS) {                       fprintf(stderr, &quot;PGFCV failed %08x\n&quot;, s); continue; }                   printf(&quot;%s\\%s\\%s\t\t : [%3.3f]\n&quot;,                        cpeBeg->szObjectName,                        cpeBeg->szCounterName,                        cpeBeg->szInstanceName,                        counterValue.doubleValue); }           }        }

// Remove all the performance counters from the query. hCounterPtr = hCounter; for (i = 0; i < nCounters; i++) {           for (j = 0; j < nInstances; j++) {               PdhRemoveCounter(*hCounterPtr); }       }    }    __finally {       HeapFree(GetProcessHeap, 0, cpe); HeapFree(GetProcessHeap, 0, hCounter);

// Only do this cleanup once. PdhCloseQuery(hQuery); }

return; }

/////////////////////////////////////////////////////////////////////////////// // // FUNCTION:     EnumerateExistingInstances - This function displays the names //               of all the instances that exist on ServerName. PDH is used //               to enumerate the performance counter and instance names. // // RETURN VALUE: none // ///////////////////////////////////////////////////////////////////////////////

void WINAPI EnumerateExistingInstances(LPTSTR serverName, LPTSTR objectName) {   TCHAR       mszEmptyList[2];  // An empty list contains 2 NULL characters LPTSTR     mszInstanceList = NULL; LPTSTR     szInstanceName; DWORD      cchInstanceList; LPTSTR     mszCounterList = NULL; DWORD      cchCounterList; PDH_STATUS pdhStatus;

__try {       mszCounterList = NULL; cchCounterList = 0; // Refresh the list of performance objects available on the specified // computer by making a call to PdhEnumObjects with bRefresh set to TRUE. pdhStatus = PdhEnumObjects(NULL, serverName, mszCounterList,           &cchCounterList, PERF_DETAIL_WIZARD, TRUE);

mszCounterList = NULL; cchCounterList = 0; // Determine the required size for the buffer containing counter names // and instance names by calling PdhEnumObjectItems. cchInstanceList = sizeof(mszEmptyList); pdhStatus = PdhEnumObjectItems(NULL, serverName,           objectName, mszCounterList,             &cchCounterList, mszEmptyList,            &cchInstanceList, PERF_DETAIL_WIZARD, 0);

if (pdhStatus == ERROR_SUCCESS) return; // The list is empty so do nothing. else if (pdhStatus != PDH_MORE_DATA) {           fprintf(stderr, &quot;PEOI failed %08x\n&quot;, pdhStatus); return; }

// Allocate a buffer for the counter names. mszCounterList = (LPTSTR)HeapAlloc(GetProcessHeap,           HEAP_ZERO_MEMORY, cchCounterList); if (!mszCounterList) {           fprintf(stderr, &quot;HA failed %08x\n&quot;, GetLastError); return; }

// Allocate a buffer for the instance names. mszInstanceList = (LPTSTR)HeapAlloc(GetProcessHeap, HEAP_ZERO_MEMORY,           cchInstanceList); if (!mszInstanceList) {           fprintf(stderr, &quot;HA failed %08x\n&quot;, GetLastError); return; }

__try {           // Enumerate to get the list of Counters and Instances provided by            // the specified object on the specified computer. pdhStatus = PdhEnumObjectItems(NULL, serverName,               objectName, mszCounterList,                 &cchCounterList, mszInstanceList,                &cchInstanceList, PERF_DETAIL_WIZARD, 0); if (pdhStatus != ERROR_SUCCESS) {               fprintf(stderr, &quot;PEOI failed %08x\n&quot;, pdhStatus); return; }

// Display the items from the buffer. szInstanceName = mszInstanceList; while (*szInstanceName) {               printf(&quot;%s\n&quot;, szInstanceName); szInstanceName += strlen(szInstanceName) + 1; }

GetCounterValues(serverName, objectName, mszCounterList,               mszInstanceList); }       __finally {       }

}   __finally {       // Free the buffers. if (mszInstanceList) HeapFree(GetProcessHeap, 0, mszInstanceList); if (mszCounterList) HeapFree(GetProcessHeap, 0, mszCounterList); }

return; }