为什么在我尝试时,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
}
我已经搜索了数十个相关的 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
}