Skip to content

Commit

Permalink
Update 1.0.03.00
Browse files Browse the repository at this point in the history
Bug-fix for adding, removing, or updating watched folders.
  • Loading branch information
AHK-just-me committed Oct 15, 2021
1 parent fb9ea71 commit 55f280a
Showing 1 changed file with 35 additions and 36 deletions.
71 changes: 35 additions & 36 deletions Sources/WatchFolder.ahk
Expand Up @@ -28,6 +28,7 @@
; Return values: ; Return values:
; Returns True on success; otherwise False. ; Returns True on success; otherwise False.
; Change history: ; Change history:
; 1.0.03.00/2021-10-14/just me - bug-fix for addding, removing, or updating folders.
; 1.0.02.00/2016-11-30/just me - bug-fix for closing handles with the '**END' option. ; 1.0.02.00/2016-11-30/just me - bug-fix for closing handles with the '**END' option.
; 1.0.01.00/2016-03-14/just me - bug-fix for multiple folders ; 1.0.01.00/2016-03-14/just me - bug-fix for multiple folders
; 1.0.00.00/2015-06-21/just me - initial release ; 1.0.00.00/2015-06-21/just me - initial release
Expand Down Expand Up @@ -69,7 +70,6 @@ WatchFolder(Folder, UserFunc, SubTree := False, Watch := 0x03) {
Static SizeOfOVL := 32 ; size of the OVERLAPPED structure (64-bit) Static SizeOfOVL := 32 ; size of the OVERLAPPED structure (64-bit)
Static WatchedFolders := {} Static WatchedFolders := {}
Static EventArray := [] Static EventArray := []
Static HandleArray := []
Static WaitObjects := 0 Static WaitObjects := 0
Static BytesRead := 0 Static BytesRead := 0
Static Paused := False Static Paused := False
Expand All @@ -80,14 +80,14 @@ WatchFolder(Folder, UserFunc, SubTree := False, Watch := 0x03) {
RebuildWaitObjects := False RebuildWaitObjects := False
; =============================================================================================================================== ; ===============================================================================================================================
If (Folder = TimerID) { ; called by timer If (Folder = TimerID) { ; called by timer
If (ObjCount := EventArray.Length()) && !Paused { If (ObjCount := EventArray.Count()) && !Paused {
ObjIndex := DllCall("WaitForMultipleObjects", "UInt", ObjCount, "Ptr", &WaitObjects, "Int", 0, "UInt", 0, "UInt") ObjIndex := DllCall("WaitForMultipleObjects", "UInt", ObjCount, "Ptr", &WaitObjects, "Int", 0, "UInt", 0, "UInt")
While (ObjIndex >= 0) && (ObjIndex < ObjCount) { While (ObjIndex >= 0) && (ObjIndex < ObjCount) {
FolderName := WatchedFolders[ObjIndex + 1] Event := NumGet(WaitObjects, ObjIndex * A_PtrSize, "UPtr")
D := WatchedFolders[FolderName] Folder := EventArray[Event]
If DllCall("GetOverlappedResult", "Ptr", D.Handle, "Ptr", D.OVLAddr, "UIntP", BytesRead, "Int", True) { If DllCall("GetOverlappedResult", "Ptr", Folder.Handle, "Ptr", Folder.OVLAddr, "UIntP", BytesRead, "Int", True) {
Changes := [] Changes := []
FNIAddr := D.FNIAddr FNIAddr := Folder.FNIAddr
FNIMax := FNIAddr + BytesRead FNIMax := FNIAddr + BytesRead
OffSet := 0 OffSet := 0
PrevIndex := 0 PrevIndex := 0
Expand All @@ -98,7 +98,7 @@ WatchFolder(Folder, UserFunc, SubTree := False, Watch := 0x03) {
OffSet := NumGet(FNIAddr + 0, "UInt") OffSet := NumGet(FNIAddr + 0, "UInt")
Action := NumGet(FNIAddr + 4, "UInt") Action := NumGet(FNIAddr + 4, "UInt")
Length := NumGet(FNIAddr + 8, "UInt") // 2 Length := NumGet(FNIAddr + 8, "UInt") // 2
Name := FolderName . "\" . StrGet(FNIAddr + 12, Length, "UTF-16") Name := Folder.Name . "\" . StrGet(FNIAddr + 12, Length, "UTF-16")
IsDir := InStr(FileExist(Name), "D") ? 1 : 0 IsDir := InStr(FileExist(Name), "D") ? 1 : 0
If (Name = PrevName) { If (Name = PrevName) {
If (Action = PrevAction) If (Action = PrevAction)
Expand All @@ -121,10 +121,11 @@ WatchFolder(Folder, UserFunc, SubTree := False, Watch := 0x03) {
PrevName := Name PrevName := Name
} Until (Offset = 0) || ((FNIAddr + Offset) > FNIMax) } Until (Offset = 0) || ((FNIAddr + Offset) > FNIMax)
If (Changes.Length() > 0) If (Changes.Length() > 0)
D.Func.Call(FolderName, Changes) Folder.Func.Call(Folder.Name, Changes)
DllCall("ResetEvent", "Ptr", EventArray[D.Index]) DllCall("ResetEvent", "Ptr", Event)
DllCall("ReadDirectoryChangesW", "Ptr", D.Handle, "Ptr", D.FNIAddr, "UInt", SizeOfFNI, "Int", D.SubTree DllCall("ReadDirectoryChangesW", "Ptr", Folder.Handle, "Ptr", Folder.FNIAddr, "UInt", SizeOfFNI
, "UInt", D.Watch, "UInt", 0, "Ptr", D.OVLAddr, "Ptr", 0) , "Int", Folder.SubTree, "UInt", Folder.Watch, "UInt", 0
, "Ptr", Folder.OVLAddr, "Ptr", 0)
} }
ObjIndex := DllCall("WaitForMultipleObjects", "UInt", ObjCount, "Ptr", &WaitObjects, "Int", 0, "UInt", 0, "UInt") ObjIndex := DllCall("WaitForMultipleObjects", "UInt", ObjCount, "Ptr", &WaitObjects, "Int", 0, "UInt", 0, "UInt")
Sleep, 0 Sleep, 0
Expand All @@ -138,11 +139,10 @@ WatchFolder(Folder, UserFunc, SubTree := False, Watch := 0x03) {
} }
; =============================================================================================================================== ; ===============================================================================================================================
Else If (Folder = "**END") { ; called to stop watching Else If (Folder = "**END") { ; called to stop watching
For K, D In WatchedFolders For Event, Folder In EventArray {
If K Is Not Integer DllCall("CloseHandle", "Ptr", Folder.Handle)
DllCall("CloseHandle", "Ptr", D.Handle)
For Each, Event In EventArray
DllCall("CloseHandle", "Ptr", Event) DllCall("CloseHandle", "Ptr", Event)
}
WatchedFolders := {} WatchedFolders := {}
EventArray := [] EventArray := []
Paused := False Paused := False
Expand All @@ -151,54 +151,53 @@ WatchFolder(Folder, UserFunc, SubTree := False, Watch := 0x03) {
; =============================================================================================================================== ; ===============================================================================================================================
Else { ; called to add, update, or remove folders Else { ; called to add, update, or remove folders
Folder := RTrim(Folder, "\") Folder := RTrim(Folder, "\")
VarSetCapacity(LongPath, SizeOfLongPath, 0) VarSetCapacity(LongPath, MAX_DIR_PATH << !!A_IsUnicode, 0)
If !DllCall("GetLongPathName", "Str", Folder, "Ptr", &LongPath, "UInt", SizeOfLongPath) If !DllCall("GetLongPathName", "Str", Folder, "Ptr", &LongPath, "UInt", MAX_DIR_PATH)
Return False Return False
VarSetCapacity(LongPath, -1) VarSetCapacity(LongPath, -1)
Folder := LongPath Folder := LongPath
If (WatchedFolders[Folder]) { ; update or remove If (WatchedFolders.HasKey(Folder)) { ; update or remove
Handle := WatchedFolders[Folder, "Handle"] Event := WatchedFolders[Folder]
Index := WatchedFolders[Folder, "Index"] FolderObj := EventArray[Event]
DllCall("CloseHandle", "Ptr", Handle) DllCall("CloseHandle", "Ptr", FolderObj.Handle)
DllCall("CloseHandle", "Ptr", EventArray[Index]) DllCall("CloseHandle", "Ptr", Event)
EventArray.RemoveAt(Index) EventArray.Delete(Event)
WatchedFolders.RemoveAt(Index)
WatchedFolders.Delete(Folder) WatchedFolders.Delete(Folder)
RebuildWaitObjects := True RebuildWaitObjects := True
} }
If InStr(FileExist(Folder), "D") && (UserFunc <> "**DEL") && (EventArray.Length() < MAXIMUM_WAIT_OBJECTS) { If InStr(FileExist(Folder), "D") && (UserFunc <> "**DEL") && (EventArray.Count() < MAXIMUM_WAIT_OBJECTS) {
If (IsFunc(UserFunc) && (UserFunc := Func(UserFunc)) && (UserFunc.MinParams >= 2)) && (Watch &= 0x017F) { If (IsFunc(UserFunc) && (UserFunc := Func(UserFunc)) && (UserFunc.MinParams >= 2)) && (Watch &= 0x017F) {
Handle := DllCall("CreateFile", "Str", Folder . "\", "UInt", 0x01, "UInt", 0x07, "Ptr",0, "UInt", 0x03 Handle := DllCall("CreateFile", "Str", Folder . "\", "UInt", 0x01, "UInt", 0x07, "Ptr",0, "UInt", 0x03
, "UInt", 0x42000000, "Ptr", 0, "UPtr") , "UInt", 0x42000000, "Ptr", 0, "UPtr")
If (Handle > 0) { If (Handle > 0) {
Event := DllCall("CreateEvent", "Ptr", 0, "Int", 1, "Int", 0, "Ptr", 0) Event := DllCall("CreateEvent", "Ptr", 0, "Int", 1, "Int", 0, "Ptr", 0)
Index := EventArray.Push(Event) FolderObj := {Name: Folder, Func: UserFunc, Handle: Handle, SubTree: !!SubTree, Watch: Watch}
WatchedFolders[Index] := Folder FolderObj.SetCapacity("FNIBuff", SizeOfFNI)
WatchedFolders[Folder] := {Func: UserFunc, Handle: Handle, Index: Index, SubTree: !!SubTree, Watch: Watch} FNIAddr := FolderObj.GetAddress("FNIBuff")
WatchedFolders[Folder].SetCapacity("FNIBuff", SizeOfFNI)
FNIAddr := WatchedFolders[Folder].GetAddress("FNIBuff")
DllCall("RtlZeroMemory", "Ptr", FNIAddr, "Ptr", SizeOfFNI) DllCall("RtlZeroMemory", "Ptr", FNIAddr, "Ptr", SizeOfFNI)
WatchedFolders[Folder, "FNIAddr"] := FNIAddr FolderObj["FNIAddr"] := FNIAddr
WatchedFolders[Folder].SetCapacity("OVLBuff", SizeOfOVL) FolderObj.SetCapacity("OVLBuff", SizeOfOVL)
OVLAddr := WatchedFolders[Folder].GetAddress("OVLBuff") OVLAddr := FolderObj.GetAddress("OVLBuff")
DllCall("RtlZeroMemory", "Ptr", OVLAddr, "Ptr", SizeOfOVL) DllCall("RtlZeroMemory", "Ptr", OVLAddr, "Ptr", SizeOfOVL)
NumPut(Event, OVLAddr + 8, A_PtrSize * 2, "Ptr") NumPut(Event, OVLAddr + 8, A_PtrSize * 2, "Ptr")
WatchedFolders[Folder, "OVLAddr"] := OVLAddr FolderObj["OVLAddr"] := OVLAddr
DllCall("ReadDirectoryChangesW", "Ptr", Handle, "Ptr", FNIAddr, "UInt", SizeOfFNI, "Int", SubTree DllCall("ReadDirectoryChangesW", "Ptr", Handle, "Ptr", FNIAddr, "UInt", SizeOfFNI, "Int", SubTree
, "UInt", Watch, "UInt", 0, "Ptr", OVLAddr, "Ptr", 0) , "UInt", Watch, "UInt", 0, "Ptr", OVLAddr, "Ptr", 0)
EventArray[Event] := FolderObj
WatchedFolders[Folder] := Event
RebuildWaitObjects := True RebuildWaitObjects := True
} }
} }
} }
If (RebuildWaitObjects) { If (RebuildWaitObjects) {
VarSetCapacity(WaitObjects, MAXIMUM_WAIT_OBJECTS * A_PtrSize, 0) VarSetCapacity(WaitObjects, MAXIMUM_WAIT_OBJECTS * A_PtrSize, 0)
OffSet := &WaitObjects OffSet := &WaitObjects
For Index, Event In EventArray For Event In EventArray
Offset := NumPut(Event, Offset + 0, 0, "Ptr") Offset := NumPut(Event, Offset + 0, 0, "Ptr")
} }
} }
; =============================================================================================================================== ; ===============================================================================================================================
If (EventArray.Length() > 0) If (EventArray.Count() > 0)
SetTimer, % TimerFunc, -100 SetTimer, % TimerFunc, -100
Return (RebuildWaitObjects) ; returns True on success, otherwise False Return (RebuildWaitObjects) ; returns True on success, otherwise False
} }

0 comments on commit 55f280a

Please sign in to comment.