Using PDH APIs correctly in a localized language


Performance Data Helper (PDH) APIs use object and counter names that are in the localized language. Therefore, applications that use PDH APIs should always use the localized string for the object or counter name specification. Before collecting performance data, the application must know the object or counter name in the application. If the name of the objects and counters is known only as an English string in the application, there are some additional steps that you must perform on a system that uses a localized language, such as French or German. This article explains the steps that are required.

More Information

Applications that retrieve object and counter names by using the PdhEnumObjects() or PdhEnumObjectItems() APIs will always have strings that correspond to the localized language. If the application is interested in collecting the performance data of all performance objects, counters, and instances, it can use the names that are returned by the PdhEnumObjects() API or the PdhEnumObjectItems() API to construct a counter path in the localized language and then add the counter by using the PdhAddCounter() API to a PDH query. If the performance data is collected in this manner, then the application will work correctly in each localized language.

However, there are situations where an application is interested in collecting performance data of only a particular performance object, counter, and instance. In such cases, the application must know the localized language name in PDH API calls that take a name, such as PdhAddCounter(). However, each of the objects and counters have different "user-friendly" names in each localized language. These user-friendly names are exposed by the respective performance extension DLL in an .ini file for each localized language. For example, objects have a user friendly name such as "Process" in English. In German or French, the same object is represented by a user-friendly name in the corresponding language, and the name is not a string that is directly converted from ANSI to UNICODE. Likewise, the counter has a user-friendly name such as "% Processor Time" in English. However, instances do not have a user friendly name in each language. In a non-English version of Windows NT or Windows 2000, object and counter strings are stored both in the native language of the system and in English. Each object or counter is identified by an object or counter index respectively. The object or counter index and name mapping information is stored in the Counter registry value under the following registry key:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\LangId

where LangId is 009 for US English. The Counter registry value is of type REG_MULTI_SZ and can be viewed only by using Regedt32. The index value for the base system counters and objects such as processor, process, thread, and memory, are always the same irrespective of the localized version of the operating system or service pack installed. However, the index value of objects that are returned by a performance extension DLL will be different on different systems. A performance extension can be installed on top of the base operating system by using the LODCTR.exe utility. LODCTR.exe generates indexes from the .ini file supplied to this utility. Therefore, the index value for performance extension counter providers such as Microsoft Internet Information Server, and Microsoft SQL Server, will be different from system to system, depending on installation sequence.

If the application knows the object and counter names only as English strings, these names can be converted to the corresponding localized names as follows.

Use the Registry API to obtain the counter titles and indexes in English as follows:
dwStatus = RegQueryValueEx(
"Counter 009",
The lpmszCounters buffer is filled with the multi-string value, including the object and counter names with the indexes. The "009" is for English. The format is index string followed by name string, and then index string followed by name string terminated by another NULL character at the end. The application can get this list once, which can be used to get the ID corresponding to an English object/counter string. Once the index for a performance object as well as counter has been identified, the application can find the localized object or counter name from the index by using the PdhLookupPerfNameByIndex() API. The localized object and counter name returned by this API can then be used in other PDH API calls that take object or counter names. If the performance object or counter name is collected by using the PdhLookupPerfNameByIndex() API, then the application will work correctly in each localized language.

If the application is distributed and stores the English counter strings on a system other then the monitored system, the application may experience a problem if there are duplicate counters with the same English name. To obtain the object or counter ID that maps to the English string is ambiguous. To work around this problem in your applications, use exception handling logic.


PDH APIs are implemented in the PDH.dll file, and this DLL in included with Windows 2000. For Windows NT 4.0, you must download a separate redistributable PDH.dll file version.For additional information about how to obtain this file for Windows NT 4.0, click the following article number to view the article in the Microsoft Knowledge Base:

284996 Latest redistributable PDH.dll available for Windows NT 4.0

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

Article ID: 287159 - Last Review: Nov 21, 2006 - Revision: 1