我想访问在不同本地化系统上运行的应用程序中的“处理器时间%”计数器。
为此,我希望通过其索引访问计数器,该索引保证是唯一的(请参见https://support.microsoft.com/en-us/kb/287159)。
以下代码为当前区域设置提供了正确的结果,但要打开性能计数器,我还需要计数器的类别名称(请参阅PerformanceCounter类的构造函数)以及实例名称:
[DllImport("pdh.dll", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern UInt32 PdhLookupPerfNameByIndex(string szMachineName, uint dwNameIndex, StringBuilder szNameBuffer, ref uint pcchNameBufferSize);
void Main()
{
var buffer = new StringBuilder(1024);
var bufSize = (uint)buffer.Capacity;
PdhLookupPerfNameByIndex(null, 6, buffer, ref bufSize);
Console.WriteLine(buffer.ToString());
var counter = new PerformanceCounter(/* category??? */, buffer.ToString(), /* instance??? */);
}我如何才能得到这个类别和实例名称?
请参见:Retrieve performance counter value in a language-independent way,它描述了相同的问题,但没有提供解决方案。
发布于 2015-11-27 11:32:32
您误解了PdhLookupPerfNameByIndex()的工作方式。它的工作不是映射性能计数器,而是映射字符串。它既应用于计数器的类别,也可用于计数器的名称。对于计数器的实例,如果适用的话,它不是本地化的。
查看它所做的事情的最好方法是使用Regedit.exe。导航到HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib。注意"009“键,它的计数器值有英文字符串映射的索引。双击“计数器”并将该框的内容复制到文本编辑器中,以获得更好的外观。"CurrentLanguage“键是相同的映射,但使用本地化名称。
因此,PdhLookupPerfNameByIndex()使用CurrentLanguage键,使用在前一步中获得的列表来知道字符串的索引号。另一种方法是在知识库文章的底部(令人困惑地),首先从"009“注册表项中查找索引号。这使您可以从英文字符串转换为本地化字符串。请注意,KB文章记录了注册表项的位置错误,不知道原因。
请记住,正如KB文章所指出的,这些映射只存在于“基本”计数器,而"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;
// Retrieve English and localized strings
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");
}
}
// Create English lookup table
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);
}
// Create localized lookup table
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的英文版本,因此无法保证本地化版本的准确性。请通过编辑这篇文章来纠正你遇到的任何错误。
发布于 2015-11-27 10:22:50
试试这个:
var counter = new PerformanceCounter("Processor", "% Processor Time", "_Total"); 它适用于我的个人电脑与德国本地化。
更新
这是一个可以用来理解这些类别、实例和计数器是如何组织的示例。不要忘记检查“管理工具”下的“性能监视器”,在“控制”面板中,可以添加计数器或查找现有计数器。
string counterName = buffer.ToString();
PerformanceCounter counter = null;
foreach (var category in PerformanceCounterCategory.GetCategories())
{
// Get all possible instances for the current category
var instanceNames = category.GetInstanceNames();
if (instanceNames.Length == 0)
continue;
// Get all counters in the category.
// We want to find an instance with underscores first, for example, "_Total"
var counters = category.GetCounters(
category.GetInstanceNames().OrderBy(i => i).First());
foreach (var currentCounter in counters)
{
if (currentCounter.CounterName == counterName)
{
// Hurray! Here it is!
counter = currentCounter;
}
}
}https://stackoverflow.com/questions/33804402
复制相似问题