程序问答   发布时间:2022-06-01  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了取消使用 ExecNotificationQuery大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。

如何解决取消使用 ExecNotificationQuery?

开发过程中遇到取消使用 ExecNotificationQuery的问题如何解决?下面主要结合日常开发的经验,给出你关于取消使用 ExecNotificationQuery的解决方法建议,希望对你解决取消使用 ExecNotificationQuery有所启发或帮助;

我可以在脚本中创建非永久性 WMI 事件查询,例如这个,它会记录接下来 5 个新 Notepad.exe 进程的 PID:

Set WMI = Getobject("winmgmts:\\.\ROOT\cimv2")

wql = "SELECT * FROM __InstanceCreationEvent WITHIN 2 " & _ 
      "WHERE TargeTinstance ISA 'Win32_Process' AND TargeTinstance.name = 'Notepad.exe'"
Set Eventsource = WMI.ExecNotificationquery(wql)

For i = 1 To 5
    With Eventsource.NextEvent(-1)
        Wscript.Echo .TargeTinstance.ProcessID
    End With
Next

但我缺少一种明确取消 Eventsource 的方法。否则,事件通知将继续在 WMI 内无限期运行,即使侦听生成事件的脚本因任何原因终止(*)。当脚本多次运行时,这会导致增加的开销累积。

@H_856_2@mSDN documentation of IWbemservices::ExecNotificationQuery 说:

IWbemservices::ExecNotificationquery 方法执行查询以接收事件。调用立即返回,用户可以在事件到达时轮询返回的枚举器。释放返回的枚举数会取消查询。

如何释放返回的枚举器?

Eventsource 对象似乎不可枚举。尝试在其上使用 For Each 失败,并显示 “VBScript 运行时错误:对象不支持此属性或方法”,因此我无法使用隐式 Release For Each 循环结束。


(*) 这来自于说明“释放返回的枚举器会取消查询”的文档。,这意味着释放枚举器导致查询持续存在 - 但也可以明确确认:

为此查询 "SELECT * FROM __InstanceCreationEvent WITHIN 2 WHERE TargeTinstance ISA 'Win32_Directory' And TargeTinstance.name = 'C:\\Test'" 设置通知并使用 Sysinternals Process Monitor 观察来自 WMI 服务 (WmiPrvSE.exe) 的文件系统访问。 WMI 服务将每 2 秒开始轮询名为“C:\Test”的文件夹,并在设置监控的脚本结束后继续这样做。

重新启动 WMI 服务可以消除轮询,但对于这种情况显然这不是一个好的@R_301_6954@案。

解决方法

您可以改用 ExecNotificationQueryAsync 吗?这样您就可以向它传递一个 SWbemSink object,稍后您可以调用 Cancel() method 以取消接收器,这也应该删除与该接收器关联的任何事件使用者。

使用 ExecNotificationQuery() 方法的问题在于它只允许您访问 SWbemEventsource 对象,该对象允许调用枚举器中的下一个事件。一旦注册,似乎不可能使用该方法删除事件使用者。

运行:

Set FSO = CreateObject("ScripTing.FileSystemObject")
Set WMI = GetObject("winmgmts:\\.\ROOT\cimv2")
Set Sink = WScript.CreateObject("WbemScripTing.SWbemSink","Sink_")

wql = "SELECT * FROM __InstanceCreationEvent WITHIN 2 " & _
      "WHERE TargeTinstance ISA 'Win32_Directory' And TargeTinstance.Name = 'C:\\Test'"

WScript.Echo "WaiTing for events..."
WMI.ExecNotificationQueryAsync Sink,wql

For i = 1 To 10
    WScript.Echo i
    Wscript.Sleep 1000
    If i = 5 Then
        FSO.CreateFolder "C:\Test"
        WScript.Echo "Test folder created."
    End If
Next

Sink.Cancel
WScript.Echo "Sink canceled."

FSO.deleteFolder "C:\Test"
WScript.Echo "Test folder deleted."

Sub Sink_OnObjectReady(eventObject,asyncContext)
    Set folder = eventObject.TargeTinstance
    WScript.Echo "__InstanceCreationEvent: " & folder.Name
End Sub

输出类似这样的东西:


WaiTing for events...
1
2
3
4
5
Test folder created.
6
7
__InstanceCreationEvent: C:\Test
8
9
10
Sink canceled.
Test folder deleted.

之后,进程监视器将确认 WMI 已停止后台轮询以创建文件夹。

警告:调用 Sink.Cancel 是绝对必要的。如果脚本意外终止,WMI 在后台继续轮询,而重新启动 WMI 服务是摆脱轮询循环的唯一方法。

大佬总结

以上是大佬教程为你收集整理的取消使用 ExecNotificationQuery全部内容,希望文章能够帮你解决取消使用 ExecNotificationQuery所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。
标签: