WatchFolder() - updated on 2021-10-14
Re: WatchFolder() - updated on 2016-11-30
Hi,
I'm pretty sure the error window pops up before the file has been written to the storage device, so IMO WatchFolder() cannot help you.
I'm pretty sure the error window pops up before the file has been written to the storage device, so IMO WatchFolder() cannot help you.
Re: WatchFolder() - updated on 2016-11-30
as the author of the function already wrote, you're on the wrong track.nschoonover wrote: ↑09 Dec 2020, 09:18So, what do you all think? Can this function be used to do what I am trying to do?
you probably should write a simple script instead yourself and run it on the server.
the script would wait for the message to appear, and do the renaming part automatically for you.
in terms of only bypassing the message, there might be a simpler solution although:
let the script simply close the window /kill the process whenever the message pops up.
in case you don't know how to achieve that, have a look e.g. here
Re: WatchFolder() - updated on 2016-11-30
nschoonover wrote: ↑09 Dec 2020, 09:18Hi All!
This sounds like a great tool. I am going to start experimenting with this now. I would like to use this for a specific scenario.
We have a network scanner that scans files directly to a network folder in PDF format. We name the file using the interface at the scanner. However, if the name you type in on the scanner already exists, the scanner doesn't have the ability to sense that. As a result, the scanner tries to save a file to the network where there is already a file. This pops a windows error that allows you to save both or skip. The error appears on the server PC, so a user can't really see it and fix it. The result is that all future scans get held up, waiting for the error message on there server to be addressed by a user.
I would like to use the WatchFolder() function to sense an incoming file that is already exists and rename it to include a (1) at the end. Ideally this would happen without any user input, effectively bypassing the windows error message and just automatically renaming the file if the name already exists.
I have scoured the scanner tools to find a similar built-in function, but to no avail! See my previous attempts here:
https://www.copytechnet.com/forums/sharp/152689-network-scanner-tool-duplicate-filenames.html
https://social.msdn.microsoft.com/Forums/en-US/f60eb786-c6a8-4ff6-b7c1-ea9d583eecad/duplicate-filenames-error-sharp-network-scan-tool?forum=wcf
So, what do you all think? Can this function be used to do what I am trying to do?
Thanks for your time!
Nate
Tüm dosyaların listesini saklayıp oradan kontrol ederek işlem yapmak bir seçenek değil mi? İngilizcem iyi değil ve sizi eksik anlamış olabilirim.
Mod edit: Google translated this as:
Isn't it an option to keep a list of all files and check them from there? I am not good at English and I may have not understood you well.
-
- Posts: 5
- Joined: 09 Dec 2020, 09:09
Re: WatchFolder() - updated on 2016-11-30
Hi Everyone,
I am back at the WatchFolder script. It is just too useful to let it go. In the example below I have built on the shoulders of giants to create a program to watch two network folders from our server PC. If a file appears in a folder and the first two letters of the filename are "VA", then automatically rename the file to include a unique tick count. If the file does not begin with VA, then ignore it.
The script works like a charm. However, I want it to be as secure and robust as possible. Can anyone review my code and suggest changes to increase security and reliability?
Thank you for your time!
Nate
I am back at the WatchFolder script. It is just too useful to let it go. In the example below I have built on the shoulders of giants to create a program to watch two network folders from our server PC. If a file appears in a folder and the first two letters of the filename are "VA", then automatically rename the file to include a unique tick count. If the file does not begin with VA, then ignore it.
The script works like a charm. However, I want it to be as secure and robust as possible. Can anyone review my code and suggest changes to increase security and reliability?
Code: Select all
#NoEnv
#Warn
#Include WatchFolder.ahk
SetBatchLines, -1
; ----------------------------------------------------------------------------------------------------------------------------------
Gui, Margin, 20, 20
Gui, Add, Text, , Watch Folder:
Gui, Add, Edit, xm y+3 w730 vWatchedFolder cGray +ReadOnly, Select a folder ...
Gui, Add, Button, x+m yp w50 hp +Default vSelect gSelectFolder, ...
Gui, Add, Text, xm, Watch Folder 2:
Gui, Add, Edit, xm y+3 w730 vWatchedFolder2 cGray +ReadOnly, Select a 2nd folder ...
Gui, Add, Button, x+m yp w50 hp +Default vSelect2 gSelectFolder2, ...
Gui, Add, Text, xm y+5, Watch Changes:
Gui, Add, Checkbox, xm y+3 vSubTree, In Sub-Tree
Gui, Add, Checkbox, x+5 yp vFiles Checked, Files
Gui, Add, Checkbox, x+5 yp vFolders Checked, Folders
Gui, Add, Checkbox, x+5 yp vAttr, Attributes
Gui, Add, Checkbox, x+5 yp vSize, Size
Gui, Add, Checkbox, x+5 yp vWrite, Last Write
Gui, Add, Checkbox, x+5 yp vAccess, Last Access
Gui, Add, Checkbox, x+5 yp vCreation, Creation
Gui, Add, Checkbox, x+5 yp vSecurity, Security
Gui, Add, ListView, xm w800 r15 vLV, TickCount|Folder|Action|Name|IsDir|OldName|%A_Space%
Gui, Add, Button, xm w100 gStartStop vAction +Disabled, Start
Gui, Add, Button, x+m yp wp gPauseResume vPause +Disabled, Pause
Gui, Add, Button, x+m yp wp gCLear, Clear
Gui, Show, , Watch Folder
GuiControl, Focus, Select
Return
; ----------------------------------------------------------------------------------------------------------------------------------
GuiClose:
ExitApp
; ----------------------------------------------------------------------------------------------------------------------------------
Clear:
LV_Delete()
Return
; ----------------------------------------------------------------------------------------------------------------------------------
PauseResume:
GuiControlGet, Caption, , Pause
If (Caption = "Pause") {
WatchFolder("**PAUSE", True)
GuiControl, Disable, Action
GuiControl, , Pause, Resume
}
ELse {
WatchFolder("**PAUSE", False)
GuiControl, Enable, Action
GuiControl, , Pause, Pause
}
Return
; ----------------------------------------------------------------------------------------------------------------------------------
StartStop:
Gui, +OwnDialogs
Gui, Submit, NoHide
If !InStr(FileExist(WatchedFolder), "D") {
MsgBox, 0, Error, "%WatchedFolder%" isn't a valid folder name!
Return
}
GuiControlGet, Caption, , Action
If (Caption = "Start") {
Watch := 0
Watch |= Files ? 1 : 0
Watch |= Folders ? 2 : 0
Watch |= Attr ? 4 : 0
Watch |= Size ? 8 : 0
Watch |= Write ? 16 : 0
Watch |= Access ? 32 : 0
Watch |= Creation ? 64 : 0
Watch |= Security ? 256 : 0
If (Watch = 0) {
GuiControl, , Files, 1
GuiControl, , Folders, 1
Watch := 3
}
If !WatchFolder(WatchedFolder, "MyUserFunc", SubTree, Watch) {
MsgBox, 0, Error, Call of WatchFolder() failed! You must specify a folder.
Return
}
If !WatchFolder(WatchedFolder2, "MyUserFunc", SubTree, Watch) {
MsgBox, 0, Error, Call of WatchFolder() failed! You must specify a second folder.
Return
}
GuiControl, , Action, Stop
GuiControl, Disable, Select
GuiControl, Enable, Pause
}
Else {
WatchFolder(WatchedFolder, "**DEL")
WatchFolder(WatchedFolder2, "**DEL")
GuiControl, , Action, Start
GuiControl, Enable, Select
GuiControl, Disable, Pause
}
Return
; ----------------------------------------------------------------------------------------------------------------------------------
SelectFolder:
FileSelectFolder, WatchedFolder
If !(ErrorLevel) {
GuiControl, +cDefault, WatchedFolder
GuiControl, , WatchedFolder, %WatchedFolder%
GuiControl, Enable, Action
}
Return
; ----------------------------------------------------------------------------------------------------------------------------------
SelectFolder2:
FileSelectFolder, WatchedFolder2
If !(ErrorLevel) {
GuiControl, +cDefault, WatchedFolder2
GuiControl, , WatchedFolder2, %WatchedFolder2%
GuiControl, Enable, Action
}
Return
; ----------------------------------------------------------------------------------------------------------------------------------
MyUserFunc(Folder, Changes) {
Static Actions := ["1 (added)", "2 (removed)", "3 (modified)", "4 (renamed)"]
TickCount := A_TickCount
GuiControl, -ReDraw, LV
For Each, Change In Changes
Name := Change.Name
StringLeft, NameOnly, Name, (InStr(Name, ".")-1)
StringRight, ExtOnly, Name, 3
SplitPath, Name, smallname
StringLeft, IsVA, smallname, 2
LV_Modify(LV_Add("", TickCount, Folder, Actions[Change.Action], Change.Name, Change.IsDir, Change.OldName, ""), "Vis")
; Look out for a file being added to the folder.
If (Change.Action = 1) {
;MsgBox Renaming File %Name% to %NameOnly%_%TickCount%.%ExtOnly% %smallname% %IsVA%
; If the file begins with VA, then autorename it.
If (IsVA = "va") {
FileMove, %Name%, %NameOnly%_%TickCount%.%ExtOnly% ; Rename a single file.
}
}
Loop, % LV_GetCount("Columns")
LV_ModifyCol(A_Index, "AutoHdr")
GuiControl, +Redraw, LV
}
Nate
Re: WatchFolder() - updated on 2016-11-30
I can't believe I'm just now seeing this. Nice job @just me!
Mind if I tinker with this and make an AHK v2 version? I might add a filter option too...
EDIT: Looks like Helgef beat me to it a while ago... i still might like to try and add a filtering option...
Mind if I tinker with this and make an AHK v2 version? I might add a filter option too...
EDIT: Looks like Helgef beat me to it a while ago... i still might like to try and add a filtering option...
« AHK Portable Installer » | « CallTipsForAll » | « TheArkive AHK v1 Scripts » | « TheArkive AHK v2 Scrpts » | « TheArkive on GitHub »
Re: WatchFolder() - updated on 2016-11-30
@TheArkive, do whatever you want to do. I'm still believing that a filter option within the function isn't necessary.
-
- Posts: 5
- Joined: 09 Dec 2020, 09:09
Re: WatchFolder() - updated on 2016-11-30
Hi again!
I have fine-tuned an application of your script to monitor a folder constantly. If any file shows up there, it checks to see if the file begins with a certain string. If it does, then it appends a tick count to the filename. Thank you for making this possible!
I have fine-tuned an application of your script to monitor a folder constantly. If any file shows up there, it checks to see if the file begins with a certain string. If it does, then it appends a tick count to the filename. Thank you for making this possible!
Code: Select all
#NoEnv
#Warn
#Include WatchFolder.ahk
;SetBatchLines, -1 ; set this option to -1 to run full speed - i am not sure this is nessecary
WatchedFolder := "C:\Users\MyUser\Desktop\temp" ;change this to the folder you want to watch
; ----------------------------------------------------------------------------------------------------------------------------------
Gui, Margin, 20, 20
Gui, Add, Text, , Watching this folder for new files: %WatchedFolder%
Gui, Add, Text, , New files will be appended with a unique number if the filename begins with 'VA'.
Gui, Add, ListView, xm w800 r15 vLV, TickCount|Folder|Action|Name|OldName|%A_Space%
Gui, Add, Button, xm w800 wp gCLear, Clear
Gui, Show, , Watch Folder
GuiControl, Focus, Select
GuiControl, Enable, Action
goto StartStop
Return
; ----------------------------------------------------------------------------------------------------------------------------------
GuiClose:
ExitApp
; ----------------------------------------------------------------------------------------------------------------------------------
Clear:
LV_Delete()
Return
; ----------------------------------------------------------------------------------------------------------------------------------
StartStop:
Gui, +OwnDialogs
Gui, Submit, NoHide
If !WatchFolder(WatchedFolder, "MyUserFunc", , 1) {
MsgBox, 0, Error, Call of WatchFolder() failed! You must specify a valid folder.
Return
}
Return
; ----------------------------------------------------------------------------------------------------------------------------------
MyUserFunc(Folder, Changes) {
Static Actions := ["1 (added)", "2 (removed)", "3 (modified)", "4 (renamed)"]
TickCount := A_TickCount
GuiControl, -ReDraw, LV
For Each, Change In Changes
Name := Change.Name
StringLeft, NameOnly, Name, (InStr(Name, ".")-1)
StringRight, ExtOnly, Name, 3
SplitPath, Name, smallname
StringLeft, IsVA, smallname, 2
LV_Modify(LV_Add("", TickCount, Folder, Actions[Change.Action], Change.Name, Change.OldName, ""), "Vis")
; Look out for a file being added to the folder.
If (Change.Action = 1) {
; If the file begins with VA, then autorename it.
If (IsVA = "va") {
FileMove, %Name%, %NameOnly%_%TickCount%.%ExtOnly% ; Rename a single file.
}
}
Loop, % LV_GetCount("Columns")
LV_ModifyCol(A_Index, "AutoHdr")
GuiControl, +Redraw, LV
}
Re: WatchFolder() - updated on 2016-11-30
How it can be used most efficiently to monitor single files. Do we have to monitor the entire folder for a file?
Re: WatchFolder() - updated on 2016-11-30
Yes, that's why it's called WatchFolder().
Re: WatchFolder() - updated on 2016-11-30
This script is great with the GUI; however, I would like a simple version so that I can get a simple " MsgBox, File Changed " or " MsgBox, Folder Changed " for a selected file or folder whenever a change is made to that file or folder.
Re: WatchFolder() - updated on 2016-11-30
@carno - The very first script in this thread is just the function (without a GUI or any other interface), which you can call and invoke your own function that simply shows a MsgBox as you would like. The example script with a GUI that follows is just that — an example. The function describes how to set up the various parameters with use with your own function. If you search the forum, you’ll find examples of other implementations, in case that helps.
Re: WatchFolder() - updated on 2016-11-30
@boiler - Thanks boiler, you are always very helpful.
Re: WatchFolder() - updated on 2016-11-30
I tested the following test script. It works fine for Actions 1, 2 and 4, but never for 3, which is "The file was modified" when I modify a file by changing the contents and saving it. What is the problem? Thanks.
Code: Select all
#Persistent
#NoEnv
#SingleInstance Force
WatchFolder("C:\Test", "ReportFunction")
; WatchFolder - Reportfunctions
ReportFunction(Directory, Changes) {
For Each, Change In Changes {
Action := Change.Action
Name := Change.Name
; -------------------------------------------------------------------------------------------------------------------------
; Action 1 (added) = File gets added in the watched folder
If (Action = 1)
MsgBox % Name . "`n" . Action ;Run, %Name%
If (Action = 2)
MsgBox % Name . "`n" . Action ;Run, %Name%
If (Action = 3)
MsgBox % Name . "`n" . Action ;Run, %Name%
If (Action = 4)
MsgBox % Name . "`n" . Action ;Run, %Name%
If (Action = 5)
MsgBox % Name . "`n" . Action ;Run, %Name%
If (Action = 6)
MsgBox % Name . "`n" . Action ;Run, %Name%
If (Action = 7)
MsgBox % Name . "`n" . Action ;Run, %Name%
If (Action = 8)
MsgBox % Name . "`n" . Action ;Run, %Name%
If (Action = 16)
MsgBox % Name . "`n" . Action ;Run, %Name%
If (Action = 32)
MsgBox % Name . "`n" . Action ;Run, %Name%
If (Action = 64)
MsgBox % Name . "`n" . Action ;Run, %Name%
If (Action = 256)
MsgBox % Name . "`n" . Action ;Run, %Name%
}
}
Re: WatchFolder() - updated on 2016-11-30
Code: Select all
; Watch - The kind of changes to watch for. This can be one or any combination of the FILE_NOTIFY_CHANGES_...
; values specified below.
; Default: 0x03 - FILE_NOTIFY_CHANGE_FILE_NAME + FILE_NOTIFY_CHANGE_DIR_NAME
Code: Select all
WatchFolder("C:\Test", "ReportFunction")
Re: WatchFolder() - updated on 2016-11-30
Thanks just me for replying to my post. This issue has come up 2-3 times in the past and I understand it has something to do with the Default: 0x03. The full GUI version works great with all actions (add file, delete file, modify file, change filename, etc.). All these actions work as expected. However, when I try the simple non-GUI version (just the function as I posted above) I run into problems (as reported in several other posts in page 3). I tried to replace 0x03 with 0x04 and this works with modify file and change filename, but other actions such as add file and delete file are disabled. I actually tried to replace the Default 0x03 throughout the script with 0x01, 0x02, 0x05, 0x06, 0x07, etc., and with these values nothing works at all. So my question is what is the appropriate value for 0x03 that works with all actions (add file, delete file, modify file, change name, etc.) the same way that it works with the full GUI version of this function when all boxes under Watch Changes: label are checked? I'm basically looking for a stripped-down non-GUI function-only version that works flawlessly with all actions (as though they are all checked in the GUI version) and I can confirm them with simple message boxes for notification.
Re: WatchFolder() - updated on 2016-11-30
Watch for all changes: WatchFolder("C:\Test", "ReportFunction", false, 1| 2 | 4 | 8 |16 | 32 | 64 | 256)
EDIT: added missing parameter, thanks @kczx3 .
EDIT: added missing parameter, thanks @kczx3 .
Re: WatchFolder() - updated on 2016-11-30
Thank HotKeyIt. I tried your reply code in the following script, but still file modification is not working (only add, delete and change filename works). I am most interested in notifications for any changes to a file (file modifications):
Code: Select all
#NoEnv
#SingleInstance Force
WatchFolder("C:\Test", "ReportFunction", 1 | 2 | 4 | 8 |16 | 32 | 64 | 256)
ReportFunction(Folder, Changes) {
For Each, Change In Changes {
Action := Change.Action
Name := Change.Name
MsgBox % Name
MsgBox % Action
}
}
; ==================================================================================================================================
; ==================================================================================================================================
; ==================================================================================================================================
; Function: Notifies about changes within folders.
; This is a rewrite of HotKeyIt's WatchDirectory() released at
; http://www.autohotkey.com/board/topic/60125-ahk-lv2-watchdirectory-report-directory-changes/
; Tested with: AHK 1.1.23.01 (A32/U32/U64)
; Tested on: Win 10 Pro x64
; Usage: WatchFolder(Folder, UserFunc[, SubTree := False[, Watch := 3]])
; Parameters:
; Folder - The full qualified path of the folder to be watched.
; Pass the string "**PAUSE" and set UserFunc to either True or False to pause respectively resume watching.
; Pass the string "**END" and an arbitrary value in UserFunc to completely stop watching anytime.
; If not, it will be done internally on exit.
; UserFunc - The name of a user-defined function to call on changes. The function must accept at least two parameters:
; 1: The path of the affected folder. The final backslash is not included even if it is a drive's root
; directory (e.g. C:).
; 2: An array of change notifications containing the following keys:
; Action: One of the integer values specified as FILE_ACTION_... (see below).
; In case of renaming Action is set to FILE_ACTION_RENAMED (4).
; Name: The full path of the changed file or folder.
; OldName: The previous path in case of renaming, otherwise not used.
; IsDir: True if Name is a directory; otherwise False. In case of Action 2 (removed) IsDir is always False.
; Pass the string "**DEL" to remove the directory from the list of watched folders.
; SubTree - Set to true if you want the whole subtree to be watched (i.e. the contents of all sub-folders).
; Default: False - sub-folders aren't watched.
; Watch - The kind of changes to watch for. This can be one or any combination of the FILE_NOTIFY_CHANGES_...
; values specified below.
; Default: 0x03 - FILE_NOTIFY_CHANGE_FILE_NAME + FILE_NOTIFY_CHANGE_DIR_NAME
; Return values:
; Returns True on success; otherwise False.
; Change history:
; 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.00.00/2015-06-21/just me - initial release
; License:
; The Unlicense -> http://unlicense.org/
; Remarks:
; Due to the limits of the API function WaitForMultipleObjects() you cannot watch more than MAXIMUM_WAIT_OBJECTS (64)
; folders simultaneously.
; MSDN:
; ReadDirectoryChangesW msdn.microsoft.com/en-us/library/aa365465(v=vs.85).aspx
; FILE_NOTIFY_CHANGE_FILE_NAME = 1 (0x00000001) : Notify about renaming, creating, or deleting a file.
; FILE_NOTIFY_CHANGE_DIR_NAME = 2 (0x00000002) : Notify about creating or deleting a directory.
; FILE_NOTIFY_CHANGE_ATTRIBUTES = 4 (0x00000004) : Notify about attribute changes.
; FILE_NOTIFY_CHANGE_SIZE = 8 (0x00000008) : Notify about any file-size change.
; FILE_NOTIFY_CHANGE_LAST_WRITE = 16 (0x00000010) : Notify about any change to the last write-time of files.
; FILE_NOTIFY_CHANGE_LAST_ACCESS = 32 (0x00000020) : Notify about any change to the last access time of files.
; FILE_NOTIFY_CHANGE_CREATION = 64 (0x00000040) : Notify about any change to the creation time of files.
; FILE_NOTIFY_CHANGE_SECURITY = 256 (0x00000100) : Notify about any security-descriptor change.
; FILE_NOTIFY_INFORMATION msdn.microsoft.com/en-us/library/aa364391(v=vs.85).aspx
; FILE_ACTION_ADDED = 1 (0x00000001) : The file was added to the directory.
; FILE_ACTION_REMOVED = 2 (0x00000002) : The file was removed from the directory.
; FILE_ACTION_MODIFIED = 3 (0x00000003) : The file was modified.
; FILE_ACTION_RENAMED = 4 (0x00000004) : The file was renamed (not defined by Microsoft).
; FILE_ACTION_RENAMED_OLD_NAME = 4 (0x00000004) : The file was renamed and this is the old name.
; FILE_ACTION_RENAMED_NEW_NAME = 5 (0x00000005) : The file was renamed and this is the new name.
; GetOverlappedResult msdn.microsoft.com/en-us/library/ms683209(v=vs.85).aspx
; CreateFile msdn.microsoft.com/en-us/library/aa363858(v=vs.85).aspx
; FILE_FLAG_BACKUP_SEMANTICS = 0x02000000
; FILE_FLAG_OVERLAPPED = 0x40000000
; ==================================================================================================================================
WatchFolder(Folder, UserFunc, SubTree := False, Watch := 0x03) {
Static DummyObject := {Base: {__Delete: Func("WatchFolder").Bind("**END", "")}}
Static TimerID := "**" . A_TickCount
Static TimerFunc := Func("WatchFolder").Bind(TimerID, "")
Static MAXIMUM_WAIT_OBJECTS := 64
Static MAX_DIR_PATH := 260 - 12 + 1
Static SizeOfLongPath := MAX_DIR_PATH << !!A_IsUnicode
Static SizeOfFNI := 0xFFFF ; size of the FILE_NOTIFY_INFORMATION structure buffer (64 KB)
Static SizeOfOVL := 32 ; size of the OVERLAPPED structure (64-bit)
Static WatchedFolders := {}
Static EventArray := []
Static HandleArray := []
Static WaitObjects := 0
Static BytesRead := 0
Static Paused := False
; ===============================================================================================================================
If (Folder = "")
Return False
SetTimer, % TimerFunc, Off
RebuildWaitObjects := False
; ===============================================================================================================================
If (Folder = TimerID) { ; called by timer
If (ObjCount := EventArray.Length()) && !Paused {
ObjIndex := DllCall("WaitForMultipleObjects", "UInt", ObjCount, "Ptr", &WaitObjects, "Int", 0, "UInt", 0, "UInt")
While (ObjIndex >= 0) && (ObjIndex < ObjCount) {
FolderName := WatchedFolders[ObjIndex + 1]
D := WatchedFolders[FolderName]
If DllCall("GetOverlappedResult", "Ptr", D.Handle, "Ptr", D.OVLAddr, "UIntP", BytesRead, "Int", True) {
Changes := []
FNIAddr := D.FNIAddr
FNIMax := FNIAddr + BytesRead
OffSet := 0
PrevIndex := 0
PrevAction := 0
PrevName := ""
Loop {
FNIAddr += Offset
OffSet := NumGet(FNIAddr + 0, "UInt")
Action := NumGet(FNIAddr + 4, "UInt")
Length := NumGet(FNIAddr + 8, "UInt") // 2
Name := FolderName . "\" . StrGet(FNIAddr + 12, Length, "UTF-16")
IsDir := InStr(FileExist(Name), "D") ? 1 : 0
If (Name = PrevName) {
If (Action = PrevAction)
Continue
If (Action = 1) && (PrevAction = 2) {
PrevAction := Action
Changes.RemoveAt(PrevIndex--)
Continue
}
}
If (Action = 4)
PrevIndex := Changes.Push({Action: Action, OldName: Name, IsDir: 0})
Else If (Action = 5) && (PrevAction = 4) {
Changes[PrevIndex, "Name"] := Name
Changes[PrevIndex, "IsDir"] := IsDir
}
Else
PrevIndex := Changes.Push({Action: Action, Name: Name, IsDir: IsDir})
PrevAction := Action
PrevName := Name
} Until (Offset = 0) || ((FNIAddr + Offset) > FNIMax)
If (Changes.Length() > 0)
D.Func.Call(FolderName, Changes)
DllCall("ResetEvent", "Ptr", EventArray[D.Index])
DllCall("ReadDirectoryChangesW", "Ptr", D.Handle, "Ptr", D.FNIAddr, "UInt", SizeOfFNI, "Int", D.SubTree
, "UInt", D.Watch, "UInt", 0, "Ptr", D.OVLAddr, "Ptr", 0)
}
ObjIndex := DllCall("WaitForMultipleObjects", "UInt", ObjCount, "Ptr", &WaitObjects, "Int", 0, "UInt", 0, "UInt")
Sleep, 0
}
}
}
; ===============================================================================================================================
Else If (Folder = "**PAUSE") { ; called to pause/resume watching
Paused := !!UserFunc
RebuildObjects := Paused
}
; ===============================================================================================================================
Else If (Folder = "**END") { ; called to stop watching
For K, D In WatchedFolders
If K Is Not Integer
DllCall("CloseHandle", "Ptr", D.Handle)
For Each, Event In EventArray
DllCall("CloseHandle", "Ptr", Event)
WatchedFolders := {}
EventArray := []
Paused := False
Return True
}
; ===============================================================================================================================
Else { ; called to add, update, or remove folders
Folder := RTrim(Folder, "\")
VarSetCapacity(LongPath, SizeOfLongPath, 0)
If !DllCall("GetLongPathName", "Str", Folder, "Ptr", &LongPath, "UInt", SizeOfLongPath)
Return False
VarSetCapacity(LongPath, -1)
Folder := LongPath
If (WatchedFolders[Folder]) { ; update or remove
Handle := WatchedFolders[Folder, "Handle"]
Index := WatchedFolders[Folder, "Index"]
DllCall("CloseHandle", "Ptr", Handle)
DllCall("CloseHandle", "Ptr", EventArray[Index])
EventArray.RemoveAt(Index)
WatchedFolders.RemoveAt(Index)
WatchedFolders.Delete(Folder)
RebuildWaitObjects := True
}
If InStr(FileExist(Folder), "D") && (UserFunc <> "**DEL") && (EventArray.Length() < MAXIMUM_WAIT_OBJECTS) {
If (IsFunc(UserFunc) && (UserFunc := Func(UserFunc)) && (UserFunc.MinParams >= 2)) && (Watch &= 0x017F) {
Handle := DllCall("CreateFile", "Str", Folder . "\", "UInt", 0x01, "UInt", 0x07, "Ptr",0, "UInt", 0x03
, "UInt", 0x42000000, "Ptr", 0, "UPtr")
If (Handle > 0) {
Event := DllCall("CreateEvent", "Ptr", 0, "Int", 1, "Int", 0, "Ptr", 0)
Index := EventArray.Push(Event)
WatchedFolders[Index] := Folder
WatchedFolders[Folder] := {Func: UserFunc, Handle: Handle, Index: Index, SubTree: !!SubTree, Watch: Watch}
WatchedFolders[Folder].SetCapacity("FNIBuff", SizeOfFNI)
FNIAddr := WatchedFolders[Folder].GetAddress("FNIBuff")
DllCall("RtlZeroMemory", "Ptr", FNIAddr, "Ptr", SizeOfFNI)
WatchedFolders[Folder, "FNIAddr"] := FNIAddr
WatchedFolders[Folder].SetCapacity("OVLBuff", SizeOfOVL)
OVLAddr := WatchedFolders[Folder].GetAddress("OVLBuff")
DllCall("RtlZeroMemory", "Ptr", OVLAddr, "Ptr", SizeOfOVL)
NumPut(Event, OVLAddr + 8, A_PtrSize * 2, "Ptr")
WatchedFolders[Folder, "OVLAddr"] := OVLAddr
DllCall("ReadDirectoryChangesW", "Ptr", Handle, "Ptr", FNIAddr, "UInt", SizeOfFNI, "Int", SubTree
, "UInt", Watch, "UInt", 0, "Ptr", OVLAddr, "Ptr", 0)
RebuildWaitObjects := True
}
}
}
If (RebuildWaitObjects) {
VarSetCapacity(WaitObjects, MAXIMUM_WAIT_OBJECTS * A_PtrSize, 0)
OffSet := &WaitObjects
For Index, Event In EventArray
Offset := NumPut(Event, Offset + 0, 0, "Ptr")
}
}
; ===============================================================================================================================
If (EventArray.Length() > 0)
SetTimer, % TimerFunc, -100
Return (RebuildWaitObjects) ; returns True on success, otherwise False
}
Re: WatchFolder() - updated on 2016-11-30
@carno
You're missing two things. First, you need to add #Persistent. Second, you are missing the third parameter to the WatchFolder function. You need to pass true/false as the third argument and then the listed of changes to watch afterwards.
WatchFolder("C:\Test", "ReportFunction", false, 1 | 2 | 4 | 8 |16 | 32 | 64 | 256)
You're missing two things. First, you need to add #Persistent. Second, you are missing the third parameter to the WatchFolder function. You need to pass true/false as the third argument and then the listed of changes to watch afterwards.
WatchFolder("C:\Test", "ReportFunction", false, 1 | 2 | 4 | 8 |16 | 32 | 64 | 256)
Re: WatchFolder() - updated on 2016-11-30
ty, I didn't know thatyou need to add #Persistent