【发布时间】:2014-12-01 11:41:02
【问题描述】:
我正在使用 C# 应用程序来监视从特定文件夹启动的进程,并且我正在使用 WMI 进行监视。我的 WMI 查询就像
SELECT * FROM __InstanceCreationEvent WITHIN 5 WHERE TargetInstance ISA 'Win32_Process' AND TargetInstance.ExecutablePath LIKE '{0}%'
我将参数替换为我感兴趣的文件夹的路径。 WMI 查询工作正常,当来自特定文件夹的进程出现时,我正在订阅事件通知以执行一些额外的处理。监控工具运行良好几个小时之后,我的应用程序中开始出现WMI QuotaViolation 异常。一旦发生这种情况,我需要重新启动 Windows Management Instrumentation 服务以使事情正常工作。
我最初使用的是
`SELECT * FROM __InstanceCreationEvent WITHIN 5 WHERE TargetInstance ISA 'Win32_Process'`
查询然后检查事件通知中的进程文件夹,查询中的修改已完成,希望它会减少结果集,从而防止配额违规。
是否有任何方法可以定期刷新 WMI 配额或任何其他方法可以防止 QuotaViolation?处理 QuotaViolation 场景的最佳方法是什么?
编辑: 这是我的进程观察对象:
public class ProcessWatcher : ManagementEventWatcher
{
private string folder = "";
// Process Events
public event ProcessEventHandler ProcessCreated; //notifies process creation
//add any more event notifications required here
// WMI WQL process query strings
static readonly string WMI_OPER_EVENT_QUERY = @"SELECT * FROM __InstanceCreationEvent WITHIN 5 WHERE TargetInstance ISA 'Win32_Process'";
static readonly string WMI_OPER_EVENT_QUERY_WITH_PROC =
WMI_OPER_EVENT_QUERY + " and TargetInstance.Name = '{0}'";
public ProcessWatcher(string basepath)
{
folder = basepath;
Init(string.Empty);
}
public ProcessWatcher(string processName, string basepath)
{
folder = basepath;
Init(processName);
}
private void Init(string processName)
{
this.Query.QueryLanguage = "WQL";
if (string.IsNullOrEmpty(processName))
{
this.Query.QueryString = string.Format(WMI_OPER_EVENT_QUERY + @" AND TargetInstance.ExecutablePath LIKE '{0}%'", folder.Replace(@"\",@"\\")) ;
}
else
{
this.Query.QueryString =
string.Format(WMI_OPER_EVENT_QUERY_WITH_PROC, processName);
}
this.EventArrived += new EventArrivedEventHandler(watcher_EventArrived);
}
private void watcher_EventArrived(object sender, EventArrivedEventArgs e)
{
try
{
ManagementBaseObject mObj = e.NewEvent["TargetInstance"] as ManagementBaseObject;
if (mObj != null)
{
Win32_Process proc = new Win32_Process(mObj);
if (proc != null)
{
folder = folder.ToLower() ?? "";
string exepath = (string.IsNullOrEmpty(proc.ExecutablePath)) ? "" : proc.ExecutablePath.ToLower();
if (!string.IsNullOrEmpty(folder) && !string.IsNullOrEmpty(exepath) && exepath.Contains(folder))
{
if (ProcessCreated != null) ProcessCreated(proc);
}
}
proc.Dispose();
}
mObj.Dispose();
}
catch(Exception ex) { throw; }
finally
{
e.NewEvent.Dispose();
}
}
我在应用程序启动时创建了一个ProcessWatcher 对象,在如下视图模型构造函数中:
watch = new ProcessWatcher(BasePath);
watch.ProcessCreated += new ProcessEventHandler(procWatcher_ProcessCreated);
watch.Start();
如果我尝试在不重新启动 WMI 的情况下第二次启动它,则启动调用是引发 QuotaViolation 的地方。
在应用程序退出时,我正在处理 ProcessWatcher 对象,例如:
watch.Stop();
watch.Dispose();
相关堆栈跟踪是:
异常 InnerException [System.Management.ManagementException: 违反配额
在 System.Management.ManagementException.ThrowWithExtendedInfo(ManagementStatus errorCode)
在 System.Management.ManagementEventWatcher.Start()
在 App.ProcessTabViewModel1..ctor()
【问题讨论】:
-
听起来你在某处缺少 Dispose / Close call ...
-
@SoMoS 我的事件观察者会在应用程序的整个生命周期中保持不变,并且我会在应用程序关闭时处理它们。但这是在应用程序的一次运行中发生的。这种方法有什么问题吗?
-
您做错的可能性很高,我需要查看异常的 sn-p 和堆栈跟踪。遇到难以解释的系统错误时的预期文档。
-
我不知道怎么刷,但是可以增加配额:support2.microsoft.com/kb/2404366
-
增加配额可能只会隐藏真正的问题(更长一段时间)。很有可能,您在 WMI 中遇到了内存泄漏。如果可以,请搜索已知问题/修补程序,或联系 Microsoft 支持。