| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253 | 
							- unit DirectoryMonitor;
 
- // Based on DirMon by phaeteon and LoLa
 
- interface
 
- uses
 
-   Windows, Messages, SysUtils, Classes, CompThread;
 
- type
 
-   EDirectoryMonitorError = class(Exception);
 
-   TFileChangedEvent = procedure(Sender: TObject; const FileName: string) of Object;
 
-   TFileRenamedEvent = procedure(Sender: TObject; const FromFileName: string; const ToFileName: string) of Object;
 
-   TDirectoryMonitor = class(TComponent)
 
-   private
 
-     FDirectoryHandle: THandle;
 
-     FNotificationBuffer: array[0..4096] of Byte;
 
-     FWatchThread: TCompThread;
 
-     FWatchFilters: DWord;
 
-     FOverlapped: TOverlapped;
 
-     FPOverlapped: POverlapped;
 
-     FBytesWritten: DWORD;
 
-     FCompletionPort: THandle;
 
-     FPath: string;
 
-     FActive: Boolean;
 
-     FOnCreated: TFileChangedEvent;
 
-     FOnDeleted: TFileChangedEvent;
 
-     FOnModified: TFileChangedEvent;
 
-     FOnRenamed: TFileRenamedEvent;
 
-     FWatchSubTree: Boolean;
 
-     procedure SetActive(AActive: Boolean);
 
-     procedure SetPath(aPath: string);
 
-   protected
 
-     procedure Start;
 
-     procedure Stop;
 
-     procedure DoCreated(Sender: TObject; FileName: string);
 
-     procedure DoDeleted(Sender: TObject; FileName: string);
 
-     procedure DoModified(Sender: TObject; FileName: string);
 
-     procedure DoRenamed(Sender: TObject; FromFileName: string; ToFileName: string);
 
-   public
 
-     constructor Create(AOwner: TComponent); override;
 
-     destructor Destroy; override;
 
-   published
 
-     property Active: Boolean read FActive write SetActive;
 
-     property Path: string read FPath write SetPath;
 
-     property OnCreated: TFileChangedEvent read FOnCreated write FOnCreated;
 
-     property OnDeleted: TFileChangedEvent read FOnDeleted write FOnDeleted;
 
-     property OnModified: TFileChangedEvent read FOnModified write FOnModified;
 
-     property OnRenamed: TFileRenamedEvent read FOnRenamed write FOnRenamed;
 
-     property WatchSubtree: Boolean read FWatchSubTree write FWatchSubtree;
 
-     property WatchFilters: DWord read FWatchFilters write FWatchFilters;
 
-   end;
 
- implementation
 
- type
 
-   // See Windows API help
 
-   PFileNotifyInformation = ^TFileNotifyInformation;
 
-   TFileNotifyInformation = record
 
-     NextEntryOffset: DWord;
 
-     Action: DWord;
 
-     FileNameLength: DWord;
 
-     FileName: array[0..0] of WideChar;
 
-   end;
 
- const
 
-   FILE_LIST_DIRECTORY = $0001;
 
- type
 
-   TDirectoryMonitorThread = class(TCompThread)
 
-   private
 
-     FParent: TDirectoryMonitor;
 
-     FRenamedFrom: string;
 
-     procedure HandleEvent;
 
-   protected
 
-     procedure Execute; override;
 
-   public
 
-     constructor Create(AParent: TDirectoryMonitor);
 
-   end;
 
- constructor TDirectoryMonitorThread.Create(AParent: TDirectoryMonitor);
 
- begin
 
-   inherited Create(True);
 
-   FreeOnTerminate := False;
 
-   FParent := AParent;
 
- end;
 
- procedure TDirectoryMonitorThread.HandleEvent;
 
- var
 
-   FileOpNotification: PFileNotifyInformation;
 
-   Offset: DWord;
 
-   FileName: string;
 
- begin
 
-   FileOpNotification := PFileNotifyInformation(@FParent.FNotificationBuffer[0]);
 
-   repeat
 
-     Offset := FileOpNotification^.NextEntryOffset;
 
-     FileName := WideCharLenToString(@(FileOpNotification^.FileName), FileOpNotification^.FileNameLength div SizeOf(Char));
 
-     case FileOpNotification^.Action of
 
-       1: FParent.DoCreated(FParent, FileName);
 
-       2: FParent.DoDeleted(FParent, FileName);
 
-       3: FParent.DoModified(FParent, FileName);
 
-       4: FRenamedFrom := FileName;
 
-       5: FParent.DoRenamed(FParent, FRenamedFrom, FileName);
 
-     end;
 
-     FileOpNotification := PFileNotifyInformation(IntPtr(FileOpNotification) + IntPtr(Offset));
 
-   until (Offset = 0);
 
- end;
 
- procedure TDirectoryMonitorThread.Execute;
 
- var
 
-   NumBytes: DWord;
 
-   CompletionKey: ULONG_PTR;
 
- begin
 
-   while (not Terminated) do
 
-   begin
 
-     GetQueuedCompletionStatus(FParent.FCompletionPort, NumBytes, CompletionKey, FParent.FPOverlapped, INFINITE);
 
-     if CompletionKey <> 0 then
 
-     begin
 
-       Synchronize(HandleEvent);
 
-       with FParent do
 
-       begin
 
