Code: Select all
settimer , start, 10
return
start:
Inst2 := new FileMonitoring(folderPath2, notifyFilter, "OnDirectoryChanged2")
Return
[Mod edit: Fixed quote... I guess.]
Code: Select all
settimer , start, 10
return
start:
Inst2 := new FileMonitoring(folderPath2, notifyFilter, "OnDirectoryChanged2")
Return
Thanks for the linkteadrinker wrote: ↑30 Jan 2022, 20:40If my class does not work perfectly for you, you can try another approach.
as I wroteteadrinker wrote: ↑30 Jan 2022, 22:16It makes no sense to update the instance so often. Just all the actions in the __Delete() do not have time to work out.
I did it every 5 seconds & I still got the same error, is it still too fast?(of course I didn't do that fast refresh, but with 10 ms it errors out within seconds)
I think adding Sleep, 100 at the end of __Delete() can help.I did it every 5 seconds & I still got the same error
teadrinker wrote: ↑29 May 2020, 21:48@Helgef
Appreciate your help, added what you suggested.Spoiler
I'm wondering if it works on network folders as it doesn't in my environment. The WMI method posted earlier in this topic works well, however.teadrinker wrote: ↑29 May 2020, 21:48@Helgef
Appreciate your help, added what you suggested.Code: Select all
#NoEnv SetBatchLines -1 FILE_NOTIFY_CHANGE_FILE_NAME := 0x1 FILE_NOTIFY_CHANGE_DIR_NAME := 0x2 FILE_NOTIFY_CHANGE_ATTRIBUTES := 0x4 FILE_NOTIFY_CHANGE_SIZE := 0x8 notifyFilter := FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE folderPath1 := A_Desktop folderPath2 := A_ScriptDir Inst1 := new FileMonitoring(folderPath1, notifyFilter, "OnDirectoryChanged1", true) Inst2 := new FileMonitoring(folderPath2, notifyFilter, "OnDirectoryChanged2") Return OnDirectoryChanged1(filePath, event) { MsgBox, % ["Added", "Removed", "Modified", "Renamed, old name", "Renamed, new name"][event] ": " filePath } OnDirectoryChanged2(filePath, event) { MsgBox, % ["Added", "Removed", "Modified", "Renamed, old name", "Renamed, new name"][event] ": " filePath } class FileMonitoring { __New(folderPath, notifyFilter, UserFunc, watchSubtree := false) { this.Event := new this._Event() this.SetCapacity("buffer", 1024) pBuffer := this.GetAddress("buffer") this.SetCapacity("overlapped", A_PtrSize*3 + 8) this.pOverlapped := this.GetAddress("overlapped") this.Directory := new this._ReadDirectoryChanges( folderPath, notifyFilter, watchSubtree , pBuffer, this.pOverlapped, this.Event.handle ) this.EventSignal := new this._EventSignal(this.Directory, this.Event.handle, pBuffer, UserFunc) this.Directory.Read() } __Delete() { DllCall("CancelIoEx", "Ptr", this.Directory.handle, "Ptr", this.pOverlapped) this.Event.Set() this.EventSignal.Clear() this.Directory.Clear() this.SetCapacity("buffer", 0) this.buffer := "" } class _Event { __New() { this.handle := DllCall("CreateEvent", "Int", 0, "Int", 0, "Int", 0, "Int", 0, "Ptr") } Set() { DllCall("SetEvent", "Ptr", this.handle) } __Delete() { DllCall("CloseHandle", "Ptr", this.handle) } } class _ReadDirectoryChanges { __New(dirPath, notifyFilter, watchSubtree, pBuffer, pOverlapped, hEvent) { static OPEN_EXISTING := 3 , access := (FILE_SHARE_READ := 1) | (FILE_SHARE_WRITE := 2) , flags := (FILE_FLAG_OVERLAPPED := 0x40000000) | (FILE_FLAG_BACKUP_SEMANTICS := 0x2000000) for k, v in ["notifyFilter", "watchSubtree", "pBuffer", "pOverlapped", "hEvent"] this[v] := %v% this.handle := DllCall("CreateFile", "Str", dirPath, "UInt", 1, "UInt", access, "Int", 0 , "UInt", OPEN_EXISTING, "UInt", flags, "Int", 0, "Ptr") } Read() { DllCall("RtlZeroMemory", "Ptr", this.pOverlapped, "Ptr", A_PtrSize*3 + 8) NumPut(this.hEvent, this.pOverlapped + A_PtrSize*2 + 8, "Ptr") ; there is only a Unicode version of this api Return DllCall("ReadDirectoryChangesW", "Ptr", this.handle, "Ptr", this.pBuffer, "UInt", 1024, "UInt", this.watchSubtree , "UInt", this.notifyFilter, "Ptr", 0, "Ptr", this.pOverlapped, "Ptr", 0) } Clear() { DllCall("CloseHandle", "Ptr", this.handle) } } class _EventSignal { __New(Directory, hEvent, pBuffer, UserFunc) { this.WM_EVENTSIGNAL := DllCall("RegisterWindowMessage", "Str", "WM_EVENTSIGNAL") for k, v in ["Directory", "hEvent", "pBuffer"] this[v] := %v% this.UserFunc := IsObject(UserFunc) ? UserFunc : Func(UserFunc) this.OnEvent := ObjBindMethod(this, "On_WM_EVENTSIGNAL") OnMessage(this.WM_EVENTSIGNAL, this.OnEvent) this.startAddress := this.CreateWaitFunc(this.hEvent, A_ScriptHwnd, this.WM_EVENTSIGNAL) this.Thread := new this._Thread(this.startAddress) } On_WM_EVENTSIGNAL(wp) { if !( wp = this.hEvent && DllCall("GetOverlappedResult", "Ptr", this.hEvent, "Ptr", this.pBuffer, "UIntP", written, "UInt", false) ) Return addr := this.pBuffer offset := 0 Loop { addr += offset eventType := NumGet(addr + 4, "UInt") objectName := StrGet(addr + 12, NumGet(addr + 8, "UInt")//2, "UTF-16") ; always in Unicode timer := this.UserFunc.Bind(objectName, eventType) SetTimer, % timer, -10 } until !offset := NumGet(addr + 0, "UInt") this.Thread.Wait() this.Thread := new this._Thread(this.startAddress) this.Directory.Read() } CreateWaitFunc(hEvent, hWnd, msg, timeout := -1) { params := ["UInt", MEM_COMMIT := 0x1000, "UInt", PAGE_EXECUTE_READWRITE := 0x40, "Ptr"] ptr := DllCall("VirtualAlloc", "Ptr", 0, "Ptr", A_PtrSize = 4 ? 49 : 85, params*) hModule := DllCall("GetModuleHandle", "Str", "kernel32.dll", "Ptr") pWaitForObj := DllCall("GetProcAddress" , "Ptr", hModule, "AStr", "WaitForSingleObject", "Ptr") hModule := DllCall("GetModuleHandle", "Str", "user32.dll", "Ptr") pPostMessage := DllCall("GetProcAddress" , "Ptr", hModule, "AStr", "PostMessageW", "Ptr") NumPut(pWaitForObj , ptr + 0) NumPut(pPostMessage, ptr + A_PtrSize) if (A_PtrSize = 4) { NumPut(0x68 , ptr + 8) NumPut(timeout, ptr + 9) , NumPut(0x68 , ptr + 13) NumPut(hEvent , ptr + 14) , NumPut(0x15FF, ptr + 18) NumPut(ptr , ptr + 20) , NumPut(0x6850, ptr + 24) NumPut(hEvent , ptr + 26) , NumPut(0x68 , ptr + 30) NumPut(msg , ptr + 31) , NumPut(0x68 , ptr + 35) NumPut(hWnd , ptr + 36) , NumPut(0x15FF, ptr + 40) NumPut(ptr + 4, ptr + 42) , NumPut(0xC2 , ptr + 46, "UChar") NumPut(4 , ptr + 47, "UShort") } else { NumPut(0x53 , ptr + 16) NumPut(0x20EC8348, ptr + 17) , NumPut(0xBACB8948, ptr + 21) NumPut(timeout , ptr + 25) , NumPut(0xB948 , ptr + 29) NumPut(hEvent , ptr + 31) , NumPut(0x15FF , ptr + 39) NumPut(-45 , ptr + 41) , NumPut(0xB849 , ptr + 45) NumPut(hEvent , ptr + 47) , NumPut(0xBA , ptr + 55) NumPut(msg , ptr + 56) , NumPut(0xB948 , ptr + 60) NumPut(hWnd , ptr + 62) , NumPut(0xC18941 , ptr + 70) NumPut(0x15FF , ptr + 73) , NumPut(-71 , ptr + 75) NumPut(0x20C48348, ptr + 79, "UInt"), NumPut(0xC35B , ptr + 83, "UShort") } Return ptr + A_PtrSize*2 } class _Thread { __New(startAddress) { if !this.handle := DllCall("CreateThread", "Int", 0, "Int", 0, "Ptr", startAddress, "Int", 0, "UInt", 0, "Int", 0, "Ptr") throw Exception("Failed to create thread.`nError code: " . A_LastError) } Wait() { DllCall("WaitForSingleObject", "Ptr", this.handle, "Int", -1) } __Delete() { DllCall("CloseHandle", "Ptr", this.handle) } } Clear() { this.Thread.Wait() OnMessage(this.WM_EVENTSIGNAL, this.OnEvent, 0) this.OnEvent := "" DllCall("VirtualFree", "Ptr", this.startAddress - A_PtrSize*2, "Ptr", A_PtrSize = 4 ? 49 : 85, "UInt", MEM_DECOMMIT := 0x4000) } } }
Only info about this issue I found is this one:
ReadDirectoryChangesW —> Return value wrote:If the network redirector or the target file system does not support this operation, the function fails with ERROR_INVALID_FUNCTION.
I see. So it depends on the environment. Thank you.teadrinker wrote: ↑24 Sep 2022, 05:04Only info about this issue I found is this one:ReadDirectoryChangesW —> Return value wrote:If the network redirector or the target file system does not support this operation, the function fails with ERROR_INVALID_FUNCTION.