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

How to increase the responsiveness of 'ManagementEventWatcher' logic?

我订阅了 Win32_ProcessStartTrace class 事件以在 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 属性 但是正如会员的描述所说,似乎与此目的无关。

您在 WMI 查询中使用 WITHIN clause 来指定轮询间隔。该文章给出了大量警告,不建议使用小间隔。但无论如何都要勇往直前:

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

而且你会发现它根本没有任何区别,默认值已经尽可能快了。这是 Windows 中的体系结构,内核没有 'hook' 在创建进程时生成通知。重要的是,它可能对病毒扫描程序来说很重要。他们被迫修补 OS 以便能够跳入。实现此查询的 WMI 提供程序 (C:\Windows\System32\wbem\KrnlProv.dll) 不执行此操作。

另一种查看方法是使用流程自己实现它 class。例如:

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

没有区别。