 |
AutoHotkey Community Let's help each other out
|
| View previous topic :: View next topic |
| Author |
Message |
shimanov
Joined: 25 Sep 2005 Posts: 612
|
Posted: Thu Jan 05, 2006 4:45 am Post subject: detect file and directory changes |
|
|
The included code encapsulates and demonstrates an OS facility to detect changes to files and directories. The required functions are present with all versions of Windows.
The monitored events are:
* FILE_NAME
* DIR_NAME
* ATTRIBUTES
* SIZE
* LAST_WRITE
* SECURITY
note: further information can be found at MSDN
| Code: |
#Persistent
OnExit, HandleExit
; note: event(s) can be present in any combination
FindFirstChangeNotification( "testdir", true, "FILE_NAME|DIR_NAME|ATTRIBUTES|SIZE|LAST_WRITE|SECURITY", handles, array_handles )
SetTimer, timer_DetectChange, 1000
return
HandleExit:
FindCloseChangeNotification( handles )
ExitApp
timer_DetectChange:
loop,
{
index := WaitForMultipleObjects( array_handles )
if ( index >= 1 and index <= 6 )
{
; note: index number correlates with order of event present during call
; to FindFirstChangeNotification
if ( index = 1 )
MsgBox, change has been detected: FILE_NAME
else if ( index = 2 )
MsgBox, change has been detected: DIR_NAME
else if ( index = 3 )
MsgBox, change has been detected: ATTRIBUTES
else if ( index = 4 )
MsgBox, change has been detected: SIZE
else if ( index = 5 )
MsgBox, change has been detected: LAST_WRITE
else if ( index = 6 )
MsgBox, change has been detected: SECURITY
FindNextChangeNotification( handles, index )
}
else
break
}
return
EncodeInteger( p_value, p_size, p_address, p_offset )
{
loop, %p_size%
DllCall( "RtlFillMemory"
, "uint", p_address+p_offset+A_Index-1
, "uint", 1
, "uchar", ( p_value >> ( 8*( A_Index-1 ) ) ) & 0xFF )
}
; return value: true = success, false = failure
FindFirstChangeNotification( p_path, p_recurse, p_events, byref r_handles, byref r_array_handles )
{
r_handles=
VarSetCapacity( r_array_handles, 25, 0 )
count = 0
loop, parse, p_events, |
{
count++
if ( A_LoopField = "FILE_NAME" )
event = 1
else if ( A_LoopField = "DIR_NAME" )
event = 2
else if ( A_LoopField = "ATTRIBUTES" )
event = 4
else if ( A_LoopField = "SIZE" )
event = 8
else if ( A_LoopField = "LAST_WRITE" )
event = 0x10
else if ( A_LoopField = "SECURITY" )
event = 0x100
h_notification := DllCall( "FindFirstChangeNotification", "str", p_path, "int", p_recurse, "uint", event )
if ( ErrorLevel or h_notification = -1 )
{
MsgBox, [FindFirstChangeNotification] failed: EL = %ErrorLevel% ~ h_notification = %h_notification%
return, false
}
r_handles = %r_handles%|%h_notification%
EncodeInteger( h_notification, 4, &r_array_handles, 1+( A_Index-1 )*4 )
}
r_handles = %r_handles%|
EncodeInteger( count, 1, &r_array_handles, 0 )
return, true
}
; return value: true = success, false = failure
FindNextChangeNotification( p_handles, p_index )
{
StringGetPos, ix, p_handles, |, L%p_index%
StringMid, handle, p_handles, ix+2, InStr( p_handles, "|", true, ix+2 )-( ix+2 )
return, DllCall( "FindNextChangeNotification", "uint", handle )
}
; return value: true = success, false = failure
FindCloseChangeNotification( p_handles )
{
StringMid, p_handles, p_handles, 2, StrLen( p_handles )-2
result := true
loop, parse, p_handles, |
result := result && DllCall( "FindCloseChangeNotification", "uint", A_LoopField )
return, result
}
; return value: [1,6], otherwise failure
WaitForMultipleObjects( byref r_array_handles )
{
result := DllCall( "WaitForMultipleObjects", "uint", *( &r_array_handles ), "uint", &r_array_handles+1, "int", false, "uint", 0 )
if ( result >= 0 and result < 6 )
return, result+1
else
return, result
}
|
Last edited by shimanov on Thu Jan 05, 2006 10:19 pm; edited 1 time in total |
|
| Back to top |
|
 |
Chris Site Admin
Joined: 02 Mar 2004 Posts: 10480
|
Posted: Thu Jan 05, 2006 1:31 pm Post subject: |
|
|
Something like this should probably be included in the standard library when that feature finally appears.
Thanks for your R&D and friendly implementation. |
|
| Back to top |
|
 |
not-logged-in-daonlyfreez Guest
|
Posted: Thu Jan 05, 2006 1:44 pm Post subject: |
|
|
Very nice!
Would it be possible to return not only a change, but also which files/folders changed and what change was detected on them? |
|
| Back to top |
|
 |
kapege.de
Joined: 07 Feb 2005 Posts: 188 Location: Munich, Germany
|
Posted: Thu Jan 05, 2006 5:35 pm Post subject: |
|
|
Fine work!
Buuuut: The polling is the main problem. To ask the drives every second for changes isn't the state of art. Sorry pal. Windows has an inbuilt function which broadcasts any changes of the file system. Sorrily I don't know much about the file system and DLL-calls, but it should be possible to intercept those messages and react.
(Sorry for the unwanted early sending) _________________ Peter
Wisenheiming for beginners: KaPeGe (German only, sorry) |
|
| Back to top |
|
 |
