 |
AutoHotkey Community Let's help each other out
|
| View previous topic :: View next topic |
| Author |
Message |
HotKeyIt
Joined: 18 Jun 2008 Posts: 2190 Location: GERMANY
|
Posted: Sat Jun 13, 2009 12:01 am Post subject: WatchDirectory() |
|
|
This functionality already exist in Crazy Scripting : FolderSpy v0.96 [ Synchronous ]
Many thanks to SKAN and Lexikos
I have been working on this function quite a long time, trying to understand everything
Finally I have put together an all in one function to handle that procedure.
- You can add a new folder to watch for.
- Report changes to any function
- Stop watching
Hope you like it and find it useful.
Please report any bugs or suggestions.
| WatchDirectory(WatchFolder,WatchSubDirs) wrote: |
Parameters
WatchFolder - Specify a valid path to watch for changes in.
- can be directory or drive (e.g. c:\ or c:\Temp)
- can be network path e.g. \\192.168.2.101\Shared)
- can include last backslash. e.g. C:\Temp\ (will be reported same form)
WatchSubDirs - Specify 1 to search in subfolders
StopWatching - THIS SHOULD BE DONE BEFORE EXITING SCRIPT AT LEAST (OnExit)
Call WatchDirectory() without parameters to stop watching all directories
ReportChanges
Call WatchDirectory("ReportingFunctionName") to process registered changes.
Syntax of ReportingFunctionName(Action,Folder,File)
Windows 2000++ required |
Easy example
| Code: | #Persistent
OnExit,Exit
WatchDirectory("C:\Windows",1)
SetTimer,WatchFolder,100
Return
WatchFolder:
WatchDirectory("RegisterChanges")
Return
RegisterChanges(action,folder,file){
static
#1:="New File", #2:="Deleted", #3:="Modified", #4:="Renamed From", #5:="Renamed To"
ToolTip % #%Action% "`n" folder . (SubStr(folder,0)="\" ? "" : "\") . file
}
Exit:
WatchDirectory()
ExitApp |
Function and a script that I used for testing:
| Code: | #Persistent
OnExit, GuiClose
WatchFolders=C:\Temp*|%A_Temp%*|%A_Desktop%|%A_DesktopCommon%|%A_MyDocuments%*|%A_ScriptDir%|%A_WinDir%*
Gui,Add,ListView,r10 w600 vWatchingDirectoriesList gShowDir,WatchingDirectories|WatchingSubdirs
Loop,Parse,WatchFolders,|
WatchDirectory(SubStr(A_LoopField,0)="*" ? (SubStr(A_LoopField,1,StrLen(A_LoopField)-1)) : A_LoopField
, SubStr(A_LoopField,0)="*" ? 1 : "")
,LV_Add("",SubStr(A_LoopField,0)="*" ? (SubStr(A_LoopField,1,StrLen(A_LoopField)-1)) : A_LoopField
, SubStr(A_LoopField,0)="*" ? 1 : 0)
LV_ModifyCol(1,"AutoHdr")
Gui,Add,ListView,r30 w600 vChangesList gShowFile,Action|Dir|FileName - Double click to open in explorer
Gui,Add,Button,gAdd Default,Watch new directory
Gui,Add,Button,gDelete x+1,Stop watching all directories
Gui,Add,Button,gClear x+1,Clear List
Gui,Add,StatusBar,,Changes Registered
Gui, Show
SetTimer, WatchFolder, -100
Return
Clear:
Gui,ListView, ChangesList
LV_Delete()
Return
Delete:
WatchDirectory()
Gui,ListView, WatchingDirectoriesList
LV_Delete()
Gui,ListView, ChangesList
TotalChanges:=0
SB_SetText("Changes Registered")
Return
ShowDir:
If A_GuiEvent!=DoubleClick
Return
Gui,ListView,%A_GuiControl%
LV_GetText(folder,A_EventInfo,1)
Run,% "explorer.exe /e`, /n`, /select`," . folder
Return
ShowFile:
If A_GuiEvent!=DoubleClick
Return
Gui,ListView,%A_GuiControl%
LV_GetText(folder,A_EventInfo,2)
LV_GetText(file,A_EventInfo,3)
Run,% "explorer.exe /e`, /n`, /select`," . (folder . "\" . file)
Return
Add:
Gui,+OwnDialogs
FileSelectFolder,dir,,3,Select directory to watch for
SetTimer,SetMsgBoxButtons,-50
MsgBox, 262146,Add directory,Would you like to watch for changes in:`n%dir%
SplashTextOn,600,0,Adding %dir% ...
Gui,ListView, WatchingDirectoriesList
IfMsgBox Retry
WatchDirectory(dir),LV_Add("",dir,1)
IfMsgBox Ignore
WatchDirectory(dir,0),LV_Add("",dir,0)
SplashTextOff
LV_ModifyCol(1,"AutoHdr")
Gui,ListView, ChangesList
Return
SetMsgBoxButtons:
ControlSetText,Button2,&Incl. subdirs, ahk_class #32770
ControlSetText,Button3,&Excl. subdirs, ahk_class #32770
Return
WatchFolder:
WatchDirectory("ReportDirectoryChanges")
SetTimer, WatchFolder, -10
Return
ReportDirectoryChanges(Action,folder,file){
static
#1:="New File", #2:="Deleted", #3:="Modified", #4:="Renamed From", #5:="Renamed To"
;ToolTip % #%Action% "`n" folder . (SubStr(folder,0)="\" ? "" : "\") . file
path:=folder . (SubStr(folder,0)="\" ? "" : "\") . file
Gui,ListView, ChangesList
SplitPath,path,filename,dir
LV_Add("",#%Action%,dir,filename)
LV_ModifyCol()
LV_ModifyCol(3,"AutoHdr")
TotalChanges++
SB_SetText("Changes Registered " . TotalChanges)
}
GuiClose:
WatchDirectory()
ExitApp
;Function WatchDirectory()
;
;Parameters
; WatchFolder - Specify a valid path to watch for changes in.
; - can be directory or drive (e.g. c:\ or c:\Temp)
; - can be network path e.g. \\192.168.2.101\Shared)
; - can include last backslash. e.g. C:\Temp\ (will be reported same form)
;
; WatchSubDirs - Specify whether to search in subfolders
;
;StopWatching - THIS SHOULD BE DONE BEFORE EXITING SCRIPT AT LEAST (OnExit)
; Call WatchDirectory() without parameters to stop watching all directories
;
;ReportChanges
; Call WatchDirectory("ReportingFunctionName") to process registered changes.
; Syntax of ReportingFunctionName(Action,Folder,File)
;
; Example
/*
#Persistent
OnExit,Exit
WatchDirectory("C:\Windows",1)
SetTimer,WatchFolder,100
Return
WatchFolder:
WatchDirectory("RegisterChanges")
Return
RegisterChanges(action,folder,file){
static
#1:="New File", #2:="Deleted", #3:="Modified", #4:="Renamed From", #5:="Renamed To"
ToolTip % #%Action% "`n" folder . (SubStr(folder,0)="\" ? "" : "\") . file
}
Exit:
WatchDirectory()
ExitApp
*/
WatchDirectory(WatchFolder="", WatchSubDirs=true)
{
static
local hDir, hEvent, r, Action, FileNameLen, pFileName, Restart, CurrentFolder, PointerFNI, _SizeOf_FNI_=65536
nReadLen := 0
If !(WatchFolder){
Gosub, StopWatchingDirectories
} else if IsFunc(WatchFolder) {
r := DllCall("MsgWaitForMultipleObjectsEx", UInt, DirIdx, UInt, &DirEvents, UInt, -1, UInt, 0x4FF, UInt, 0x6) ;Timeout=-1
if !(r >= 0 && r < DirIdx)
Return
r += 1
CurrentFolder := Dir%r%Path
PointerFNI := &Dir%r%FNI
DllCall( "GetOverlappedResult", UInt, hDir, UInt, &Dir%r%Overlapped, UIntP, nReadLen, Int, true )
Loop {
pNext := NumGet( PointerFNI + 0 )
Action := NumGet( PointerFNI + 4 )
FileNameLen := NumGet( PointerFNI + 8 )
pFileName := ( PointerFNI + 12 )
If (Action < 0x6){
VarSetCapacity( FileNameANSI, FileNameLen )
DllCall( "WideCharToMultiByte",UInt,0,UInt,0,UInt,pFileName,UInt,FileNameLen,Str,FileNameANSI,UInt,FileNameLen,UInt,0,UInt,0)
%WatchFolder%(Action,CurrentFolder,SubStr( FileNameANSI, 1, FileNameLen/2 ))
}
If (!pNext or pNext = 4129024)
Break
Else
PointerFNI := (PointerFNI + pNext)
}
DllCall( "ResetEvent", UInt,NumGet( Dir%r%Overlapped, 16 ) )
Gosub, ReadDirectoryChanges
return r
} else {
Loop % (DirIdx) {
If InStr(WatchFolder, Dir%A_Index%Path){
If (Dir%A_Index%Subdirs)
Return
} else if InStr(Dir%A_Index%Path, WatchFolder) {
If (WatchSubDirs){
DllCall( "CloseHandle", UInt,Dir%A_Index% )
DllCall( "CloseHandle", UInt,NumGet(Dir%A_Index%Overlapped, 16) )
Restart := DirIdx, DirIdx := A_Index
}
}
}
If !Restart
DirIdx += 1
r:=DirIdx
hDir := DllCall( "CreateFile"
, Str , WatchFolder
, UInt , ( FILE_LIST_DIRECTORY := 0x1 )
, UInt , ( FILE_SHARE_READ := 0x1 )
| ( FILE_SHARE_WRITE := 0x2 )
| ( FILE_SHARE_DELETE := 0x4 )
, UInt , 0
, UInt , ( OPEN_EXISTING := 0x3 )
, UInt , ( FILE_FLAG_BACKUP_SEMANTICS := 0x2000000 )
| ( FILE_FLAG_OVERLAPPED := 0x40000000 )
, UInt , 0 )
Dir%r% := hDir
Dir%r%Path := WatchFolder
Dir%r%Subdirs := WatchSubDirs
VarSetCapacity( Dir%r%FNI, _SizeOf_FNI_ )
VarSetCapacity( Dir%r%Overlapped, 20, 0 )
DllCall( "CloseHandle", UInt,hEvent )
hEvent := DllCall( "CreateEvent", UInt,0, Int,true, Int,false, UInt,0 )
NumPut( hEvent, Dir%r%Overlapped, 16 )
if ( VarSetCapacity(DirEvents) < DirIdx*4 and VarSetCapacity(DirEvents, DirIdx*4 + 60))
Loop %DirIdx%
{
If (SubStr(Dir%A_Index%Path,1,1)!="-"){
action++
NumPut( NumGet( Dir%action%Overlapped, 16 ), DirEvents, action*4-4 )
}
}
NumPut( hEvent, DirEvents, DirIdx*4-4)
Gosub, ReadDirectoryChanges
If Restart
DirIdx = %Restart%
}
Return
StopWatchingDirectories:
Loop % (DirIdx) {
DllCall( "CloseHandle", UInt,Dir%A_Index% )
DllCall( "CloseHandle", UInt,NumGet(Dir%A_Index%Overlapped, 16) )
Dir%A_Index%=
Dir%A_Index%Path=
Dir%A_Index%Subdirs=
Dir%A_Index%FNI=
DllCall( "CloseHandle", UInt, NumGet(Dir%A_Index%Overlapped,16) )
VarSetCapacity(Dir%A_Index%Overlapped,0)
}
DirIdx=
VarSetCapacity(DirEvents,0)
Return
ReadDirectoryChanges:
DllCall( "ReadDirectoryChangesW"
, UInt , Dir%r%
, UInt , &Dir%r%FNI
, UInt , _SizeOf_FNI_
, UInt , Dir%r%SubDirs
, UInt , ( FILE_NOTIFY_CHANGE_FILE_NAME := 0x1 )
| ( FILE_NOTIFY_CHANGE_DIR_NAME := 0x2 )
| ( FILE_NOTIFY_CHANGE_ATTRIBUTES := 0x4 )
| ( FILE_NOTIFY_CHANGE_SIZE := 0x8 )
| ( FILE_NOTIFY_CHANGE_LAST_WRITE := 0x10 )
| ( FILE_NOTIFY_CHANGE_CREATION := 0x40 )
| ( FILE_NOTIFY_CHANGE_SECURITY := 0x100 )
, UInt , 0
, UInt , &Dir%r%Overlapped
, UInt , 0 )
Return
} |
_________________ AutoHotFile - ToolTip(n,text,title,options) |
|
| Back to top |
|
 |
TLM
Joined: 21 Aug 2006 Posts: 920 Location: The Shell
|
Posted: Sat Jun 13, 2009 11:36 am Post subject: |
|
|
Thanks for this!
I was wondeirng if this will 'monitor' all dir's recursed from root(s)? _________________
 |
|
| Back to top |
|
 |
HotKeyIt
Joined: 18 Jun 2008 Posts: 2190 Location: GERMANY
|
Posted: Sun Jun 14, 2009 12:22 am Post subject: |
|
|
| TLM wrote: | Thanks for this!
I was wondeirng if this will 'monitor' all dir's recursed from root(s)? |
WatchDirectory("C:\",1) is definitely possible, I am not sure if WatchDirectory("\\192.168.2.102\",1) will work, I will test tomorrow. _________________ AutoHotFile - ToolTip(n,text,title,options) |
|
| Back to top |
|
 |
TLM
Joined: 21 Aug 2006 Posts: 920 Location: The Shell
|
Posted: Sun Jun 14, 2009 1:40 am Post subject: |
|
|
Just a heads up, there are errors in both versions starting with 'static'. I think it should be 'static:'???
After that the 1st WatchDirectory func is not recognized.
I'd really like it if the easy version worked (at least I can somewhat understand it) .. _________________
 |
|
| Back to top |
|
 |
HotKeyIt
Joined: 18 Jun 2008 Posts: 2190 Location: GERMANY
|
Posted: Sun Jun 14, 2009 2:01 am Post subject: |
|
|
| TLM wrote: | Just a heads up, there are errors in both versions starting with 'static'. I think it should be 'static:'???
After that the 1st WatchDirectory func is not recognized.
I'd really like it if the easy version worked (at least I can somewhat understand it) .. |
static mode in WatchDirectory is used to keep variables inside the function so you have no access to these outside it.
In ReportDirectoryChanges static mode is used to keep those variables loaded
| Code: | | #1:="New File", #2:="Deleted", #3:="Modified", #4:="Renamed From", #5:="Renamed To" |
As far as I understand otherwise they would need to be assigned each time calling that function.
| Quote: | | After that the 1st WatchDirectory func is not recognized. |
What exactly do you mean?
When I change WatchFolders to | Code: | | WatchFolders=%A_WinDir%*|C:\Temp* |
I get all changes reported?
Is this not working for you? _________________ AutoHotFile - ToolTip(n,text,title,options) |
|
| Back to top |
|
 |
TLM
Joined: 21 Aug 2006 Posts: 920 Location: The Shell
|
Posted: Sun Jun 14, 2009 2:34 am Post subject: |
|
|
Heres what I get..
When static is changed to static:
 _________________
 |
|
| Back to top |
|
 |
infogulch
Joined: 27 Mar 2008 Posts: 378
|
Posted: Sun Jun 14, 2009 2:53 am Post subject: |
|
|
Wow! Thanks! I've wanted this so many times!
Quick question: Does it only report acculumulated changes up until WatchDirectory() is called with a function name?
TLM: is your autohotkey version current? 1.48*** _________________
Scripts - License |
|
| Back to top |
|
 |
HotKeyIt
Joined: 18 Jun 2008 Posts: 2190 Location: GERMANY
|
Posted: Sun Jun 14, 2009 6:40 am Post subject: |
|
|
| infogulch wrote: | Wow! Thanks! I've wanted this so many times!
Quick question: Does it only report acculumulated changes up until WatchDirectory() is called with a function name? |
Thank you me too
Yes your are right, as far as I understand but please bear in mind:
| MSDN wrote: | | When you first call ReadDirectoryChangesW, the system allocates a buffer to store change information. This buffer is associated with the directory handle until it is closed and its size does not change during its lifetime. Directory changes that occur between calls to this function are added to the buffer and then returned with the next call. If the buffer overflows, the entire contents of the buffer are discarded and the lpBytesReturned parameter contains zero. |
_________________ AutoHotFile - ToolTip(n,text,title,options) |
|
| Back to top |
|
 |
TLM
Joined: 21 Aug 2006 Posts: 920 Location: The Shell
|
Posted: Sun Jun 14, 2009 9:22 pm Post subject: |
|
|
Wish I could get this to work  _________________
 |
|
| Back to top |
|
 |
Krogdor
Joined: 18 Apr 2008 Posts: 1381 Location: The Interwebs
|
Posted: Sun Jun 14, 2009 9:24 pm Post subject: |
|
|
| TLM wrote: | Wish I could get this to work  |
You need to upgrade to the latest AHK version, which supports assume-static functions. |
|
| Back to top |
|
 |
HotKeyIt
Joined: 18 Jun 2008 Posts: 2190 Location: GERMANY
|
|
| Back to top |
|
 |
TLM
Joined: 21 Aug 2006 Posts: 920 Location: The Shell
|
Posted: Mon Jun 15, 2009 11:28 am Post subject: |
|
|
Not to be a pita but I installed the latest version and I get this
I really need this function to work.
Any assitance please _________________
 |
|
| Back to top |
|
 |
HotKeyIt
Joined: 18 Jun 2008 Posts: 2190 Location: GERMANY
|
Posted: Mon Jun 15, 2009 12:53 pm Post subject: |
|
|
| TLM wrote: | Not to be a pita but I installed the latest version and I get this
I really need this function to work.
Any assitance please |
This is now because you did not put the function in your Lib folder
e.g. C:\Program Files\AutoHotkey\Lib\WatchDirectory.ahk
But you can also use #include, e.g. | Code: | | #include C:\Program Files\AutoHotkey\AutoScriptWriter\WatchDirectory.ahk |
When you copy the whole script + function at the top into a file (not the easy example), doesn't it work for you? _________________ AutoHotFile - ToolTip(n,text,title,options) |
|
| Back to top |
|
 |
infogulch
Joined: 27 Mar 2008 Posts: 378
|
Posted: Mon Jun 15, 2009 4:10 pm Post subject: |
|
|
HotKeyIt:
Did you test if it works with UNC paths? The ReadDirectoryChangesW function doesn't even mention it, but maybe a mapped network drive would work.
Thx again! _________________
Scripts - License |
|
| Back to top |
|
 |
HotKeyIt
Joined: 18 Jun 2008 Posts: 2190 Location: GERMANY
|
Posted: Mon Jun 15, 2009 7:22 pm Post subject: |
|
|
| infogulch wrote: | HotKeyIt:
Did you test if it works with UNC paths? The ReadDirectoryChangesW function doesn't even mention it, but maybe a mapped network drive would work.
Thx again! |
Yes I tested on my home PC from Laptop watching \\192.168.2.103\data and it worked very well, as well as on a mapped drive
I was surprised that this works
Edit:
Though it does not work for an online mapped drive  _________________ AutoHotFile - ToolTip(n,text,title,options) |
|
| Back to top |
|
 |
|
|
You can post new topics in this forum You can reply to topics in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|