FIX: PdhExpandCounterPath Fails on Windows 2000 (274561)



The information in this article applies to:

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

This article was previously published under Q274561

SYMPTOMS

On Windows 2000, the PdhExpandCounterPath() API fails and a random error code is returned. Both the ANSI version of the API, PdhExpandCounterPathA(), and the Unicode version, PdhExpandCounterPathW(), exhibit this problem.

RESOLUTION

A supported fix is now available from Microsoft, but it is only intended to correct the problem that is described in this article. Apply it only to computers that are experiencing this specific problem. This fix may receive additional testing. Therefore, if you are not severely affected by this problem, Microsoft recommends that you wait for the next Windows 2000 Service Pack that contains this hotfix.

To resolve this problem immediately, contact Microsoft Product Support Services to obtain the fix. For a complete list of Microsoft Product Support Services phone numbers and information about support costs, visit the following Microsoft Web site:NOTE: In special cases, charges that are ordinarily incurred for support calls may be canceled if a Microsoft Support Professional determines that a specific update will resolve your problem. The typical support costs will apply to additional support questions and issues that do not qualify for the specific update in question.


STATUS

Microsoft has confirmed that this is a problem in Microsoft Windows 2000 and Microsoft Windows 2000 Service Pack 1.

MORE INFORMATION

If an application needs to determine all of the counter paths for a given performance object, the following algorithm can be used on Windows NT 4.0 as well as Windows 2000:
  1. Call the PdhEnumObjectItems() API to return the available counters and instances provided by a given object on a given computer.
  2. Call the PdhMakeCounterPath() API to create a full counter path from individual path members.

Sample Code

The following sample code demonstrates the problem with PdhExpandCounterPath(). It also demonstrates how to use the other Performance Data Helper (PDH) APIs to work around the problem. This code must be linked with Pdh.lib.

#define UNICODE
#define _UNICODE

#include <stdio.h>
#include <conio.h>
#include <tchar.h>

// The following headers require that this code be linked with Pdh.lib.
#include <pdh.h>     
#include <pdhmsg.h>

#define PATHSIZE 0xFFFF

void DemonstrateFailure() {

   // This routine will fail on Windows 2000 and Windows 2000 SP1
   // due to a bug in PdhExpandCounterPath().

   PTSTR szCtrPath  = NULL;
   DWORD cchCtrPath = 0;

   TCHAR szWildCardPath[MAX_PATH];

   PDH_STATUS pdhStatus;

   // Use the counter path format without specifying the computer.
   // \object(parent/instance#index)\counter

   _tcscpy(szWildCardPath, TEXT("\\Process(*/*#1)\\*"));

   // First try with an initial buffer size.
   szCtrPath = (PTSTR) GlobalAlloc(GPTR, PATHSIZE * sizeof(TCHAR));
   cchCtrPath = PATHSIZE;

   pdhStatus = PdhExpandCounterPath(szWildCardPath, szCtrPath, 
         &cchCtrPath);

   // Upon success, print all counter path names.
   if (pdhStatus == PDH_CSTATUS_VALID_DATA) {

      PTSTR ptr;

      ptr = szCtrPath;
      while (*ptr) {
         _tprintf(TEXT("[] %s\n"), ptr);
         ptr += _tcslen(ptr);
         ptr++;
      }

   } else 
      _tprintf(TEXT("PdhExpandCounterPath() failed: %X\n"), pdhStatus);

   GlobalFree((PVOID)szCtrPath);
}

void main() {

   PTSTR szCtrPath       = NULL;
   DWORD cchCtrPath      = 0;

   PTSTR szInstancePath  = NULL;
   DWORD cchInstancePath = 0;
   
   TCHAR szWildCardPath[MAX_PATH];
   TCHAR szFullCounterPath[MAX_PATH];
   
   PDH_COUNTER_PATH_ELEMENTS counterPath;

   PDH_STATUS pdhStatus;

   DemonstrateFailure();

   printf("\nPress any key to demonstrate the workaround...\n");
   _getch();

   _tcscpy(szWildCardPath, TEXT("Process"));

   szCtrPath = (PTSTR) GlobalAlloc(GPTR, PATHSIZE * sizeof(TCHAR));
   cchCtrPath = PATHSIZE;
   
   szInstancePath = (PTSTR) GlobalAlloc(GPTR, PATHSIZE * sizeof(TCHAR));
   cchInstancePath = PATHSIZE;

   pdhStatus = PdhEnumObjectItems(NULL, NULL, szWildCardPath, szCtrPath,
         &cchCtrPath, szInstancePath, &cchInstancePath, 
         PERF_DETAIL_WIZARD, 0);

   // Upon success, print all counter path names.
   if (pdhStatus == ERROR_SUCCESS) {

      PTSTR ptr, ptr1;

      counterPath.szMachineName = NULL;
      counterPath.szObjectName = szWildCardPath;
      counterPath.szParentInstance = NULL;
      counterPath.dwInstanceIndex = -1;

      ptr = szCtrPath;
      while (*ptr) {

         counterPath.szCounterName = ptr;
         ptr1 = szInstancePath;
         while (*ptr1) {

            counterPath.szInstanceName = ptr1;

            cchCtrPath = sizeof(szFullCounterPath);
            pdhStatus = PdhMakeCounterPath(&counterPath, 
                  szFullCounterPath, &cchCtrPath, 0);

            if (pdhStatus == ERROR_SUCCESS)
               _tprintf(TEXT("%s\n"), szFullCounterPath);
            else
               _tprintf(TEXT("PdhMakeCounterPath() failed : %X\n"),
                     pdhStatus);

            ptr1 += _tcslen(ptr1);
            ptr1++;
         }

         ptr += _tcslen(ptr);
         ptr++;
      }
   }
   else 
      _tprintf(TEXT("PdhEnumObjectItems() failed: %X\n"), pdhStatus);

   GlobalFree((PVOID) szCtrPath);
   GlobalFree((PVOID) szInstancePath);
}
				

REFERENCES

For additional information about how to install Windows 2000 and Windows 2000 hotfixes at the same time, click the article number below to view the article in the Microsoft Knowledge Base:

249149 Installing Microsoft Windows 2000 and Windows 2000 Hotfixes

For additional information on the PDH APIs, refer to the Performance Monitoring topics in the Base Services section of the MSDN Library.

Modification Type:MinorLast Reviewed:10/7/2005
Keywords:kbAPI kbBug kbfix kbKernBase kbPerfMon KB274561