views:

216

answers:

3

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?

+1  A: 

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.

RRUZ
+1  A: 

See this question. mghie's great answer provides what you are looking for.

Smasher
A: 

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.

megatr0n
Please use an indentation of 4 spaces for all your code or nobody will be able to read it.
Smasher
Why are you doing this in a thread and not in the main program? Maybe the main program shuts down before any change has been noticed. Also, what sets the 'terminated' variable?
No'am Newman