如何提高' ManagementEventWatcher'的响应能力?逻辑?

时间:2015-10-30 13:56:22

标签: c# .net vb.net wmi responsiveness

我已经被Win32_ProcessStartTrace个类事件引用,以便在PC上运行进程时通知:

Me.processStartWatcher = 
    New ManagementEventWatcher(New WqlEventQuery("SELECT * FROM Win32_ProcessStartTrace"))

但是,这似乎效率不高,因为在运行可执行文件后需要1或2秒才能触发事件:

Private Sub ProcessStartWatcher_EventArrived(sender As Object, e As EventArrivedEventArgs) _
Handles processStartWatcher.EventArrived

    If (Me.ProcessStartedEvent IsNot Nothing) Then
        RaiseEvent ProcessStarted(Me, e)
    End If

End Sub

这意味着如果某个流程已经运行并且已经快速退出,那么我将不会收到通知。

我可以采取哪些措施来提高ManagementEventWatcher对象的响应能力吗?

我尝试设置Timeout属性,但正如成员的描述所说,似乎与此目的无关。

1 个答案:

答案 0 :(得分:2)

您可以在WMI查询中使用WITHIN clause来指定轮询间隔。该文章提供了大量警告,建议不要使用小间隔。但是要继续前进并尝试它:

Me.processStartWatcher = 
    New ManagementEventWatcher(
       New WqlEventQuery("SELECT * FROM Win32_ProcessStartTrace WITHIN 0.1"))

你会发现它根本没有任何区别,默认已经尽可能快。这是Windows中的体系结构,内核没有“钩子”来在创建进程时生成通知。重要的是,例如,病毒扫描程序。他们被迫修补操作系统以便能够跳入。实现此查询的WMI提供程序(C:\ Windows \ System32 \ wbem \ KrnlProv.dll)不会这样做。

另一种看待这种情况的方法是自己使用Process类实现它。例如:

Public Class ProcessMonitor
    Public Event Started As Action(Of Integer)
    Public Event Stopped As Action(Of Integer)

    Public Sub New(interval As Integer)
        Me.interval = interval
        running = Scan()
        timer = New Threading.Timer(AddressOf callback, Nothing, interval, 0)
    End Sub

    Private Sub callback(state As Object)
        Dim active As HashSet(Of Integer) = Scan()
        Dim started As IEnumerable(Of Integer) = active.Except(running)
        Dim stopped As IEnumerable(Of Integer) = running.Except(active)
        running = active
        For Each pid As Integer In started
            RaiseEvent started(pid)
        Next
        For Each pid As Integer In stopped
            RaiseEvent stopped(pid)
        Next
        timer.Change(interval, 0)
    End Sub

    Private Function Scan() As HashSet(Of Integer)
        Dim ret As New HashSet(Of Integer)
        For Each proc As Process In Process.GetProcesses()
            ret.Add(proc.Id)
        Next
        Return ret
    End Function

    Private running As HashSet(Of Integer)
    Private timer As System.Threading.Timer
    Private interval As Integer
End Class

使用示例程序:

Module Module1
    Sub Main()
        Dim monitor As New ProcessMonitor(100)
        AddHandler monitor.Started, AddressOf Started
        AddHandler monitor.Stopped, AddressOf Stopped
        Console.ReadLine()
    End Sub
    Sub Started(pid As Integer)
        Console.WriteLine("Started: {0}", Process.GetProcessById(pid).ProcessName)
    End Sub
    Sub Stopped(pid As Integer)
        Console.WriteLine("Stopped: {0}", pid)
    End Sub
End Module

没有区别。