AutoHotkey Homepage AutoHotkey Community
Let's help each other out
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

WatchDirectory()
Goto page 1, 2, 3  Next
 
Post new topic   Reply to topic    AutoHotkey Community Forum Index -> Scripts & Functions
View previous topic :: View next topic  
Author Message
HotKeyIt



Joined: 18 Jun 2008
Posts: 2190
Location: GERMANY

PostPosted: Sat Jun 13, 2009 12:01 am    Post subject: WatchDirectory() Reply with quote

This functionality already exist in Crazy Scripting : FolderSpy v0.96 [ Synchronous ]
Many thanks to SKAN and Lexikos Wink

I have been working on this function quite a long time, trying to understand everything Confused
Finally I have put together an all in one function to handle that procedure. Very Happy

- You can add a new folder to watch for.
- Report changes to any function
- Stop watching

Hope you like it and find it useful. Wink

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) Wink
Back to top
View user's profile Send private message
TLM



Joined: 21 Aug 2006
Posts: 920
Location: The Shell

PostPosted: Sat Jun 13, 2009 11:36 am    Post subject: Reply with quote

Thanks for this!

I was wondeirng if this will 'monitor' all dir's recursed from root(s)?
_________________
Back to top
View user's profile Send private message
HotKeyIt



Joined: 18 Jun 2008
Posts: 2190
Location: GERMANY

PostPosted: Sun Jun 14, 2009 12:22 am    Post subject: Reply with quote

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) Wink
Back to top
View user's profile Send private message
TLM



Joined: 21 Aug 2006
Posts: 920
Location: The Shell

PostPosted: Sun Jun 14, 2009 1:40 am    Post subject: Reply with quote

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) Wink..
_________________
Back to top
View user's profile Send private message
HotKeyIt



Joined: 18 Jun 2008
Posts: 2190
Location: GERMANY

PostPosted: Sun Jun 14, 2009 2:01 am    Post subject: Reply with quote

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) Wink..


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) Wink
Back to top
View user's profile Send private message
TLM



Joined: 21 Aug 2006
Posts: 920
Location: The Shell

PostPosted: Sun Jun 14, 2009 2:34 am    Post subject: Reply with quote

Heres what I get..

When static is changed to static:

_________________
Back to top
View user's profile Send private message
infogulch



Joined: 27 Mar 2008
Posts: 378

PostPosted: Sun Jun 14, 2009 2:53 am    Post subject: Reply with quote

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
View user's profile Send private message
HotKeyIt



Joined: 18 Jun 2008
Posts: 2190
Location: GERMANY

PostPosted: Sun Jun 14, 2009 6:40 am    Post subject: Reply with quote

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 Very Happy
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) Wink
Back to top
View user's profile Send private message
TLM



Joined: 21 Aug 2006
Posts: 920
Location: The Shell

PostPosted: Sun Jun 14, 2009 9:22 pm    Post subject: Reply with quote

Wish I could get this to work Crying or Very sad
_________________
Back to top
View user's profile Send private message
Krogdor



Joined: 18 Apr 2008
Posts: 1381
Location: The Interwebs

PostPosted: Sun Jun 14, 2009 9:24 pm    Post subject: Reply with quote

TLM wrote:
Wish I could get this to work Crying or Very sad

You need to upgrade to the latest AHK version, which supports assume-static functions.
Back to top
View user's profile Send private message AIM Address
HotKeyIt



Joined: 18 Jun 2008
Posts: 2190
Location: GERMANY

PostPosted: Sun Jun 14, 2009 10:10 pm    Post subject: Reply with quote

TLM wrote:
Wish I could get this to work Crying or Very sad

->http://www.autohotkey.com/download/
_________________
AutoHotFile - ToolTip(n,text,title,options) Wink
Back to top
View user's profile Send private message
TLM



Joined: 21 Aug 2006
Posts: 920
Location: The Shell

PostPosted: Mon Jun 15, 2009 11:28 am    Post subject: Reply with quote

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
View user's profile Send private message
HotKeyIt



Joined: 18 Jun 2008
Posts: 2190
Location: GERMANY

PostPosted: Mon Jun 15, 2009 12:53 pm    Post subject: Reply with quote

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) Wink
Back to top
View user's profile Send private message
infogulch



Joined: 27 Mar 2008
Posts: 378

PostPosted: Mon Jun 15, 2009 4:10 pm    Post subject: Reply with quote

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
View user's profile Send private message
HotKeyIt



Joined: 18 Jun 2008
Posts: 2190
Location: GERMANY

PostPosted: Mon Jun 15, 2009 7:22 pm    Post subject: Reply with quote

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 Smile
I was surprised that this works Surprised

Edit:
Though it does not work for an online mapped drive Sad
_________________
AutoHotFile - ToolTip(n,text,title,options) Wink
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    AutoHotkey Community Forum Index -> Scripts & Functions All times are GMT
Goto page 1, 2, 3  Next
Page 1 of 3

 
Jump to:  
You can post new topics in this forum
You can reply to topics in this forum


Powered by phpBB © 2001, 2005 phpBB Group