I have very limited knowledge of using C Builder, could you give me an example or point me to tutorial showing how to use FindNextChangeNotification in Delphi or ,if it is possible, how to use the C component in delphi?
One option is use the TJvChangeNotify component, The JVCL support Delphi and C++ Builder.
Another option is use the SHChangeNotifyRegister function. see this link Monitoring System Shell Changes using Delphi
Bye.
The ReadDirectoryChanges seems to be the function that I am looking for. Here is my attempt using mghie's code http://stackoverflow.com/questions/863135/why-does-readdirectorychangesw-omit-events
My objective here is to monitor the directory/path or file you will see in Unit1. I just want a simple showmessage dialogue to popup whenever a change at the location is detected. I can't find where I am supposed to pass my notification procedure or fuction. Unit2 just holds the unchanged code from mghie. When I compile this project and make a simple change in the directory nothing happens. I am using the ReadDirectoryChanges correctly?
here is unit1
unit Unit1;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, Unit2;
type TForm1 = class(TForm) Button1: TButton; Button2: TButton; procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure Button1Click(Sender: TObject); private { Private declarations } public { Public declarations } end;
var Form1: TForm1; fthread:TWatcherthread;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject); begin //start directory or file watch here end;
procedure TForm1.FormCreate(Sender: TObject); begin fThread := TWatcherThread.Create('C:\Users\abe\Desktop\statcious\mitsu\Demo\abc.txt');
end;
procedure TForm1.FormDestroy(Sender: TObject); begin if fThread <> nil then begin TWatcherThread(fThread).Shutdown; fThread.Free; end; end;
end.
Here is unit2 unit Unit2;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs;
type TWatcherThread = class(TThread) private fChangeHandle: THandle; fDirHandle: THandle; fShutdownHandle: THandle; protected procedure Execute; override; public constructor Create(ADirectoryToWatch: string); destructor Destroy; override;
procedure Shutdown;
end;
type TForm2 = class(TForm) private { Private declarations } public { Public declarations } end;
var Form2: TForm2;
implementation
{$R *.dfm}
constructor TWatcherThread.Create(ADirectoryToWatch: string); const FILE_LIST_DIRECTORY = 1; begin inherited Create(TRUE); fChangeHandle := CreateEvent(nil, FALSE, FALSE, nil); fDirHandle := CreateFile(PChar(ADirectoryToWatch), FILE_LIST_DIRECTORY or GENERIC_READ, FILE_SHARE_READ or FILE_SHARE_WRITE or FILE_SHARE_DELETE, nil, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS or FILE_FLAG_OVERLAPPED, 0); fShutdownHandle := CreateEvent(nil, FALSE, FALSE, nil); Resume; end;
destructor TWatcherThread.Destroy; begin if fDirHandle <> INVALID_HANDLE_VALUE then CloseHandle(fDirHandle); if fChangeHandle <> 0 then CloseHandle(fChangeHandle); if fShutdownHandle <> 0 then CloseHandle(fShutdownHandle); inherited Destroy; end;
procedure TWatcherThread.Execute; type PFileNotifyInformation = ^TFileNotifyInformation; TFileNotifyInformation = record NextEntryOffset: DWORD; Action: DWORD; FileNameLength: DWORD; FileName: WideChar; end; const BufferLength = 65536; var Filter, BytesRead: DWORD; InfoPointer: PFileNotifyInformation; Offset, NextOffset: DWORD; Buffer: array[0..BufferLength - 1] of byte; Overlap: TOverlapped; Events: array[0..1] of THandle; WaitResult: DWORD; FileName, s: string; begin if fDirHandle <> INVALID_HANDLE_VALUE then begin Filter := FILE_NOTIFY_CHANGE_FILE_NAME or FILE_NOTIFY_CHANGE_DIR_NAME or FILE_NOTIFY_CHANGE_SIZE or FILE_NOTIFY_CHANGE_LAST_WRITE;
FillChar(Overlap, SizeOf(TOverlapped), 0);
Overlap.hEvent := fChangeHandle;
Events[0] := fChangeHandle;
Events[1] := fShutdownHandle;
while not Terminated do begin
if ReadDirectoryChangesW (fDirHandle, @Buffer[0], BufferLength, TRUE,
Filter, @BytesRead, @Overlap, nil)
then begin
WaitResult := WaitForMultipleObjects(2, @Events[0], FALSE, INFINITE);
if WaitResult = WAIT_OBJECT_0 then begin
InfoPointer := @Buffer[0];
Offset := 0;
repeat
NextOffset := InfoPointer.NextEntryOffset;
FileName := WideCharLenToString(@InfoPointer.FileName,
InfoPointer.FileNameLength);
SetLength(FileName, StrLen(PChar(FileName)));
s := Format('[%d] Action: %.8xh, File: "%s"',
[Offset, InfoPointer.Action, FileName]);
OutputDebugString(PChar(s));
PByte(InfoPointer) := PByte(DWORD(InfoPointer) + NextOffset);
Offset := Offset + NextOffset;
until NextOffset = 0;
end;
end;
end;
end; end;
procedure TWatcherThread.Shutdown; begin Terminate; if fShutdownHandle <> 0 then SetEvent(fShutdownHandle); end;
////////////////////////////////////////////////////////////////////////////////
end.