In an effort to make ReadDirectoryChangesW less of a mystery, this article will briefly explain the ReadDirectoryChangesW function, present a class for Delphi that encapsulates the ReadDirectoryChangesW function and provide an example program that shows how to use the class to monitor a directory for updates, deletes or renames of files in the directory.
(Note : All code in this article has been tested with Delphi 6 and 7, but I can’t think of any reason it won’t work with Delphi 4 or 5 if you declare the function prototype yourself. Delphi 8 is a pure .NET environment, so if you are using Delphi 8 use the FileSystemWatcher class.)
The ReadDirectoryChangesW Function.
At the heart of the class lies the ReadDirectoryChangesW function. The function monitors a directory and alerts the caller when certain events occur. It is important to note that the ReadDirectoryChangesW function will only work on Windows NT, 2000 and XP. The function will not work on any other version of Windows. The ReadDirectoryChangesW function is defined in the Windows.pas unit in Delphi as :
function ReadDirectoryChangesW(hDirectory: THandle; lpBuffer: Pointer; nBufferLength: DWORD; bWatchSubtree: Bool; dwNotifyFilter: DWORD; lpBytesReturned: LPDWORD; lpOverlapped: POverlapped; lpCompletionRoutine: FARPROC): BOOL; stdcall;
Lets examine the parameters of ReadDirectoryChangesW and look at how the function is called.
hDirectory is the handle of the directory to be watched. This handle is obtained by calling the CreateFile function with the FILE_LIST_DIRECTORY flag.
lpBuffer parameter is a pointer to a list of
File_Notify_Information records. The Delphi definition of
File_Notify_Information is shown in Figure 1. The
File_Notify_Information record contains four fields. The first is
NextEntryOffset. This field contains the number of bytes to the next record. A value of zero indicates the last record in the list. The second field is the
Action field. The action field holds a value that describes the type of change that occurred. The possible values for this field are described in Figure 2. The third field is
FileNameLength. The FileNameLength is the length of the filename in bytes (not chars). This field does not include the null terminating character. The last field in the
File_Notify_Information record is
FileName. This contains the name of the file that was effected. There is no null terminator, and it is unspecified if the field will have the long or short filename, but during all of my testing it always had the long filename.
TFileNotifyInformation = Record NextEntryOffset : DWORD; Action : DWORD; FileNameLength : DWORD; FileName : Array[0..MAX_PATH] OfWCHAR; end; PFileNotifyInformation = ^TFileNotifyInformation;
Figure 1 - The