我已经被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
属性,但正如成员的描述所说,似乎与此目的无关。
答案 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
没有区别。