2015-11-19 35 views
5

我想訪問在具有不同本地化的系統上運行的應用程序中的「處理器時間百分比」計數器。按索引獲取PerformanceCounter

爲此,我想通過索引訪問計數器,索引保證唯一(請參閱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,它描述了相同的問題,但沒有提供解決方案。

回答

6

您誤解了PdhLookupPerfNameByIndex()如何工作。它的工作不是映射性能計數器,而是映射字符串。它應該既用於櫃檯的類別也用於其名稱。不適用於櫃檯的實例,如果適用,它不是本地化的。

最好的方法是使用Regedit.exe來查看它的功能。導航到HKEY_LOCAL_MACHINE \ SOFTWARE \ Microsoft \ Windows NT \ CurrentVersion \ Perflib。請注意「009」鍵,其計數器值具有英文字符串映射的索引。雙擊計數器並將該框的內容複製粘貼到文本編輯器中,以獲得更好的外觀。 「CurrentLanguage」鍵是相同的映射,但使用本地化名稱。

因此,PdhLookupPerfNameByIndex()使用CurrentLanguage鍵,使用您在上一步中獲得的列表來知道該字符串的索引號。另一種方法,如知道知識庫文章底部所述(易混淆),首先從「009」註冊表項中查找索引編號。這使您可以從英文字符串轉換爲本地化字符串。請注意,知識庫文章記錄了註冊表項位置錯誤,不知道爲什麼。

請記住,它並不完美,正如知識庫文章中指出的那樣,這些映射只存在於「基本」計數器中,而「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,從而無法保證準確性的本地化版本。請通過編輯此帖修改您遇到的任何錯誤。

0

試試這個:

var counter = new PerformanceCounter("Processor", "% Processor Time", "_Total"); 

它爲我用德語本地化的電腦上。

UPDATE

這是你可以用它來了解這些類別,實例和計數器如何組織一個例子。不要忘記檢查性能監視器根據管理工具控制面板您可以添加一個計數器或找到現有的計數器。

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; 
     } 
    } 
} 
+0

看來,傳遞英文名稱大多數時候工作(也在德國系統測試)。但是我們有一些瑞士體系無法找到那些英文專櫃。 – thomai