How To Retrieve Performance Counter Value Using PDH (287158)



The information in this article applies to:

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

This article was previously published under Q287158

SUMMARY

Performance Data Helper (PDH) APIs can be used to collect performance data of various performance counters or instances that are available on the system. This article demonstrates the PDH API calls that are needed to collect performance data for a performance object, counter, and instance name.

MORE INFORMATION

The sample code below has a PDH_COUNTER_PATH_ELEMENTS CPE table that specifies the performance object, counter, and instance names for which the application is collecting the performance data.
#include <windows.h>
#include <pdh.h>
#include <stdio.h>

BOOL WINAPI GetCounterValues(LPTSTR serverName);

void main(int argc, char *argv[])
{
    if (argc > 1)
    {
        // argv[1] - Server Name

        GetCounterValues(argv[1]);
    }
    else
    {
        // Local System

        GetCounterValues(NULL);
    }
}

BOOL WINAPI GetCounterValues(LPTSTR serverName)
{
    PDH_STATUS s;

    HQUERY hQuery;

    // Array to specify the performance object, counter and instance for
    // which performance data should be collected.

    // typedef struct _PDH_COUNTER_PATH_ELEMENTS {
    //   LPTSTR  szMachineName;
    //   LPTSTR  szObjectName;
    //   LPTSTR  szInstanceName;
    //   LPTSTR  szParentInstance;
    //   DWORD   dwInstanceIndex;
    //   LPTSTR  szCounterName;
    // } PDH_COUNTER_PATH_ELEMENTS, *PPDH_COUNTER_PATH_ELEMENTS;

    // Each element in the array is a PDH_COUNTER_PATH_ELEMENTS structure.
    PDH_COUNTER_PATH_ELEMENTS cpe[] =
    {
        { NULL, "Memory", NULL, NULL, -1, "Cache Bytes" },
        { NULL, "Memory", NULL, NULL, -1, "Available Bytes" },
        { NULL, "Processor", "_Total", NULL, -1, "% Processor Time" }
    };

    HCOUNTER hCounter[sizeof(cpe)/sizeof(cpe[0])];

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

    BOOL  ret = FALSE;

    PDH_FMT_COUNTERVALUE counterValue;

    // Only do this setup once.
    if ((s = PdhOpenQuery(NULL, 0, &hQuery)) != ERROR_SUCCESS)
    {
        fprintf(stderr, "POQ failed %08x\n", s);
        return ret;
    }

    for (i = 0; i < sizeof(hCounter)/sizeof(hCounter[0]); i++)
    {
        cbPathSize = sizeof(szFullPath);

        cpe[i].szMachineName = serverName;

        if ((s = PdhMakeCounterPath(&cpe[i],
            szFullPath, &cbPathSize, 0)) != ERROR_SUCCESS)
        {
            fprintf(stderr,"MCP failed %08x\n", s);
            return ret;
        }

        if (cpe[i].szInstanceName)
        {
            printf("Adding [%s\\%s\\%s]\n",
                    cpe[i].szObjectName,
                    cpe[i].szCounterName,
                    cpe[i].szInstanceName);
        }
        else
            printf("Adding [%s\\%s]\n",
                    cpe[i].szObjectName,
                    cpe[i].szCounterName);

        if ((s = PdhAddCounter(hQuery, szFullPath, 0, &hCounter[i]))
            != ERROR_SUCCESS)
        {
            fprintf(stderr, "PAC failed %08x\n", s);
            return ret;
        }
    }

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

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

        if (i == 0) continue;

        // Extract the calculated performance counter value for each counter or
        // instance.
        for (j = 0; j < sizeof(hCounter)/sizeof(hCounter[0]); j++)
        {
            if ((s = PdhGetFormattedCounterValue(hCounter[j], PDH_FMT_DOUBLE,
                NULL, &counterValue)) != ERROR_SUCCESS)
            {
                fprintf(stderr, "PGFCV failed %08x\n", s);
                continue;
            }
            if (cpe[j].szInstanceName)
            {
                printf("%s\\%s\\%s\t\t : [%3.3f]\n",
                    cpe[j].szObjectName,
                    cpe[j].szCounterName,
                    cpe[j].szInstanceName,
                    counterValue.doubleValue);
            }
            else
                printf("%s\\%s\t\t : [%3.3f]\n",
                    cpe[j].szObjectName,
                    cpe[j].szCounterName,
                    counterValue.doubleValue);
        }
    }

    // Remove all the counters from the query.
    for (i = 0; i < sizeof(hCounter)/sizeof(hCounter[0]); i++)
    {
        PdhRemoveCounter(hCounter[i]);
    }

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

    return TRUE;
}
				

REFERENCES

PDH APIs are implemented in the Pdh.dll file that ships with the Microsoft Windows 2000 and Microsoft Windows XP operating system. For the Microsoft Windows NT 4.0 operating system, you can download a separate redistributable Pdh.dll version.

For additional information on how to obtain the redistributable version of Pdh.dll for Windows NT 4.0, click the article number below to view the article in the Microsoft Knowledge Base:

284996 FILE: Latest Redistributable PDH.dll Available for Windows NT 4.0

For additional information on the PDH APIs, see the "Performance Monitoring" topic in the "Base Services" section of the MSDN Library.

Modification Type:MinorLast Reviewed:3/22/2005
Keywords:kbAPI kbhowto kbKernBase kbPerfMon KB287158