Page 1 of 1

Releasing SWbemSink

Posted: 05 Nov 2017, 08:43
by ELFoglalt
I am writing an application that monitors some other processes and changes behaviour based on what is running. I can detect creation and destruction events using winmgmts just fine, however I've ran into issues with closing the script properly.

Given the following code:

Code: Select all

#Persistent	

; Get WMI service
WMIServiceObject := ComObjGet("winmgmts:")

; Create sink
ProcessCreatedSink := ComObjCreate("WbemScripting.SWbemSink")
ComObjConnect(ProcessCreatedSink, "NotifyCreate_")

; Start async query
WMIServiceObject.ExecNotificationQueryAsync(ProcessCreatedSink
    , "Select * from __InstanceCreationEvent"
    . " within " 1
    . " where TargetInstance isa 'Win32_Process'")

NotifyCreate_OnObjectReady(obj)
{
    TrayTip obj.TargetInstance.Name, "Process started"
}

Xbutton2::
#X::
    WMIServiceObject := ""
    ;ProcessCreatedSink.Cancel() ; Does not exist :(
    ProcessCreatedSink := ""
    ExitApp

ProcessNotifierExample.ahk
(609 Bytes) Downloaded 179 times
If the script closes before any notifications are created, the script exits regularly. If one closes the AHK script after any notifications are created, it appears to close (icon disappears, hotkeyes stop registering), but the process actually stays in limbo, idling, until killed from the outside.
I'm fairly certain that the problem is related to the sink, not being deleted/the async call not being cancelled. But the returned COM wrapper does not seem to have any Cancel (https://msdn.microsoft.com/hu-hu/library/aa393878.aspx) like methods, and it seems like I would need something along the lines of CancelAsyncCall (https://msdn.microsoft.com/en-us/librar ... s.85).aspx), but I'm new to using windows dll-s and can't quite figure out 1. what the proper library/function call would be, 2. how to get a pointer to the actual object as opposed to the AKH wrapper returned by ComObjGet.

For anyone interested, I have a workaround for now that obviously closes the process, but I'd rather have a programatically correct solution, as I'd prefer if my notifier could be stopped and started as needed.

Code: Select all

OnExit "QuitApp" 1

ForceQuit()
{
    ProcessClose(DllCall("GetCurrentProcessId"))
}

Re: Releasing SWbemSink

Posted: 25 Sep 2022, 01:49
by tester
ELFoglalt wrote:
05 Nov 2017, 08:43

Code: Select all

    ;ProcessCreatedSink.Cancel() ; Does not exist :(
In my environment, Window 10 64bit, AutoHotkey 1.1.34.04 (I'm not using AutoHotkey_H), the Cancel() method seem to exist. When I change the method name to Cancel2() or something, an error appears but not with Cancel(). If I run your posted code, WmiPrvSE.exe starts consuming CPU like about 1%. If the script exits, the consumption stops. Also, the below line properly stops the CPU usage by pressing esc.

Code: Select all

~Esc::ProcessCreatedSink.Cancel()
So it seems to do the job.