shimanov
Joined: 25 Sep 2005 Posts: 612
|
Posted: Thu Jan 05, 2006 6:02 pm Post subject: |
|
|
| Chris wrote: | | Thanks for your R&D and friendly implementation. |
Sure. Happy to contribute.
| daonlyfreez wrote: | | Would it be possible to return not only a change, but also which files/folders changed and what change was detected on them? |
There is another Windows function, ReadDirectoryChangesW, but it requires a callback function and is only present with Windows NT 4.0 and later. Otherwise, identification of changes will require a custom implementation. You may find useful information in another thread, Storing MD5 Hash in a Variable using DllCall().
| kapege.de wrote: | | ask the drives every second for changes |
I cannot say with absolute certainty, but I don't believe this is the method employed. It is more likely there is code in the path for file system access, which monitors for those changes configured by calling FindFirstChangeNotification. When an event matching that requested occurs, a flag is set and the invoking process will be notified. I used the WaitForMultipleObjects function precisely because it permits polling and can be used within AHk. Review RegisterWaitForSingleObject for a fully asynchronous method to receive notification. There are other methods, but they are outside the scope of this forum.
To verify my assertion, use File Monitor from Sysinternals, which captures file system access at a lower (driver) level. |
|
| Back to top |
|
 |
Laszlo
Joined: 14 Feb 2005 Posts: 4078 Location: Pittsburgh
|
Posted: Thu Jan 05, 2006 6:34 pm Post subject: |
|
|
| I get an error (h_notification = -1) in FindFirstChangeNotification. What does it mean? |
|
| Back to top |
|
 |
shimanov
Joined: 25 Sep 2005 Posts: 612
|
Posted: Thu Jan 05, 2006 7:34 pm Post subject: |
|
|
| Laszlo wrote: | | I get an error (h_notification = -1) in FindFirstChangeNotification. What does it mean? |
Have you verified that h_notification = -1 or ErrorLevel is non-zero? It would also help if you post the code used to call FindFirstChangeNotification.
| MSDN wrote: | | If the function fails, the return value is INVALID_HANDLE_VALUE = -1. To get extended error information, call GetLastError. |
Unfortunately, GetLastError does not return relevant information when called from AHk using DllCall. You can try the same calls from a native program (e.g., C program) to perform further diagnostics. |
|
| Back to top |
|
 |
Laszlo
Joined: 14 Feb 2005 Posts: 4078 Location: Pittsburgh
|
Posted: Tue Jan 10, 2006 12:07 am Post subject: |
|
|
| Laszlo wrote: | | I get an error (h_notification = -1) in FindFirstChangeNotification. What does it mean? | It meant, the directory "testdir" did not exist. My fault! When I changed it to "c:\t", which does exist, everything works! |
|
| Back to top |
|
 |
AHKnow
Joined: 03 Jul 2004 Posts: 118
|
Posted: Mon Mar 13, 2006 3:37 am Post subject: |
|
|
| Just seen this. Very nice. |
|
| Back to top |
|
 |
AHKnow* Guest
|
Posted: Tue Mar 14, 2006 8:42 pm Post subject: |
|
|
| not-logged-in-daonlyfreez wrote: | Very nice!
Would it be possible to return not only a change, but also which files/folders changed and what change was detected on them? |
I agree. Specific information is needed to make this script more useful. You need to know which files and what change. |
|
| Back to top |
|
 |
majkinetor
Joined: 24 May 2006 Posts: 3652 Location: Belgrade
|
Posted: Wed Sep 13, 2006 10:43 am Post subject: |
|
|
Nice. _________________
 |
|
| Back to top |
|
 |
Mystiq
Joined: 08 Jan 2007 Posts: 19
|
Posted: Fri May 18, 2007 1:13 pm Post subject: |
|
|
Is it possible to monitor multiple directories?
Ive checked the code but im not really sure, might be out of my expertise i think.
update:
Nevermind, i think i got it. Just awesome.  |
|
| Back to top |
|
 |
majkinetor
Joined: 24 May 2006 Posts: 3652 Location: Belgrade
|
Posted: Fri May 18, 2007 1:54 pm Post subject: |
|
|
y _________________
 |
|
| Back to top |
|
 |
Mystiq
Joined: 08 Jan 2007 Posts: 19
|
Posted: Fri May 18, 2007 7:50 pm Post subject: |
|
|
After lot of confusion ive managed to "wrap" these with new functions so that im easily able to monitor as many directories as i need but im wondering if its "recommended" to set up a lot of them?
Mainly im thinking of not using the recursive option so i can "limit" my search for the file(s) that have been added/changed. Basically, have directory and its subfolders all separate.
Any thoughts on this? |
|
| Back to top |
|
 |
Mystiq
Joined: 08 Jan 2007 Posts: 19
|
Posted: Sat May 19, 2007 1:02 pm Post subject: |
|
|
Desided not to use mutliple instances for each directory but theres one question.
Does this capture all the changes? What ive tested so far, these functions only capture up to two changes max. I mean that if i create two new files i get two file_name events. If i make more than two, it still gives only two file_name events. Is this normal?
edit:
Bit of searching i think found the answer. It seems that theres is a maximum of 2 per event. According to this website:
http://netez.com/2xExplorer/shellFAQ/bas_xplore.html |
|
| 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
|