Detecting File/Directory Changes

blindwig
08-05-2003, 06:14 PM
It's been asked a couple of times, and I've been wondering myself, so I'm working on writing a module to answer the question "How can I tell if a file or directory (meaning any/all files in that directory) have been modified, without constantly looping and checking time/date stamps?"

I found this thread: How to Detect when a Directory has changed (http://www.visualbasicforum.com/showthread.php?t=25336) in the tutors corner, and using BillSoo's code as an example, I wrote this module:

Option Explicit

Private Const FCM_FLAGS_NAME = &H1
Private Const FCM_FLAGS_DIR_NAME = &H2
Private Const FCM_FLAGS_ATTRIBUTES = &H4
Private Const FCM_FLAGS_SIZE = &H8
Private Const FCM_FLAGS_LAST_WRITE = &H10
Private Const FCM_FLAGS_SECURITY = &H100
Private Const FCM_FLAGS_ALL = &H1 Or &H2 Or &H4 Or &H8 Or &H10 Or &H100

Private Declare Function FindFirstChangeNotification Lib "kernel32" _
Alias "FindFirstChangeNotificationA" (ByVal lpPathName As String, _
ByVal bWatchSubtree As Long, ByVal dwNotifyFilter As Long) As Long
Private Declare Function FindCloseChangeNotification Lib "kernel32" _
(ByVal hChangeHandle As Long) As Long
Private Declare Function FindNextChangeNotification Lib "kernel32" _
(ByVal hChangeHandle As Long) As Long
Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal _
hHandle As Long, ByVal dwMilliseconds As Long) As Long
Private Declare Function ResetEvent Lib "kernel32" (ByVal hEvent As _
Long) As Long

Public Type FileChangeMonitor
CheckSub As Boolean
Flags As Long
Hook As Long
Path As String
End Type

Public Sub SetFileChangeMonitor(ByRef Monitor As FileChangeMonitor, _
ByVal TargetPath As String, Optional ByVal CheckSubDir As Boolean = _
True, Optional ByVal Flags = FCM_FLAGS_ALL)
With Monitor
If Not (.Hook = 0) Then
ClearFileChangeMonitor Monitor
End If
.CheckSub = CheckSubDir
.Flags = Flags
.Path = TargetPath
.Hook = FindFirstChangeNotification(.Path, .CheckSub, .Flags)
End With
End Sub

Public Function CheckFileChangeMonitor(ByRef Monitor As _
FileChangeMonitor)
Dim fcmTemp As FileChangeMonitor
fcmTemp = Monitor
If Not (Monitor.Hook = 0) Then
'Not sure about the returns, but 0 seems to indicate a change
If (WaitForSingleObject(Monitor.Hook, 0) = 0) Then
CheckFileChangeMonitor = True
ClearFileChangeMonitor Monitor
SetFileChangeMonitor Monitor, fcmTemp.Path, _
fcmTemp.CheckSub, fcmTemp.Flags
Else
CheckFileChangeMonitor = False
End If
End If
End Function

Public Sub ClearFileChangeMonitor(ByRef Monitor As FileChangeMonitor)
With Monitor
If Not (.Hook = 0) Then
FindCloseChangeNotification .Hook 'Clear the hook
.Path = vbNullString
.Flags = 0
.CheckSub = False
.Hook = 0
End If
End With
End Sub

Public Function WaitFileChangeMonitor(ByRef Monitor As _
FileChangeMonitor, Optional ByVal TimeOut As Long = -1)
Dim fcmTemp As FileChangeMonitor

'Backup the file monitor
fcmTemp = Monitor

If Not (Monitor.Hook = 0) Then

'Wait for the event
WaitFileChangeMonitor = WaitForSingleObject(Monitor.Hook, _
TimeOut)

'Reset the file monitor hook
ClearFileChangeMonitor Monitor
SetFileChangeMonitor Monitor, fcmTemp.Path, _
fcmTemp.CheckSub, fcmTemp.Flags

End If
End Function

You can use it like this:

Dim MyFileMonitor as FileChangeMonitor
SetFileChangeMonitor MyFileMonitor, "C:\MyPath"

'Do some stuff

'Check to see if a file has changed in the meantime
If CheckFileChangeMonitor(MyFileMonitor) then
'do something else here
end if

'Wait for another file to change
WaitFileChange(MyFileMonitor)

'Do some more stuff

'clean up when done
ClearFileChangeMonitor MyFileMonitor

The next thing I want to figure out how to do is how do I create my own event? Like if I wanted to make it so that when a file is changed, a message is send to my program to trigger a sub being run - Do I need to create my own control for that?

EZ Archive Ads Plugin for vBulletin Copyright 2006 Computer Help Forum