-         FBytesWritten := 0;
 
-         ZeroMemory(@FNotificationBuffer, SizeOf(FNotificationBuffer));
 
-         ReadDirectoryChanges(FDirectoryHandle, @FNotificationBuffer, SizeOf(FNotificationBuffer), FParent.WatchSubtree, WatchFilters, @FBytesWritten, @FOverlapped, nil);
 
-       end;
 
-     end
 
-       else
 
-     begin
 
-       Terminate;
 
-     end;
 
-   end;
 
- end;
 
- { TDirectoryMonitor }
 
- constructor TDirectoryMonitor.Create(AOwner: TComponent);
 
- begin
 
-   inherited;
 
-   FCompletionPort := 0;
 
-   FDirectoryHandle := 0;
 
-   FPOverlapped := @FOverlapped;
 
-   ZeroMemory(@FOverlapped, SizeOf(FOverlapped));
 
-   FWatchFilters := FILE_NOTIFY_CHANGE_FILE_NAME or FILE_NOTIFY_CHANGE_DIR_NAME or FILE_NOTIFY_CHANGE_LAST_WRITE or FILE_NOTIFY_CHANGE_CREATION;
 
- end;
 
- destructor TDirectoryMonitor.Destroy;
 
- begin
 
-   if FActive then Stop;
 
-   inherited;
 
- end;
 
- procedure TDirectoryMonitor.SetActive(AActive: Boolean);
 
- begin
 
-   if csDesigning in ComponentState then Exit;
 
-   if AActive <> FActive then
 
-   begin
 
-     if AActive then Start
 
-       else Stop;
 
-   end;
 
- end;
 
- procedure TDirectoryMonitor.Start;
 
- begin
 
-   FDirectoryHandle :=
 
-     CreateFile(
 
-       PChar(FPath),
 
-       FILE_LIST_DIRECTORY,
 
-       FILE_SHARE_READ or FILE_SHARE_WRITE or FILE_SHARE_DELETE,
 
-       nil,
 
-       OPEN_EXISTING,
 
-       FILE_FLAG_BACKUP_SEMANTICS or FILE_FLAG_OVERLAPPED,
 
-       0);
 
-   if FDirectoryHandle = INVALID_HANDLE_VALUE then
 
-   begin
 
-     FDirectoryHandle := 0;
 
-     raise EDirectoryMonitorError.Create(SysErrorMessage(GetLastError));
 
-     exit;
 
-   end;
 
-   FCompletionPort := CreateIoCompletionPort(FDirectoryHandle, 0, LongInt(Pointer(Self)), 0);
 
-   ZeroMemory(@FNotificationBuffer, SizeOf(FNotificationBuffer));
 
-   FBytesWritten := 0;
 
-   if not ReadDirectoryChanges(FDirectoryHandle, @FNotificationBuffer, SizeOf(FNotificationBuffer), FWatchSubTree, WatchFilters, @FBytesWritten, @FOverlapped, nil) then
 
-   begin
 
-     CloseHandle(FDirectoryHandle);
 
-     FDirectoryHandle := 0;
 
-     CloseHandle(FCompletionPort);
 
-     FCompletionPort := 0;
 
-     raise EDirectoryMonitorError.Create(SysErrorMessage(GetLastError));
 
-     exit;
 
-   end;
 
-   FWatchThread := TDirectoryMonitorThread.Create(Self);
 
-   TDirectoryMonitorThread(FWatchThread).Resume;
 
-   FActive := True;
 
- end;
 
- procedure TDirectoryMonitor.Stop;
 
- begin
 
-   PostQueuedCompletionStatus(FCompletionPort, 0, 0, nil);
 
-   FWatchThread.WaitFor;
 
-   FWatchThread.Free;
 
-   CloseHandle(FDirectoryHandle);
 
-   FDirectoryHandle := 0;
 
-   CloseHandle(FCompletionPort);
 
-   FCompletionPort := 0;
 
-   FActive := False;
 
- end;
 
- procedure TDirectoryMonitor.DoCreated(Sender: TObject; FileName: string);
 
- begin
 
-   if Assigned(FOnCreated) then FOnCreated(Sender, FPath + FileName);
 
- end;
 
- procedure TDirectoryMonitor.DoDeleted(Sender: TObject; FileName: string);
 
- begin
 
-   if Assigned(FOnDeleted) then FOnDeleted(Sender, FPath + FileName);
 
- end;
 
- procedure TDirectoryMonitor.DoModified(Sender: TObject; FileName: string);
 
- begin
 
-   if Assigned(FOnModified) then FOnModified(Sender, FPath + FileName);
 
- end;
 
- procedure TDirectoryMonitor.DoRenamed(Sender: TObject; FromFileName: string; ToFileName: string);
 
- begin
 
-   if Assigned(FOnRenamed) then FOnRenamed(Sender, FPath + FromFileName, FPath + ToFileName);
 
- end;
 
- procedure TDirectoryMonitor.SetPath(APath: string);
 
- begin
 
-   APath := IncludeTrailingPathDelimiter(APath);
 
-   if APath <> FPath then
 
-   begin
 
-     FPath := APath;
 
-     if FActive then
 
-     begin
 
-       Stop;
 
-       Start;
 
-     end;
 
-   end;
 
- end;
 
- end.
 
 
  |