2014-10-07 57 views
0

我正在使用C#應用程序來監視從特定文件夾啓動的進程,並且我正在使用WMI進行監視。我的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)

at System.Management.ManagementEventWatcher.Start()

在App.ProcessTabViewModel1..ctor()

+0

聽起來像是你缺少物/關閉通話的地方... – 2014-10-07 09:40:24

+0

@SoMoS我的事件觀察仍然在整個應用程序的生命週期當應用程序關閉時我正在處理它們。但是這是在應用程序的一次運行中發生的。這種方法有什麼問題嗎? – jester 2014-10-07 12:07:27

+1

您做錯了的可能性很高,我需要查看異常的片段和堆棧跟蹤。預期的文件,當你難以解釋系統錯誤。 – 2014-10-10 09:42:29

回答

3

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; 
} 
+0

非常感謝我的代碼中的努力,解釋和缺失部分。我想我應該以不同的方式解決它。我試圖獲得的過濾是,我想要一個事件,當一個特定文件夾的進程啓動時。我沒有太多,但我有大約3到4個ProcessWatchers同時運行。但看來我仍然超出配額限制。我應該嘗試一種不同的方法。 – jester 2014-10-14 09:36:09