While I'm experimenting with WMI's ExecNotificationQueryAsync() COM method, I've encountered some strange behavior. Please run the code below. And create a test file in the A_ScriptDir\test directory and edit it to see if a tray notice appears. After that, reload the script several times. Then modify the file under A_ScriptDir\test again. If you can reproduce the problem, you'll see the Edited notice multiple times for one modification. Moreover, if you leave the script running for a while, the __InstanceModificationEvent event gets triggered again and again with some random intervals without any modifications.
Code: Select all
#Persistent
sPathDir1 := A_ScriptDir "\test"
FileCreateDir, % sPathDir1
; oFileMonitor := new FileMonitor.Common( "NotifyFileChange", sPathDir1 )
oFileMonitorEdit := new FileMonitor.Edit( "NotifyFileChange", sPathDir1 )
oFileMonitorCreate := new FileMonitor.Create( "NotifyFileChange", sPathDir1 )
oFileMonitorDelete := new FileMonitor.Delete( "NotifyFileChange", sPathDir1 )
return
~Esc::ExitApp
NotifyFileChange( aParams* ) {
_oEvent := aParams.1
SplitPath, % aParams.1.TargetInstance.Name, sFileName
if ( "__InstanceModificationEvent" == _oEvent.Path_.Class ) {
TrayTip, Edited, % sFileName "`n" _oEvent.Path_.Class
return
}
if ( "__InstanceCreationEvent" == _oEvent.Path_.Class ) {
TrayTip, Created, % sFileName "`n" _oEvent.Path_.Class
return
}
if ( "__InstanceDeletionEvent" == _oEvent.Path_.Class ) {
TrayTip, Deleted, % sFileName "`n" _oEvent.Path_.Class
return
}
TrayTip, Unknown Class, % sFileName "`n" . _oEvent.Path_.Class
}
class FileMonitor {
class Delete extends FileMonitor.Common {
sQueryFROM := "__InstanceDeletionEvent"
}
class Create extends FileMonitor.Common {
sQueryFROM := "__InstanceCreationEvent"
}
class Edit extends FileMonitor.Common {
sQueryFROM := "__InstanceModificationEvent"
}
class Common {
sQueryFROM := "__InstanceOperationEvent"
oCOMWMI := {}
oCOMSWemSink := {}
__New( cb, sPathDir, nInterval:=1 ) {
this.oCOMWMI := ComObjGet( "winmgmts:" )
this.oCOMSWemSink := ComObjCreate( "WbemScripting.SWbemSink" )
ComObjConnect( this.oCOMSWemSink, new this.Connect( cb ) )
this.oCOMWMI.ExecNotificationQueryAsync( this.oCOMSWemSink, this.getWMIQuery( sPathDir, nInterval ) )
OnExit( ObjBindMethod( this, "stop" ) )
}
getWMIQuery( sPathDir, nInterval ) {
SplitPath, sPathDir,,,,, _sDriveLetter
return "SELECT * From " this.sQueryFROM
. " WITHIN " nInterval
. " WHERE Targetinstance ISA 'CIM_DataFile'"
. " AND TargetInstance.Drive='" _sDriveLetter "'"
. " AND TargetInstance.Path='" RegExReplace( sPathDir, "[A-Z]:\\|((?<!\\)\\(?!\\)|(?<!\\)$)", "\\" ) "'"
}
stop() {
this.oCOMSWemSink.Cancel()
ComObjConnect( this.oCOMSWemSink )
}
class Connect {
fnCallback := {}
__New( fnCallback ) {
this.fnCallback := fnCallback
}
OnObjectReady( aParams* ) {
if StrLen( this.fnCallback ) {
Func( this.fnCallback ).Call( aParams* )
return
}
this.fnCallback.Call( aParams* )
}
}
}
}
Code: Select all
oFileMonitorEdit := new FileMonitor.Edit( "NotifyFileChange", sPathDir1 )
oFileMonitorCreate := new FileMonitor.Create( "NotifyFileChange", sPathDir1 )
oFileMonitorDelete := new FileMonitor.Delete( "NotifyFileChange", sPathDir1 )
I've searched the web and came across this topic. It says the WMI query is still running in the background after the script exits so you need to use the Cancel() method. I'm not sure if it is the case here. I used Cancel() in the above example but the strange behavior still persists.