15

Under Windows, performance counters have different names, depending on the operating system language. For example, on an English Windows version, there is the performance counter \Processor(_Total)\% Processor Time. The same counter is called \Prozessor(_Total)\Prozessorzeit (%) on a German Windows version.

Is there any way to retrieve the performance counter value in a language-independent way (using C++ or C#)? Or is there an alternative to get the processor load of the whole computer without performance counters?

5 Answers5

13

Each PerfMon counter is given a unique (per machine) integer ID to identify the PerfMon counter (however in the case of the standard counters this id is guaranteed to stay the same).

The information linking PerfMon counters id's to both their US English name and their Localized name is stored in the registry in the following key:

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

Once you have used the registry to obtain the PerfMon counter name (which you can embed in your app as a constant for standard counters) you can use the PdhLookupPerfNameByIndex function to look up the localized name for the given counter ID.

See Using PDH APIs correctly in a localized language (Microsoft KB) for more details.

You might also find Finding perfmon counter id via winreg (StackOverflow) somewhat relevant.

Community
  • 1
  • 1
Justin
  • 84,773
  • 49
  • 224
  • 367
  • 2
    I compared IDs and some of them are different on other computers. But there is a workaround: I look for ID in "009" key using English name, then I look for the localized name using PdhLookupPerfNameByIndex function. Source code: http://wojciechkulik.pl/csharp/get-a-performancecounter-using-english-name – Wojciech Kulik Dec 16 '15 at 01:30
1

Add this

using System.Runtime.InteropServices;
using Microsoft.Win32;

In your class import the DLL(my classed is named Program)

[DllImport("pdh.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        static extern UInt32 PdhLookupPerfIndexByName(string szMachineName, string szNameBuffer, ref uint pdwIndex);

Send the name of the counter you want in your OS language and it return the english NAME

public string GetEnglishName(string name)
        {
            string buffer2 = name;
            UInt32 iRet2 = new UInt32();
            iRet3 = PdhLookupPerfIndexByName(null, buffer2, ref iRet2);
            //Console.WriteLine(iRet2.ToString());

            RegistryKey pRegKey = Registry.LocalMachine;
            pRegKey = pRegKey.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\009");
            string[] after;
            after = (string[])pRegKey.GetValue("Counter");
            string value = iRet2.ToString();
            int pos = Array.IndexOf(after, value);
            return after[pos + 1];
        }

Here is how to use it

Program m = new Program();
            string result = m.GetEnglishName("Mémoire");
            Console.WriteLine(result);
Tek465B
  • 11
  • 2
0

There are the WinAPI functions, QueryHighPerformanceCounter and QueryHighPerformanceFrequency.

Puppy
  • 144,682
  • 38
  • 256
  • 465
  • Actually there is no "High" in the names! – Nawaz Apr 07 '11 at 13:44
  • These functions return the values of a high-precision timer that is used for performance counters. But you cannot use these functions to return the value of a performance counter like \Processor(_Total)\% Processor Time. –  Apr 07 '11 at 14:12
0

Have you tried using the Pdh helper functions and the PdhAddEnglishCounter function?

selbie
  • 100,020
  • 15
  • 103
  • 173
  • Unfortunately, this function is only available in Vista, Windows Server 2008, and higher. I also need to retrieve performance counters on Windows XP and Windows Server 2003. –  Apr 08 '11 at 05:29
0

My version of Full Path localization using PdhGetCounterInfoW.

std::wstring GetLocalizedCounterFullPath(const std::wstring& englishCounterName)
{
    std::wstring localizedCounterName;
    PDH_HQUERY queryHandle = nullptr;
    try
    {
        std::ostringstream errorText;
        auto status = PdhOpenQueryW(nullptr, 0, &queryHandle);

        if (status != ERROR_SUCCESS)
        {
            errorText << "PdhOpenQueryW failed with " << std::hex << status;
            throw std::runtime_error(errorText.str());
        }

        PDH_HCOUNTER counterHandle;
        status = PdhAddEnglishCounterW(queryHandle, englishCounterName.data(), 0, &counterHandle);
        if (status != ERROR_SUCCESS)
        {
            errorText << "PdhAddEnglishCounterW failed with " << std::hex << status;
            throw std::runtime_error(errorText.str());
        }

        DWORD bufferSize = 0;
        std::vector<unsigned char> counterInfo;
        do 
        {
            if (bufferSize != 0)
            {
                counterInfo.resize(bufferSize);
            }
            status = PdhGetCounterInfoW(counterHandle, 
                                        TRUE, 
                                        &bufferSize, 
                                        reinterpret_cast<PPDH_COUNTER_INFO_W>(counterInfo.data()));
        }
        while(static_cast<unsigned>(status) == PDH_MORE_DATA);
        
        if (status != ERROR_SUCCESS)
        {
            errorText << "PdhGetCounterInfoW failed with " << std::hex << status;
            throw std::runtime_error(errorText.str());
        }
        
        localizedCounterName = reinterpret_cast<PPDH_COUNTER_INFO_W>(counterInfo.data())->szFullPath;

        status = PdhCloseQuery(queryHandle);
        if (status != ERROR_SUCCESS)
        {
            errorText << "PdhCloseQuery failed with " << std::hex << status;
            throw std::runtime_error(errorText.str());
        }
    }
    catch (const std::exception& e)
    {
        std::wcout << e.what() << "\n";
        PdhCloseQuery(queryHandle);
    }
    
    return localizedCounterName;
}
Anton Agapov
  • 143
  • 1
  • 9