我编写了一个 C# 程序,用于读取特定命名空间中的 WMI 实例操作事件。另一个第三方软件(SCCM 客户端 [1])负责在后台创建这些实例。当运行我的程序的多个实例时,只有第一个实例能够侦听事件并触发回调函数。其余进程继续循环,而不在控制台上记录任何内容。此外,如果我终止第一个进程并生成一个新进程,则所有进程(已运行的进程或新进程)仍然无法读取新的实例操作事件,即使它们在 WMI Explorer 工具中可见。是什么阻止其他进程也监听这些事件?
class Program
{
static ManagementEventWatcher watcher;
static void StopListening(object sender, ConsoleCancelEventArgs e)
{
Console.WriteLine("Stopping listener");
watcher.Stop();
watcher.Dispose();
watcher.EventArrived -= WmiEventArrived;
Console.WriteLine("...stopped.");
}
static void Main(string[] args)
{
string ClassName = "CCM_StateMsg";
string WmiQueryAsync = "SELECT * FROM __InstanceOperationEvent WHERE TargetInstance ISA '{0}'";
string query = string.Format(CultureInfo.InvariantCulture, WmiQueryAsync, ClassName);
string scope = @"root\ccm\StateMsg";
watcher = new ManagementEventWatcher(scope, query);
watcher.EventArrived += WmiEventArrived;
Console.CancelKeyPress += StopListening;
Console.WriteLine("Starting watcher");
watcher.Start();
Console.WriteLine("...started");
while (true)
{
Console.WriteLine("Waiting for events...");
Thread.Sleep(10000);
}
}
public static void WmiEventArrived(object sender, EventArrivedEventArgs e)
{
// Choose type of event based on class name
string eventClassName = (string)e.NewEvent.GetPropertyValue("__CLASS");
Console.WriteLine("StateMessageProvider got event from WMI of type: {0}", eventClassName);
ManagementBaseObject currInstance = (ManagementBaseObject)e.NewEvent.GetPropertyValue("TargetInstance");
// RAISE THE EVENT
Console.WriteLine("GOT EVENT: {0}", e.NewEvent.ClassPath.ToString());
}
}
}
您的第一个程序只能侦听 WMI 事件而后续实例都无法接收事件的问题可能与 ManagementEventWatcher 类的功能有关。此类的结构对于给定查询一次仅允许一个订阅。
你可以尝试一下吗?
static void Main(string[] args) {
string ClassName = "CCM_StateMsg";
string WmiQueryAsync = "SELECT * FROM __InstanceOperationEvent WHERE TargetInstance ISA '{0}' AND SourceInstanceName='{1}'";
// Generate a unique identifier for this instance
string instanceId = Guid.NewGuid().ToString();
string query = string.Format(WmiQueryAsync, ClassName, instanceId);
string scope = @"root\ccm\StateMsg";
watcher = new ManagementEventWatcher(scope, query);
watcher.EventArrived += (sender, e) => WmiEventArrived(sender, e, instanceId);
}
public static void WmiEventArrived(object sender, EventArrivedEventArgs e, string instanceId)
{
string eventInstanceId = (string)e.NewEvent.GetPropertyValue("SourceInstanceName");
if (eventInstanceId != instanceId)
{
// Ignore events not intended for this instance
return;
}
}