├── README └── WatchDirectory.ahk /README: -------------------------------------------------------------------------------- 1 | WatchDirectory will inform you about file changes in specified directories. 2 | 3 | You can get informed about certain files only using a filter and also filter on types of changes (e.g. new files, renamed files, changed files...) 4 | 5 | All you need in your script is to call WatchDirectory with required parameters and additional report function which is the second parameter to WatchDirectory. 6 | The report function must accepts 2 parameters: 7 | - When a file is changed, both parameters will contain same filename/path 8 | - When a file is deleted, first parameter contains the file/path and second parameter will be empty 9 | - When a new file is created, first parameter is empty and second parameter contains filename/path 10 | - When a file is renamed, first parameter contains old filename/path and second new filename/path 11 | 12 | WatchDirectory syntax: 13 | WatchDirectory(dir[\*|...],ReportFunction,ActionFilter) accepts up to 3 parameters 14 | - dir, can be a folder/directory (last backslash is optional) 15 | - include * in the end of your directory to watch in sub folders 16 | - after that you can include file name filters separated by pipe '|', here you have following options: 17 | - use * and ? wildcard 18 | - include Back Slash in front = match beginning of filename 19 | - include Back Slash at the end = match end of filename 20 | - include Back Slash anywhere in the middle to search in complete file path 21 | - E.g. following will search for files that start with a and end with .txt or .ini 22 | WatchDirectory("C:\temp\*|.txt\|.ini\|\a","ReportChanges") 23 | - func, a function to be launched when changes in corresponding folder occur 24 | - when you omit func, last used function will be used 25 | - Your function must accept 2 parameters 26 | - When new file is created: 27 | - first parameter will be empty 28 | - second parameter will contain the filepath 29 | - When file is deleted 30 | - second parameter will be empty 31 | - first parameter will contain the filepath 32 | - When file is modified both parameters contain same filepath 33 | - When file is renamed 34 | - first parameter will contain old filename 35 | - second parameter will contain new filename 36 | - ActionFilter can be used to report only specific changes 37 | - therefore include one or several of following values i 38 | - FILE_NOTIFY_CHANGE_FILE_NAME=0x1 39 | - FILE_NOTIFY_CHANGE_DIR_NAME=0x2 40 | - FILE_NOTIFY_CHANGE_ATTRIBUTES=0x4 41 | - FILE_NOTIFY_CHANGE_SIZE=0x8 42 | - FILE_NOTIFY_CHANGE_LAST_WRITE=0x10 43 | - FILE_NOTIFY_CHANGE_CREATION=0x40 44 | - FILE_NOTIFY_CHANGE_SECURITY=0x100 45 | - these values must be separated by |, by default all changes are reported. -------------------------------------------------------------------------------- /WatchDirectory.ahk: -------------------------------------------------------------------------------- 1 | /* 2 | #Persistent 3 | SetBatchLines,-1 4 | SetWinDelay,-1 5 | OnExit, GuiClose 6 | 7 | WatchFolders=C:\Temp*|%A_Temp%*|%A_Desktop%|%A_DesktopCommon%|%A_MyDocuments%*|%A_ScriptDir%|%A_WinDir%* 8 | Gui,+Resize 9 | Gui,Add,ListView,r10 w800 vWatchingDirectoriesList HWNDhList1 gShow,WatchingDirectories|WatchingSubdirs 10 | Loop,Parse,WatchFolders,| 11 | WatchDirectory(A_LoopField,"ReportChanges") 12 | ,LV_Add("",SubStr(A_LoopField,0)="*" ? (SubStr(A_LoopField,1,StrLen(A_LoopField)-1)) : A_LoopField 13 | ,SubStr(A_LoopField,0)="*" ? 1 : 0) 14 | LV_ModifyCol(1,"AutoHdr") 15 | Gui,Add,ListView,r30 w800 vChangesList HWNDhList2 gShow,Time|FileChangedFrom - Double click to show in Explorer|FileChangedTo - Double click to show in Explorer 16 | Gui,Add,Button,gAdd Default,Watch new directory 17 | Gui,Add,Button,gDelete x+1,Stop watching all directories 18 | Gui,Add,Button,gClear x+1,Clear List 19 | Gui,Add,StatusBar,,Changes Registered 20 | Gui, Show 21 | 22 | Return 23 | 24 | Clear: 25 | Gui,ListView, ChangesList 26 | LV_Delete() 27 | Return 28 | 29 | Delete: 30 | WatchDirectory("") 31 | Gui,ListView, WatchingDirectoriesList 32 | LV_Delete() 33 | Gui,ListView, ChangesList 34 | TotalChanges:=0 35 | SB_SetText("Changes Registered") 36 | Return 37 | 38 | Show: 39 | If A_GuiEvent!=DoubleClick 40 | Return 41 | Gui,ListView,%A_GuiControl% 42 | LV_GetText(file,A_EventInfo,2) 43 | If file= 44 | LV_GetText(file,A_EventInfo,3) 45 | Run,% "explorer.exe /e`, /n`, /select`," . file 46 | Return 47 | 48 | Add: 49 | Gui,+OwnDialogs 50 | dir= 51 | FileSelectFolder,dir,,3,Select directory to watch for 52 | If !dir 53 | Return 54 | SetTimer,SetMsgBoxButtons,-10 55 | MsgBox, 262146,Add directory,Would you like to watch for changes in:`n%dir% 56 | 57 | Gui,ListView, WatchingDirectoriesList 58 | IfMsgBox Retry 59 | WatchDirectory(dir "*"),LV_Add("",dir,1) 60 | IfMsgBox Ignore 61 | WatchDirectory(dir),LV_Add("",dir,0) 62 | LV_ModifyCol(1,"AutoHdr") 63 | Gui,ListView, ChangesList 64 | Return 65 | 66 | SetMsgBoxButtons: 67 | WinWait, ahk_class #32770 68 | WinActivate 69 | WinWaitActive 70 | ControlSetText,Button2,&Incl. subdirs, ahk_class #32770 71 | ControlSetText,Button3,&Excl. subdirs, ahk_class #32770 72 | Return 73 | 74 | ReportChanges(from,to){ 75 | global TotalChanges 76 | Gui,ListView, ChangesList 77 | LV_Insert(1,"",A_Hour ":" A_Min ":" A_Sec ":" A_MSec,from,to) 78 | LV_ModifyCol() 79 | LV_ModifyCol(1,"AutoHdr"),LV_ModifyCol(2,"AutoHdr") 80 | TotalChanges++ 81 | SB_SetText("Changes Registered " . TotalChanges) 82 | } 83 | 84 | GuiClose: 85 | WatchDirectory("") ;Stop Watching Directory = delete all directories 86 | ExitApp 87 | END: 88 | return 89 | */ 90 | #include <_Struct> 91 | WatchDirectory(p*){ 92 | ;Structures 93 | static FILE_NOTIFY_INFORMATION:="DWORD NextEntryOffset,DWORD Action,DWORD FileNameLength,WCHAR FileName[1]" 94 | static OVERLAPPED:="ULONG_PTR Internal,ULONG_PTR InternalHigh,{struct{DWORD offset,DWORD offsetHigh},PVOID Pointer},HANDLE hEvent" 95 | ;Variables 96 | static running,sizeof_FNI=65536,temp1:=VarSetCapacity(nReadLen,8),WatchDirectory:=RegisterCallback("WatchDirectory","F",0,0) 97 | static timer,ReportToFunction,LP,temp2:=VarSetCapacity(LP,(260)*(A_PtrSize/2),0) 98 | static @:=Object(),reconnect:=Object(),#:=Object(),DirEvents,StringToRegEx="\\\|.\.|+\+|[\[|{\{|(\(|)\)|^\^|$\$|?\.?|*.*" 99 | ;ReadDirectoryChanges related 100 | static FILE_NOTIFY_CHANGE_FILE_NAME=0x1,FILE_NOTIFY_CHANGE_DIR_NAME=0x2,FILE_NOTIFY_CHANGE_ATTRIBUTES=0x4 101 | ,FILE_NOTIFY_CHANGE_SIZE=0x8,FILE_NOTIFY_CHANGE_LAST_WRITE=0x10,FILE_NOTIFY_CHANGE_CREATION=0x40 102 | ,FILE_NOTIFY_CHANGE_SECURITY=0x100 103 | static FILE_ACTION_ADDED=1,FILE_ACTION_REMOVED=2,FILE_ACTION_MODIFIED=3 104 | ,FILE_ACTION_RENAMED_OLD_NAME=4,FILE_ACTION_RENAMED_NEW_NAME=5 105 | static OPEN_EXISTING=3,FILE_FLAG_BACKUP_SEMANTICS=0x2000000,FILE_FLAG_OVERLAPPED=0x40000000 106 | ,FILE_SHARE_DELETE=4,FILE_SHARE_WRITE=2,FILE_SHARE_READ=1,FILE_LIST_DIRECTORY=1 107 | If p.MaxIndex(){ 108 | If (p.MaxIndex()=1 && p.1=""){ 109 | for i,folder in # 110 | DllCall("CloseHandle","Uint",@[folder].hD),DllCall("CloseHandle","Uint",@[folder].O.hEvent) 111 | ,@.Remove(folder) 112 | #:=Object() 113 | DirEvents:=new _Struct("HANDLE[1000]") 114 | DllCall("KillTimer","Uint",0,"Uint",timer) 115 | timer= 116 | Return 0 117 | } else { 118 | if p.2 119 | ReportToFunction:=p.2 120 | If !IsFunc(ReportToFunction) 121 | Return -1 ;DllCall("MessageBox","Uint",0,"Str","Function " ReportToFunction " does not exist","Str","Error Missing Function","UInt",0) 122 | RegExMatch(p.1,"^([^/\*\?<>\|""]+)(\*)?(\|.+)?$",dir) 123 | if (SubStr(dir1,0)="\") 124 | StringTrimRight,dir1,dir1,1 125 | StringTrimLeft,dir3,dir3,1 126 | If (p.MaxIndex()=2 && p.2=""){ 127 | for i,folder in # 128 | If (dir1=SubStr(folder,1,StrLen(folder)-1)) 129 | Return 0 ,DirEvents[i]:=DirEvents[#.MaxIndex()],DirEvents[#.MaxIndex()]:=0 130 | @.Remove(folder),#[i]:=#[#.MaxIndex()],#.Remove(i) 131 | Return 0 132 | } 133 | } 134 | if !InStr(FileExist(dir1),"D") 135 | Return -1 ;DllCall("MessageBox","Uint",0,"Str","Folder " dir1 " does not exist","Str","Error Missing File","UInt",0) 136 | for i,folder in # 137 | { 138 | If (dir1=SubStr(folder,1,StrLen(folder)-1) || (InStr(dir1,folder) && @[folder].sD)) 139 | Return 0 140 | else if (InStr(SubStr(folder,1,StrLen(folder)-1),dir1 "\") && dir2){ ;replace watch 141 | DllCall("CloseHandle","Uint",@[folder].hD),DllCall("CloseHandle","Uint",@[folder].O.hEvent),reset:=i 142 | } 143 | } 144 | LP:=SubStr(LP,1,DllCall("GetLongPathName","Str",dir1,"Uint",&LP,"Uint",VarSetCapacity(LP))) "\" 145 | If !(reset && @[reset]:=LP) 146 | #.Insert(LP) 147 | @[LP,"dir"]:=LP 148 | @[LP].hD:=DllCall("CreateFile","Str",StrLen(LP)=3?SubStr(LP,1,2):LP,"UInt",0x1,"UInt",0x1|0x2|0x4 149 | ,"UInt",0,"UInt",0x3,"UInt",0x2000000|0x40000000,"UInt",0) 150 | @[LP].sD:=(dir2=""?0:1) 151 | 152 | Loop,Parse,StringToRegEx,| 153 | StringReplace,dir3,dir3,% SubStr(A_LoopField,1,1),% SubStr(A_LoopField,2),A 154 | StringReplace,dir3,dir3,%A_Space%,\s,A 155 | Loop,Parse,dir3,| 156 | { 157 | If A_Index=1 158 | dir3= 159 | pre:=(SubStr(A_LoopField,1,2)="\\"?2:0) 160 | succ:=(SubStr(A_LoopField,-1)="\\"?2:0) 161 | dir3.=(dir3?"|":"") (pre?"\\\K":"") 162 | . SubStr(A_LoopField,1+pre,StrLen(A_LoopField)-pre-succ) 163 | . ((!succ && !InStr(SubStr(A_LoopField,1+pre,StrLen(A_LoopField)-pre-succ),"\"))?"[^\\]*$":"") (succ?"$":"") 164 | } 165 | @[LP].FLT:="i)" dir3 166 | @[LP].FUNC:=ReportToFunction 167 | @[LP].CNG:=(p.3?p.3:(0x1|0x2|0x4|0x8|0x10|0x40|0x100)) 168 | If !reset { 169 | @[LP].SetCapacity("pFNI",sizeof_FNI) 170 | @[LP].FNI:=new _Struct(FILE_NOTIFY_INFORMATION,@[LP].GetAddress("pFNI")) 171 | @[LP].O:=new _Struct(OVERLAPPED) 172 | } 173 | @[LP].O.hEvent:=DllCall("CreateEvent","Uint",0,"Int",1,"Int",0,"UInt",0) 174 | If (!DirEvents) 175 | DirEvents:=new _Struct("HANDLE[1000]") 176 | DirEvents[reset?reset:#.MaxIndex()]:=@[LP].O.hEvent 177 | DllCall("ReadDirectoryChangesW","UInt",@[LP].hD,"UInt",@[LP].FNI[""],"UInt",sizeof_FNI 178 | ,"Int",@[LP].sD,"UInt",@[LP].CNG,"UInt",0,"UInt",@[LP].O[""],"UInt",0) 179 | Return timer:=DllCall("SetTimer","Uint",0,"UInt",timer,"Uint",50,"UInt",WatchDirectory) 180 | } else { 181 | Sleep, 0 182 | for LP in reconnect 183 | { 184 | If (FileExist(@[LP].dir) && reconnect.Remove(LP)){ 185 | DllCall("CloseHandle","Uint",@[LP].hD) 186 | @[LP].hD:=DllCall("CreateFile","Str",StrLen(@[LP].dir)=3?SubStr(@[LP].dir,1,2):@[LP].dir,"UInt",0x1,"UInt",0x1|0x2|0x4 187 | ,"UInt",0,"UInt",0x3,"UInt",0x2000000|0x40000000,"UInt",0) 188 | DllCall("ResetEvent","UInt",@[LP].O.hEvent) 189 | DllCall("ReadDirectoryChangesW","UInt",@[LP].hD,"UInt",@[LP].FNI[""],"UInt",sizeof_FNI 190 | ,"Int",@[LP].sD,"UInt",@[LP].CNG,"UInt",0,"UInt",@[LP].O[""],"UInt",0) 191 | } 192 | } 193 | if !( (r:=DllCall("MsgWaitForMultipleObjectsEx","UInt",#.MaxIndex() 194 | ,"UInt",DirEvents[""],"UInt",0,"UInt",0x4FF,"UInt",6))>=0 195 | && r<#.MaxIndex() ){ 196 | return 197 | } 198 | DllCall("KillTimer", UInt,0, UInt,timer) 199 | LP:=#[r+1],DllCall("GetOverlappedResult","UInt",@[LP].hD,"UInt",@[LP].O[""],"UIntP",nReadLen,"Int",1) 200 | If (A_LastError=64){ ; ERROR_NETNAME_DELETED - The specified network name is no longer available. 201 | If !FileExist(@[LP].dir) ; If folder does not exist add to reconnect routine 202 | reconnect.Insert(LP,LP) 203 | } else 204 | Loop { 205 | FNI:=A_Index>1?(new _Struct(FILE_NOTIFY_INFORMATION,FNI[""]+FNI.NextEntryOffset)):(new _Struct(FILE_NOTIFY_INFORMATION,@[LP].FNI[""])) 206 | If (FNI.Action < 0x6){ 207 | FileName:=@[LP].dir . StrGet(FNI.FileName[""],FNI.FileNameLength/2,"UTF-16") 208 | If ((FNI.Action=FILE_ACTION_RENAMED_OLD_NAME && FileFromOptional:=FileName) 209 | || @[LP].FLT="" || RegExMatch(FileName,@[LP].FLT) || RegExMatch(FileFrom,@[LP].FLT) || InStr(FileExist(FileName),"D")) 210 | If (FNI.Action=FILE_ACTION_ADDED){ 211 | FileTo:=FileName 212 | } else If (FNI.Action=FILE_ACTION_REMOVED){ 213 | FileFrom:=FileName 214 | } else If (FNI.Action=FILE_ACTION_MODIFIED){ 215 | FileFrom:=FileTo:=FileName 216 | } else If (FNI.Action=FILE_ACTION_RENAMED_OLD_NAME){ 217 | FileFrom:=FileName 218 | } else If (FNI.Action=FILE_ACTION_RENAMED_NEW_NAME){ 219 | FileTo:=FileName 220 | } 221 | If (FNI.Action != 4 && (FileTo . FileFrom) !="") 222 | @[LP].Func(FileFrom=""?FileFromOptional:FileFrom,FileTo) 223 | ,FileFrom:="",FileTo:="",FileFromOptional:="" 224 | } 225 | } Until (!FNI.NextEntryOffset || ((FNI[""]+FNI.NextEntryOffset) > (@[LP].FNI[""]+sizeof_FNI-12))) 226 | DllCall("ResetEvent","UInt",@[LP].O.hEvent) 227 | DllCall("ReadDirectoryChangesW","UInt",@[LP].hD,"UInt",@[LP].FNI[""],"UInt",sizeof_FNI 228 | ,"Int",@[LP].sD,"UInt",@[LP].CNG,"UInt",0,"UInt",@[LP].O[""],"UInt",0) 229 | timer:=DllCall("SetTimer","Uint",0,"UInt",timer,"Uint",50,"UInt",WatchDirectory) 230 | Return 231 | } 232 | Return 233 | } 234 | 235 | /* 236 | WatchDirectory(p*){ 237 | global _Struct 238 | ;Structures 239 | static FILE_NOTIFY_INFORMATION:="DWORD NextEntryOffset,DWORD Action,DWORD FileNameLength,WCHAR FileName[1]" 240 | static OVERLAPPED:="ULONG_PTR Internal,ULONG_PTR InternalHigh,{struct{DWORD offset,DWORD offsetHigh},PVOID Pointer},HANDLE hEvent" 241 | ;Variables 242 | static running,sizeof_FNI=65536,nReadLen:=VarSetCapacity(nReadLen,8),WatchDirectory:=RegisterCallback("WatchDirectory","F",0,0) 243 | static timer,ReportToFunction,LP,nReadLen:=VarSetCapacity(LP,(260)*(A_PtrSize/2),0) 244 | static @:=Object(),reconnect:=Object(),#:=Object(),DirEvents,StringToRegEx="\\\|.\.|+\+|[\[|{\{|(\(|)\)|^\^|$\$|?\.?|*.*" 245 | ;ReadDirectoryChanges related 246 | static FILE_NOTIFY_CHANGE_FILE_NAME=0x1,FILE_NOTIFY_CHANGE_DIR_NAME=0x2,FILE_NOTIFY_CHANGE_ATTRIBUTES=0x4 247 | ,FILE_NOTIFY_CHANGE_SIZE=0x8,FILE_NOTIFY_CHANGE_LAST_WRITE=0x10,FILE_NOTIFY_CHANGE_CREATION=0x40 248 | ,FILE_NOTIFY_CHANGE_SECURITY=0x100 249 | static FILE_ACTION_ADDED=1,FILE_ACTION_REMOVED=2,FILE_ACTION_MODIFIED=3 250 | ,FILE_ACTION_RENAMED_OLD_NAME=4,FILE_ACTION_RENAMED_NEW_NAME=5 251 | static OPEN_EXISTING=3,FILE_FLAG_BACKUP_SEMANTICS=0x2000000,FILE_FLAG_OVERLAPPED=0x40000000 252 | ,FILE_SHARE_DELETE=4,FILE_SHARE_WRITE=2,FILE_SHARE_READ=1,FILE_LIST_DIRECTORY=1 253 | If p.MaxIndex(){ 254 | If (p.MaxIndex()=1 && p.1=""){ 255 | for i,folder in # 256 | DllCall("CloseHandle","Uint",@[folder].hD),DllCall("CloseHandle","Uint",@[folder].O.hEvent) 257 | ,@.Remove(folder) 258 | #:=Object() 259 | DirEvents:=new _Struct("HANDLE[1000]") 260 | DllCall("KillTimer","Uint",0,"Uint",timer) 261 | timer= 262 | Return 0 263 | } else { 264 | if p.2 265 | ReportToFunction:=p.2 266 | If !IsFunc(ReportToFunction) 267 | Return -1 ;DllCall("MessageBox","Uint",0,"Str","Function " ReportToFunction " does not exist","Str","Error Missing Function","UInt",0) 268 | RegExMatch(p.1,"^([^/\*\?<>\|""]+)(\*)?(\|.+)?$",dir) 269 | if (SubStr(dir1,0)="\") 270 | StringTrimRight,dir1,dir1,1 271 | StringTrimLeft,dir3,dir3,1 272 | If (p.MaxIndex()=2 && p.2=""){ 273 | for i,folder in # 274 | If (dir1=SubStr(folder,1,StrLen(folder)-1)) 275 | Return 0 ,DirEvents[i]:=DirEvents[#.MaxIndex()],DirEvents[#.MaxIndex()]:=0 276 | @.Remove(folder),#[i]:=#[#.MaxIndex()],#.Remove(i) 277 | Return 0 278 | } 279 | } 280 | if !InStr(FileExist(dir1),"D") 281 | Return -1 ;DllCall("MessageBox","Uint",0,"Str","Folder " dir1 " does not exist","Str","Error Missing File","UInt",0) 282 | for i,folder in # 283 | { 284 | If (dir1=SubStr(folder,1,StrLen(folder)-1) || (InStr(dir1,folder) && @[folder].sD)) 285 | Return 0 286 | else if (InStr(SubStr(folder,1,StrLen(folder)-1),dir1 "\") && dir2){ ;replace watch 287 | DllCall("CloseHandle","Uint",@[folder].hD),DllCall("CloseHandle","Uint",@[folder].O.hEvent),reset:=i 288 | } 289 | } 290 | LP:=SubStr(LP,1,DllCall("GetLongPathName","Str",dir1,"Uint",&LP,"Uint",VarSetCapacity(LP))) "\" 291 | If !(reset && @[reset]:=LP) 292 | #.Insert(LP) 293 | @[LP,"dir"]:=LP 294 | @[LP].hD:=DllCall("CreateFile","Str",StrLen(LP)=3?SubStr(LP,1,2):LP,"UInt",0x1,"UInt",0x1|0x2|0x4 295 | ,"UInt",0,"UInt",0x3,"UInt",0x2000000|0x40000000,"UInt",0) 296 | @[LP].sD:=(dir2=""?0:1) 297 | 298 | Loop,Parse,StringToRegEx,| 299 | StringReplace,dir3,dir3,% SubStr(A_LoopField,1,1),% SubStr(A_LoopField,2),A 300 | StringReplace,dir3,dir3,%A_Space%,\s,A 301 | Loop,Parse,dir3,| 302 | { 303 | If A_Index=1 304 | dir3= 305 | pre:=(SubStr(A_LoopField,1,2)="\\"?2:0) 306 | succ:=(SubStr(A_LoopField,-1)="\\"?2:0) 307 | dir3.=(dir3?"|":"") (pre?"\\\K":"") 308 | . SubStr(A_LoopField,1+pre,StrLen(A_LoopField)-pre-succ) 309 | . ((!succ && !InStr(SubStr(A_LoopField,1+pre,StrLen(A_LoopField)-pre-succ),"\"))?"[^\\]*$":"") (succ?"$":"") 310 | } 311 | @[LP].FLT:="i)" dir3 312 | @[LP].FUNC:=ReportToFunction 313 | @[LP].CNG:=(p.3?p.3:(0x1|0x2|0x4|0x8|0x10|0x40|0x100)) 314 | If !reset { 315 | @[LP].SetCapacity("pFNI",sizeof_FNI) 316 | @[LP].FNI:=new _Struct(FILE_NOTIFY_INFORMATION,@[LP].GetAddress("pFNI")) 317 | @[LP].O:=new _Struct(OVERLAPPED) 318 | } 319 | @[LP].O.hEvent:=DllCall("CreateEvent","Uint",0,"Int",1,"Int",0,"UInt",0) 320 | If (!DirEvents) 321 | DirEvents:=new _Struct("HANDLE[1000]") 322 | DirEvents[reset?reset:#.MaxIndex()]:=@[LP].O.hEvent 323 | DllCall("ReadDirectoryChangesW","UInt",@[LP].hD,"UInt",@[LP].FNI[],"UInt",sizeof_FNI 324 | ,"Int",@[LP].sD,"UInt",@[LP].CNG,"UInt",0,"UInt",@[LP].O[],"UInt",0) 325 | Return timer:=DllCall("SetTimer","Uint",0,"UInt",timer,"Uint",50,"UInt",WatchDirectory) 326 | } else { 327 | Sleep, 0 328 | for LP in reconnect 329 | { 330 | If (FileExist(@[LP].dir) && reconnect.Remove(LP)){ 331 | DllCall("CloseHandle","Uint",@[LP].hD) 332 | @[LP].hD:=DllCall("CreateFile","Str",StrLen(@[LP].dir)=3?SubStr(@[LP].dir,1,2):@[LP].dir,"UInt",0x1,"UInt",0x1|0x2|0x4 333 | ,"UInt",0,"UInt",0x3,"UInt",0x2000000|0x40000000,"UInt",0) 334 | DllCall("ResetEvent","UInt",@[LP].O.hEvent) 335 | DllCall("ReadDirectoryChangesW","UInt",@[LP].hD,"UInt",@[LP].FNI[],"UInt",sizeof_FNI 336 | ,"Int",@[LP].sD,"UInt",@[LP].CNG,"UInt",0,"UInt",@[LP].O[],"UInt",0) 337 | } 338 | } 339 | if !( (r:=DllCall("MsgWaitForMultipleObjectsEx","UInt",#.MaxIndex() 340 | ,"UInt",DirEvents[],"UInt",0,"UInt",0x4FF,"UInt",6))>=0 341 | && r<#.MaxIndex() ){ 342 | return 343 | } 344 | DllCall("KillTimer", UInt,0, UInt,timer) 345 | LP:=#[r+1],DllCall("GetOverlappedResult","UInt",@[LP].hD,"UInt",@[LP].O[],"UIntP",nReadLen,"Int",1) 346 | If (A_LastError=64){ ; ERROR_NETNAME_DELETED - The specified network name is no longer available. 347 | If !FileExist(@[LP].dir) ; If folder does not exist add to reconnect routine 348 | reconnect.Insert(LP,LP) 349 | } else 350 | Loop { 351 | FNI:=A_Index>1?(new _Struct(FILE_NOTIFY_INFORMATION,FNI[]+FNI.NextEntryOffset)):(new _Struct(FILE_NOTIFY_INFORMATION,@[LP].FNI[])) 352 | If (FNI.Action < 0x6){ 353 | FileName:=@[LP].dir . StrGet(FNI.FileName[""],FNI.FileNameLength/2,"UTF-16") 354 | If (FNI.Action=FILE_ACTION_RENAMED_OLD_NAME) 355 | FileFromOptional:=FileName 356 | If (@[LP].FLT="" || RegExMatch(FileName,@[LP].FLT) || FileFrom) 357 | If (FNI.Action=FILE_ACTION_ADDED){ 358 | FileTo:=FileName 359 | } else If (FNI.Action=FILE_ACTION_REMOVED){ 360 | FileFrom:=FileName 361 | } else If (FNI.Action=FILE_ACTION_MODIFIED){ 362 | FileFrom:=FileTo:=FileName 363 | } else If (FNI.Action=FILE_ACTION_RENAMED_OLD_NAME){ 364 | FileFrom:=FileName 365 | } else If (FNI.Action=FILE_ACTION_RENAMED_NEW_NAME){ 366 | FileTo:=FileName 367 | } 368 | If (FNI.Action != 4 && (FileTo . FileFrom) !="") 369 | @[LP].Func(FileFrom=""?FileFromOptional:FileFrom,FileTo) 370 | } 371 | } Until (!FNI.NextEntryOffset || ((FNI[]+FNI.NextEntryOffset) > (@[LP].FNI[]+sizeof_FNI-12))) 372 | DllCall("ResetEvent","UInt",@[LP].O.hEvent) 373 | DllCall("ReadDirectoryChangesW","UInt",@[LP].hD,"UInt",@[LP].FNI[],"UInt",sizeof_FNI 374 | ,"Int",@[LP].sD,"UInt",@[LP].CNG,"UInt",0,"UInt",@[LP].O[],"UInt",0) 375 | timer:=DllCall("SetTimer","Uint",0,"UInt",timer,"Uint",50,"UInt",WatchDirectory) 376 | Return 377 | } 378 | Return 379 | } 380 | */ 381 | 382 | 383 | 384 | 385 | 386 | 387 | /* 388 | WatchDirectory(p*){ 389 | ;Structures 390 | static FILE_NOTIFY_INFORMATION:="DWORD NextEntryOffset,DWORD Action,DWORD FileNameLength,WCHAR FileName[1]" 391 | static OVERLAPPED:="ULONG_PTR Internal,ULONG_PTR InternalHigh,{{DWORD offset,DWORD offsetHigh},PVOID Pointer},HANDLE hEvent" 392 | ;Variables 393 | static running,sizeof_FNI=65536,nReadLen:=VarSetCapacity(nReadLen,8),WatchDirectory:=RegisterCallback("WatchDirectory","F",0,0) 394 | static timer,ReportToFunction,LP,nReadLen:=VarSetCapacity(LP,(260)*(A_PtrSize/2),0) 395 | static @:=Object(),reconnect:=Object(),#:=Object(),DirEvents,StringToRegEx="\\\|.\.|+\+|[\[|{\{|(\(|)\)|^\^|$\$|?\.?|*.*" 396 | ;ReadDirectoryChanges related 397 | static FILE_NOTIFY_CHANGE_FILE_NAME=0x1,FILE_NOTIFY_CHANGE_DIR_NAME=0x2,FILE_NOTIFY_CHANGE_ATTRIBUTES=0x4 398 | ,FILE_NOTIFY_CHANGE_SIZE=0x8,FILE_NOTIFY_CHANGE_LAST_WRITE=0x10,FILE_NOTIFY_CHANGE_CREATION=0x40 399 | ,FILE_NOTIFY_CHANGE_SECURITY=0x100 400 | static FILE_ACTION_ADDED=1,FILE_ACTION_REMOVED=2,FILE_ACTION_MODIFIED=3 401 | ,FILE_ACTION_RENAMED_OLD_NAME=4,FILE_ACTION_RENAMED_NEW_NAME=5 402 | static OPEN_EXISTING=3,FILE_FLAG_BACKUP_SEMANTICS=0x2000000,FILE_FLAG_OVERLAPPED=0x40000000 403 | ,FILE_SHARE_DELETE=4,FILE_SHARE_WRITE=2,FILE_SHARE_READ=1,FILE_LIST_DIRECTORY=1 404 | If p.MaxIndex(){ 405 | If (p.MaxIndex()=1 && p.1=""){ 406 | for i,folder in # 407 | DllCall("CloseHandle","Uint",@[folder].hD),DllCall("CloseHandle","Uint",@[folder].O.hEvent) 408 | ,@.Remove(folder) 409 | #:=Object() 410 | DirEvents:=Struct("HANDLE[1000]") 411 | DllCall("KillTimer","Uint",0,"Uint",timer) 412 | timer= 413 | Return 0 414 | } else { 415 | if p.2 416 | ReportToFunction:=p.2 417 | If !IsFunc(ReportToFunction) 418 | Return -1 ;DllCall("MessageBox","Uint",0,"Str","Function " ReportToFunction " does not exist","Str","Error Missing Function","UInt",0) 419 | RegExMatch(p.1,"^([^/\*\?<>\|""]+)(\*)?(\|.+)?$",dir) 420 | if (SubStr(dir1,0)="\") 421 | StringTrimRight,dir1,dir1,1 422 | StringTrimLeft,dir3,dir3,1 423 | If (p.MaxIndex()=2 && p.2=""){ 424 | for i,folder in # 425 | If (dir1=SubStr(folder,1,StrLen(folder)-1)) 426 | Return 0 ,DirEvents[i]:=DirEvents[#.MaxIndex()],DirEvents[#.MaxIndex()]:=0 427 | @.Remove(folder),#[i]:=#[#.MaxIndex()],#.Remove(i) 428 | Return 0 429 | } 430 | } 431 | if !InStr(FileExist(dir1),"D") 432 | Return -1 ;DllCall("MessageBox","Uint",0,"Str","Folder " dir1 " does not exist","Str","Error Missing File","UInt",0) 433 | for i,folder in # 434 | { 435 | If (dir1=SubStr(folder,1,StrLen(folder)-1) || (InStr(dir1,folder) && @[folder].sD)) 436 | Return 0 437 | else if (InStr(SubStr(folder,1,StrLen(folder)-1),dir1 "\") && dir2){ ;replace watch 438 | DllCall("CloseHandle","Uint",@[folder].hD),DllCall("CloseHandle","Uint",@[folder].O.hEvent),reset:=i 439 | } 440 | } 441 | LP:=SubStr(LP,1,DllCall("GetLongPathName","Str",dir1,"Uint",&LP,"Uint",VarSetCapacity(LP))) "\" 442 | If !(reset && @[reset]:=LP) 443 | #.Insert(LP) 444 | @[LP,"dir"]:=LP 445 | @[LP].hD:=DllCall("CreateFile","Str",StrLen(LP)=3?SubStr(LP,1,2):LP,"UInt",0x1,"UInt",0x1|0x2|0x4 446 | ,"UInt",0,"UInt",0x3,"UInt",0x2000000|0x40000000,"UInt",0) 447 | @[LP].sD:=(dir2=""?0:1) 448 | 449 | Loop,Parse,StringToRegEx,| 450 | StringReplace,dir3,dir3,% SubStr(A_LoopField,1,1),% SubStr(A_LoopField,2),A 451 | StringReplace,dir3,dir3,%A_Space%,\s,A 452 | Loop,Parse,dir3,| 453 | { 454 | If A_Index=1 455 | dir3= 456 | pre:=(SubStr(A_LoopField,1,2)="\\"?2:0) 457 | succ:=(SubStr(A_LoopField,-1)="\\"?2:0) 458 | dir3.=(dir3?"|":"") (pre?"\\\K":"") 459 | . SubStr(A_LoopField,1+pre,StrLen(A_LoopField)-pre-succ) 460 | . ((!succ && !InStr(SubStr(A_LoopField,1+pre,StrLen(A_LoopField)-pre-succ),"\"))?"[^\\]*$":"") (succ?"$":"") 461 | } 462 | @[LP].FLT:="i)" dir3 463 | @[LP].FUNC:=ReportToFunction 464 | @[LP].CNG:=(p.3?p.3:(0x1|0x2|0x4|0x8|0x10|0x40|0x100)) 465 | If !reset { 466 | @[LP].SetCapacity("pFNI",sizeof_FNI) 467 | @[LP].FNI:=Struct(FILE_NOTIFY_INFORMATION,@[LP].GetAddress("pFNI")) 468 | @[LP].O:=Struct(OVERLAPPED) 469 | } 470 | @[LP].O.hEvent:=DllCall("CreateEvent","Uint",0,"Int",1,"Int",0,"UInt",0) 471 | If (!DirEvents) 472 | DirEvents:=Struct("HANDLE[1000]") 473 | DirEvents[reset?reset:#.MaxIndex()]:=@[LP].O.hEvent 474 | DllCall("ReadDirectoryChangesW","UInt",@[LP].hD,"UInt",@[LP].FNI[],"UInt",sizeof_FNI 475 | ,"Int",@[LP].sD,"UInt",@[LP].CNG,"UInt",0,"UInt",@[LP].O[],"UInt",0) 476 | Return timer:=DllCall("SetTimer","Uint",0,"UInt",timer,"Uint",50,"UInt",WatchDirectory) 477 | } else { 478 | Sleep, 0 479 | for LP in reconnect 480 | { 481 | If (FileExist(@[LP].dir) && reconnect.Remove(LP)){ 482 | DllCall("CloseHandle","Uint",@[LP].hD) 483 | @[LP].hD:=DllCall("CreateFile","Str",StrLen(@[LP].dir)=3?SubStr(@[LP].dir,1,2):@[LP].dir,"UInt",0x1,"UInt",0x1|0x2|0x4 484 | ,"UInt",0,"UInt",0x3,"UInt",0x2000000|0x40000000,"UInt",0) 485 | DllCall("ResetEvent","UInt",@[LP].O.hEvent) 486 | DllCall("ReadDirectoryChangesW","UInt",@[LP].hD,"UInt",@[LP].FNI[],"UInt",sizeof_FNI 487 | ,"Int",@[LP].sD,"UInt",@[LP].CNG,"UInt",0,"UInt",@[LP].O[],"UInt",0) 488 | } 489 | } 490 | if !( (r:=DllCall("MsgWaitForMultipleObjectsEx","UInt",#.MaxIndex() 491 | ,"UInt",DirEvents[],"UInt",0,"UInt",0x4FF,"UInt",6))>=0 492 | && r<#.MaxIndex() ){ 493 | return 494 | } 495 | DllCall("KillTimer", UInt,0, UInt,timer) 496 | LP:=#[r+1],DllCall("GetOverlappedResult","UInt",@[LP].hD,"UInt",@[LP].O[],"UIntP",nReadLen,"Int",1) 497 | If (A_LastError=64){ ; ERROR_NETNAME_DELETED - The specified network name is no longer available. 498 | If !FileExist(@[LP].dir) ; If folder does not exist add to reconnect routine 499 | reconnect.Insert(LP,LP) 500 | } else 501 | Loop { 502 | FNI:=A_Index>1?Struct(FILE_NOTIFY_INFORMATION,FNI[]+FNI.NextEntryOffset):Struct(FILE_NOTIFY_INFORMATION,@[LP].FNI[]) 503 | If (FNI.Action < 0x6){ 504 | FileName:=@[LP].dir StrGet(FNI.FileName[""],FNI.FileNameLength/2,"UTF-16") 505 | If (FNI.Action=FILE_ACTION_RENAMED_OLD_NAME) 506 | FileFromOptional:=FileName 507 | If (@[LP].FLT="" || RegExMatch(FileName,@[LP].FLT) || FileFrom) 508 | If (FNI.Action=FILE_ACTION_ADDED){ 509 | FileTo:=FileName 510 | } else If (FNI.Action=FILE_ACTION_REMOVED){ 511 | FileFrom:=FileName 512 | } else If (FNI.Action=FILE_ACTION_MODIFIED){ 513 | FileFrom:=FileTo:=FileName 514 | } else If (FNI.Action=FILE_ACTION_RENAMED_OLD_NAME){ 515 | FileFrom:=FileName 516 | } else If (FNI.Action=FILE_ACTION_RENAMED_NEW_NAME){ 517 | FileTo:=FileName 518 | } 519 | If (FNI.Action != 4 && (FileTo . FileFrom) !="") 520 | @[LP].Func(FileFrom=""?FileFromOptional:FileFrom,FileTo) 521 | } 522 | } Until (!FNI.NextEntryOffset || ((FNI[]+FNI.NextEntryOffset) > (@[LP].FNI[]+sizeof_FNI-12))) 523 | DllCall("ResetEvent","UInt",@[LP].O.hEvent) 524 | DllCall("ReadDirectoryChangesW","UInt",@[LP].hD,"UInt",@[LP].FNI[],"UInt",sizeof_FNI 525 | ,"Int",@[LP].sD,"UInt",@[LP].CNG,"UInt",0,"UInt",@[LP].O[],"UInt",0) 526 | timer:=DllCall("SetTimer","Uint",0,"UInt",timer,"Uint",50,"UInt",WatchDirectory) 527 | Return 528 | } 529 | Return 530 | } 531 | --------------------------------------------------------------------------------