你误解了PdhLookupPerfNameByIndex()的工作方式。它的任务不是映射性能计数器,而是映射一个字符串。应该同时用于计数器类别和名称,但不适用于计数器实例(如果适用,则不进行本地化)。
最好的方法是使用Regedit.exe来查看它的工作过程。导航到HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib。请注意"009"键,它的Counter值具有英文字符串映射的索引。双击Counter并将框中的内容复制粘贴到文本编辑器中以更好地查看。"CurrentLanguage"键是相同的映射,但使用本地化名称。
所以PdhLookupPerfNameByIndex()使用CurrentLanguage键,使用您在上一步获取的列表来确定字符串的索引编号。另一种方法是如KB文章底部所述(令人困惑),首先从"009"注册表键查找索引号。这样可以从英文字符串翻译为本地化字符串。请注意,KB文章错误地记录了注册表键的位置,原因不明。
请记住,这不是完美的,正如KB文章中指出的那样,这些映射仅存在于"base"计数器中,而"009"键是含糊不清的,因为某些索引映射到相同的字符串。在本地化的Windows版本上进行测试非常重要。
以下是一些双向执行它的代码:
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Win32;
using System.Diagnostics;
using System.Runtime.InteropServices;
public static class PerfMapper {
private static Dictionary<string, int> English;
private static Dictionary<int, string> Localized;
public static PerformanceCounter FromEnglish(string category, string name, string instance = null) {
return new PerformanceCounter(Map(category), Map(name), instance);
}
public static PerformanceCounter FromIndices(int category, int name, string instance = null) {
return new PerformanceCounter(PdhMap(category), PdhMap(name), instance);
}
public static bool HasName(string name) {
if (English == null) LoadNames();
if (!English.ContainsKey(name)) return false;
var index = English[name];
return Localized.ContainsKey(index);
}
public static string Map(string text) {
if (HasName(text)) return Localized[English[text]];
else return text;
}
private static string PdhMap(int index) {
int size = 0;
uint ret = PdhLookupPerfNameByIndex(null, index, null, ref size);
if (ret == 0x800007D2) {
var buffer = new StringBuilder(size);
ret = PdhLookupPerfNameByIndex(null, index, buffer, ref size);
if (ret == 0) return buffer.ToString();
}
throw new System.ComponentModel.Win32Exception((int)ret, "PDH lookup failed");
}
private static void LoadNames() {
string[] english;
string[] local;
using (var hklm = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64)) {
using (var key = hklm.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\009")) {
english = (string[])key.GetValue("Counter");
}
using (var key = hklm.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\CurrentLanguage")) {
local = (string[])key.GetValue("Counter");
}
}
English = new Dictionary<string, int>(english.Length / 2, StringComparer.InvariantCultureIgnoreCase);
for (int ix = 0; ix < english.Length - 1; ix += 2) {
int index = int.Parse(english[ix]);
if (!English.ContainsKey(english[ix + 1])) English.Add(english[ix + 1], index);
}
Localized = new Dictionary<int, string>(local.Length / 2);
for (int ix = 0; ix < local.Length - 1; ix += 2) {
int index = int.Parse(local[ix]);
Localized.Add(index, local[ix + 1]);
}
}
[DllImport("pdh.dll", CharSet = CharSet.Auto)]
private static extern uint PdhLookupPerfNameByIndex(string machine, int index, StringBuilder buffer, ref int bufsize);
}
示例用法:
class Program {
static void Main(string[] args) {
var ctr1 = PerfMapper.FromEnglish("Processor", "% Processor Time");
var ctr2 = PerfMapper.FromIndices(238, 6);
}
}
我只能访问英文版的Windows,无法保证本地化版本的准确性。如果您遇到任何错误,请通过编辑此帖子进行更正。