簡體   English   中英

如何防止WMI配額溢出?

[英]How to prevent WMI quotas from overflowing?

我正在使用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'`

查詢,然后檢查事件通知中的processs文件夾,查詢中的修改已完成,希望它會減少結果集並因此防止違反配額。

有什么方法可以定期刷新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();
        }
    }

我在應用啟動時在一個像這樣的viewmodel構造函數中創建一個ProcessWatcher對象:

        watch = new ProcessWatcher(BasePath);
        watch.ProcessCreated += new ProcessEventHandler(procWatcher_ProcessCreated);
        watch.Start();

如果我嘗試在不重新啟動WMI的情況下第二次啟動QuotaViolation則會在start調用處引發該調用。 在應用程序出口處,我正在處理ProcessWatcher對象,例如:

watch.Stop();
watch.Dispose();

相關堆棧跟蹤為:

異常InnerException [System.Management.ManagementException:違反配額

在System.Management.ManagementException.ThrowWithExtendedInfo(ManagementStatus errorCode)

在System.Management.ManagementEventWatcher.Start()

在App.ProcessTabViewModel1..ctor()

System.Management.ManagementException:違反配額

是的,那會發生。 在添加缺失的部分之后,我根據您的代碼片段編寫了一個小測試程序:

    static void Main(string[] args) {
        for (int ix = 0; ix < 1000; ++ix) {
            var obj = new ProcessWatcher("");
            obj.ProcessCreated += obj_ProcessCreated;
            obj.Start();
        }
    }

KABOOM! 與您引用的堆棧跟蹤完全相同。 它以ix == 76表示。換句話說,此查詢的WMI配額為75。在Windows 8.1中進行了測試。 感覺不錯,這是一個非常昂貴的查詢,也不是太快。

您將不得不從根本上進行此操作,僅創建一個查詢。 一個就足夠了,對許多文件夾執行此操作可能會遇到麻煩。 采取不同的攻擊方式,在獲得事件時進行自己的過濾。 一個粗略的例子(我沒有完全得到想要的過濾):

public class ProcessWatcher2 : IDisposable {
    public delegate void ProcessCreateEvent(string name, string path);
    public event ProcessCreateEvent ProcessCreated;

    public ProcessWatcher2(string folder) {
        this.folder = folder;
        lock (locker) {
            listeners.Add(this);
            if (watcher == null) Initialize();
        }
    }

    public void Dispose() {
        lock (locker) {
            listeners.Remove(this);
            if (listeners.Count == 0) {
                watcher.Stop();
                watcher.Dispose();
                watcher = null;
            }
        }
    }

    private static void Initialize() {
        var query = new WqlEventQuery(@"SELECT * FROM __InstanceCreationEvent WITHIN 5 WHERE TargetInstance ISA 'Win32_Process'");
        watcher = new ManagementEventWatcher(query);
        watcher.EventArrived += watcher_EventArrived;
        watcher.Start();
    }

    private static void watcher_EventArrived(object sender, EventArrivedEventArgs e) {
        using (var proc = (ManagementBaseObject)e.NewEvent["TargetInstance"]) {
            string name = (string)proc.Properties["Name"].Value;
            string path = (string)proc.Properties["ExecutablePath"].Value;
            lock (locker) {
                foreach (var listener in listeners) {
                    bool filtered = false;
                    // Todo: implement your filtering
                    //...
                    var handler = listener.ProcessCreated;
                    if (!filtered && handler != null) {
                        handler(name, path);
                    }
                }
            }
        }
    }

    private static ManagementEventWatcher watcher;
    private static List<ProcessWatcher2> listeners = new List<ProcessWatcher2>();
    private static object locker = new object();
    private string folder;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM