为什么在我尝试时,WMI 的 MS 示例 C# 应用程序会失败?

Why does the MS sample C# app for WMI fail when I try it?

我已经搜索了数十个相关的 SO 问题和一百多个 MS 文档页面,但仍然找不到我遗漏的内容。我的最终目标是在总 CPU 或 RAM 使用量超过阈值时创建前几个 CPU 消费者和 RAM 消费者的列表。获得总数相对容易。我的困惑是我 运行 在尝试收集单个过程数据的每种方法时遇到的障碍。

我第一次尝试 Process.GetProcesses(),但是当我尝试访问它们的资源使用属性时,它 returns 的一半进程抛出异常。 (这并不全是坏事,因为我并不真正关心其中的大部分。)我可以忽略那些并使用有效的方法,但我不能依赖被忽略的进程不在我想要的集合中。

接下来我深入研究了 WMI 并测试了一个 VB 脚本以查看它是否可以收集所有进程的信息:

Set objWMIService = GetObject("winmgmts:")
Set colProcesses = objWMIService.ExecQuery("Select * from Win32_Process")
For Each objProcess in colProcesses
  sngProcessTime = (CSng(objProcess.KernelModeTime) + CSng(objProcess.UserModeTime)) / 10000000
  Wscript.Echo objProcess.Name & " CPU: " & sngProcessTime _
      & " MEM: " & objProcess.WorkingSetSize/1024 
Next

确实如此。内存数字似乎不合时宜,但这个障碍可以等待。回到 C#,我从 MS Docs 复制了一个简单的例子,它只列出了进程:

using Microsoft.Management.Infrastructure;
. . .
  {
      var cimSession = CimSession.Create("localhost");
      var enumeratedInstances = cimSession.EnumerateInstances(@"root\cimv2", "Win32_Process");
      foreach (CimInstance cimInstance in enumeratedInstances)
          Console.WriteLine("{0}", cimInstance.CimInstanceProperties["Name"].Value.ToString());
    }

我为 MMI DLL 引用了 Windows 10 SDK。该应用程序成功创建了 CIMSession 但在 EnumerateInstances 方法调用上失败并出现错误“客户端无法连接到请求中指定的目标”。我找不到任何可能丢失的线索。会是什么???

我并不十分反对编写一些 Win32 C++ 代码来实现这一点,但我已经离开 C++ 太久了,以至于我忘记了我所记得的两倍。如果我必须那样做,我更愿意使用来自 C# 的包装调用。

(这一切都在一台 PC 上;不涉及远程计算机。)

我相信这就是您想要的。此代码将 return 进程 ID 及其 CPU 用法。显示的示例使用本地主机。这里有一些问题。如果您尝试访问网络上的另一台计算机,您将需要确保防火墙和防病毒软件允许 WMI/RPC。此外,您可能需要提供该机器的登录凭据。同样的陷阱也适用于网络域。您肯定需要凭据。

这里是Microsoft's ManagementScope documentation.

        try
        {
            var scope = new ManagementScope($@"\localhost\ROOT\CIMV2");

            // If you're on a domain you will need to provide credentials
            // 
            //var scope = new ManagementScope(
            //    $@"\{macheName}\ROOT\CIMV2",
            //new ConnectionOptions
            //{
            //    Username = "{Username}",
            //    Password = "{Password}"
            //});

            scope.Connect();

            var query = new ObjectQuery("SELECT * FROM Win32_PerfFormattedData_PerfProc_Process");
            var searcher = new ManagementObjectSearcher(scope, query);

            var queryCollection = searcher.Get();
            foreach (var m in queryCollection)
            {
                var pId = m["IDProcess"];
                var cpuTime = m["PercentProcessorTime"];
            }
        }
        catch
        {
            // ignored
        }