Problem with file notification handles...
Posted: Sat Aug 02, 2003 10:29 pm
OK, I'm trying to monitor a directory for changes -- files created, deleted, etc. This code (below) works if you're only monitoring one folder; however, if you try to monitor more than one, it fails with 'invalid file handle'. Try running it, and copy a file into C: (if you wait more than 10 seconds, the program ends, so be quick!). Now enable the extra AddNotifier lines (altering paths to suit your system) -- it fails.
The program basically creates a list of handles, then passes them (@mylist ()) to the API call WaitForMultipleObjects (), which says to pass an array of handles. As far as I'm aware, @mylist () should be compatible (it's just a block of memory containing 'long' handles, AFAIK), but it fails. Any ideas why?
The program basically creates a list of handles, then passes them (@mylist ()) to the API call WaitForMultipleObjects (), which says to pass an array of handles. As far as I'm aware, @mylist () should be compatible (it's just a block of memory containing 'long' handles, AFAIK), but it fails. Any ideas why?
Code: Select all
#WAIT_FAILED = $FFFFFFFF
#WAIT_OBJECT_0 = $0
#WAIT_ABANDONED = $80
#WAIT_TIMEOUT = $102
Structure Handles
notifier.l
EndStructure
Global HCount
NewList changes.Handles ()
Procedure AddNotifier (dir$, recursive)
If flags = 0
flags = #FILE_NOTIFY_CHANGE_FILE_NAME | #FILE_NOTIFY_CHANGE_DIR_NAME | #FILE_NOTIFY_CHANGE_LAST_WRITE
EndIf
handle = FindFirstChangeNotification_ (dir$, recursive, flags)
If handle <> #INVALID_HANDLE_VALUE
AddElement (changes ())
changes ()\notifier = handle
HCount = HCount + 1
EndIf
EndProcedure
Procedure DeleteAllNotifiers ()
While NextElement (changes ())
FindCloseChangeNotification_ (changes ()\notifier)
DeleteElement (changes ())
HCount = HCount - 1
SelectElement (changes (), LastElement (changes ()))
Wend
EndProcedure
;Procedure DeleteNotifier (handle)
; While NextElement (changes ())
; If changes ()\notifier = handle
; FindCloseChangeNotification_ (changes ()\notifier)
; DeleteElement (changes ())
; HCount = HCount - 1
; SelectElement (changes (), LastElement (changes ()))
; EndIf
; Wend
;EndProcedure
Procedure InitErrors (def)
SetLastError_ (def)
EndProcedure
; SHOWERROR (title$)
; Puts up a dialog box with last error message, only if an error
; has occurred. The title$ parameter appears in the title bar of
; the dialog box.
Procedure.s ShowError (title$)
error = GetLastError_ ()
If error
AllocateMemory (0, 255)
FormatMessage_ (#FORMAT_MESSAGE_FROM_SYSTEM, #NULL, error, 0, MemoryID (), 255, #NULL)
e$ = PeekS (MemoryID ())
FreeMemory (0)
MessageRequester (title$, e$, #MB_ICONWARNING) ; ProcedureReturn e$ ; Alternative to MessageRequester!
EndIf
EndProcedure
; T e s t . . .
InitErrors (0)
msg$ = "Copy something anywhere in C: after closing this requester! (Program"
msg$ + Chr (10) + " will end in 10 seconds if you do nothing, or 10 secs after last file operation.)"
msg$ + Chr (10) + "Then try enabling the following AddNotifier lines..."
MessageRequester ("Info", msg$, 0)
; UNCOMMENT THESE! CHANGE TO SUIT YOUR SYSTEM...
AddNotifier ("C:\", #TRUE)
;AddNotifier ("D:\", #TRUE)
;AddNotifier ("T:\", #TRUE)
ResetList (changes ())
While NextElement (changes ())
Debug "Watching " + Str (changes ()\notifier)
Wend
FirstElement (changes ())
Repeat
result = WaitForMultipleObjects_ (HCount, @changes (), #FALSE, 10000)
; Valid result! See WaitForMultipleObjects docs to explain bounds check!
If result => #WAIT_OBJECT_0 And result <= #WAIT_OBJECT_0 + HCount - 1
Debug "Change in monitored folders/sub-folders!"
; Reset the handle that caused the notification (again, see docs)...
notifier = #WAIT_OBJECT_0 - result
SelectElement (changes (), notifier)
FindNextChangeNotification_ (changes ()\notifier)
Else
; Result failed!
If result = #WAIT_FAILED
ShowError ("WaitForMultipleObjects result: #WAIT_FAILED") ; Handle invalid?!!
DeleteAllNotifiers ()
End
EndIf
EndIf
Until result = #WAIT_TIMEOUT ; Programs ends after 10 seconds...
DeleteAllNotifiers ()
End