DirMon.pas
上传用户:rickyhu
上传日期:2007-05-27
资源大小:842k
文件大小:10k
源码类别:

控制台编程

开发平台:

Delphi

  1. unit DirMon;
  2. interface
  3. uses
  4.    Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;
  5. type
  6.    // Exception's
  7.    EDirMonError = class(Exception);
  8.    // Changes in Files/Directories
  9.    //TFileChangedEvent = procedure( Sender: TObject; FileName: String) of Object;
  10.    TFileChangedEvent = procedure( StrInfo: String) of Object;
  11.    // Files/Directory - Renamed
  12.    //TFileRenamedEvent = procedure( Sender: TObject; fromFileName: String; toFileName: String) of Object;
  13.    TFileRenamedEvent = procedure( StrInfo: String) of Object;
  14.    // watch filters
  15.    TWatchFilter = (nfFILE_NAME,
  16.                   nfDIR_NAME,
  17.                   nfATTRIBUTES,
  18.                   nfSIZE,
  19.                   nfLAST_WRITE,
  20.                   nfLAST_ACCESS,
  21.                   nfCREATION,
  22.                   nfSECURITY);
  23.    TWatchFilters = set of TWatchFilter;
  24.    // The Directory Monitor
  25.    TDirMon = class(TComponent)
  26.    private
  27.       { Private-Deklarationen }
  28.       FDirectoryHandle: THandle;
  29.       FNotificationBuffer: array[0..4096] of Byte;
  30.       FWatchThread: TThread;
  31.       FWatchFilters: TWatchFilters;
  32.       FNotifyFilter: DWord;
  33.       FOverlapped: TOverlapped;
  34.       FPOverlapped: POverlapped;
  35.       FBytesWritten: DWORD;
  36.       FCompletionPort: THandle;
  37.       FPath: String;
  38.       FActive: Boolean;
  39.       FOnCreated: TFileChangedEvent;
  40.       FOnDeleted: TFileChangedEvent;
  41.       FOnModified: TFileChangedEvent;
  42.       FOnRenamed: TFileRenamedEvent;
  43.       FWatchSubTree: Boolean;
  44.       procedure SetActive( AActive: Boolean);
  45.       procedure SetPath(aPath: String);
  46.       procedure cmdCreated( Sender: TObject; FileName: String);
  47.       procedure cmdDeleted( Sender: TObject; FileName: String);
  48.       procedure cmdModified( Sender: TObject; FileName: String);
  49.       procedure cmdRenamed( Sender: TObject; fromFileName: String; toFileName: String);
  50.    protected
  51.       procedure Start;
  52.       procedure Stop;
  53.    public
  54.       { Public-Deklarationen }
  55.       { Protected-Deklarationen }
  56.       constructor Create(Aowner:TComponent);override;
  57.       destructor destroy; override;
  58.    published
  59.       { Published-Deklarationen }
  60.       property Active: Boolean read FActive write SetActive;
  61.       property Path: String read FPath write SetPath;
  62.       property OnCreated: TFileChangedEvent read FOnCreated write FOnCreated;
  63.       property OnDeleted: TFileChangedEvent read FOnDeleted write FOnDeleted;
  64.       property OnModified: TFileChangedEvent read FOnModified write FOnModified;
  65.       property OnRenamed: TFileRenamedEvent read FOnRenamed write FOnRenamed;
  66.       property WatchSubtree: Boolean read FWatchSubTree write FWatchSubtree;
  67.       property WatchFilters: TWatchfilters read FWatchFilters write FWatchFilters;
  68.    end;
  69. implementation
  70. uses
  71.    ShlObj, ActiveX, FileCtrl;
  72. type
  73.    // see windows API help
  74.    PFileNotifyInformation = ^TFileNotifyInformation;
  75.    TFileNotifyInformation = record
  76.       NextEntryOffset: DWORD;
  77.       Action: DWORD;
  78.       FileNameLength: DWORD;
  79.       FileName: array[0..0] of WideChar;
  80.    end;
  81. const
  82.    FILE_LIST_DIRECTORY   = $0001;
  83. type
  84.    TWaitThread = class(TThread)
  85.    private
  86.       FParent: TDirMon;
  87.       FRenamedFrom: String;
  88.       procedure HandleEvent;
  89.    protected
  90.       procedure Execute; override;
  91.    public
  92.       constructor Create(AParent: TDirMon);
  93.    end;
  94. ///////////////////////////////////////////////////////////////////////
  95. constructor TWaitThread.Create(AParent: TDirMon);
  96. begin
  97.    inherited Create(True);
  98.    FreeOnTerminate := False;
  99.    FParent := AParent;
  100. end;
  101. procedure TWaitThread.HandleEvent;
  102. var
  103.    FileOpNotification: PFileNotifyInformation;
  104.    Offset: Longint;
  105. begin
  106.    with FParent do
  107.    begin
  108.       Pointer(FileOpNotification) := @FNotificationBuffer[0];
  109.       repeat
  110.          Offset := FileOpNotification^.NextEntryOffset;
  111.          Case FileOpNotification^.Action of
  112.             1: cmdCreated( FParent, WideCharToString(@(FileOpNotification^.FileName)));
  113.             2: cmdDeleted( FParent, WideCharToString(@(FileOpNotification^.FileName)));
  114.             3: cmdModified( FParent, WideCharToString(@(FileOpNotification^.FileName)));
  115.             4: FRenamedFrom := WideCharToString(@(FileOpNotification^.FileName)); // Ausnahme
  116.             5: cmdRenamed( FParent, FRenamedFrom,WideCharToString(@(FileOpNotification^.FileName)));
  117.          end;
  118.          PChar(FileOpNotification) := PChar(FileOpNotification)+Offset;
  119.       until Offset=0;
  120.    end;
  121. end;
  122. procedure TWaitThread.Execute;
  123. var
  124.    numBytes: DWORD;
  125.    CompletionKey: DWORD;
  126. begin
  127.    while not Terminated do
  128.    begin
  129.      GetQueuedCompletionStatus( FParent.FCompletionPort, numBytes, CompletionKey, FParent.FPOverlapped, INFINITE);
  130.      if CompletionKey <> 0 then
  131.      begin
  132.         Synchronize(HandleEvent);
  133.         with FParent do
  134.         begin
  135.            FBytesWritten := 0;
  136.            ZeroMemory(@FNotificationBuffer, SizeOf(FNotificationBuffer));
  137.            ReadDirectoryChanges(FDirectoryHandle, @FNotificationBuffer, SizeOf(FNotificationBuffer), FParent.WatchSubtree , FNotifyFilter, @FBytesWritten, @FOverlapped, nil);
  138.         end;
  139.      end
  140.      else
  141.         Terminate;
  142.   end;
  143. end;
  144. constructor TDirMon.Create(Aowner:TComponent);
  145. begin
  146.   inherited Create(Aowner);
  147.   FCompletionPort := 0;
  148.   FDirectoryHandle := 0;
  149.   FPOverlapped := @FOverlapped;
  150.   ZeroMemory(@FOverlapped, SizeOf(FOverlapped));
  151.   FWatchFilters:=[nfFILE_NAME,nfDIR_NAME,nfLAST_WRITE,nfCREATION];
  152. end;
  153. destructor TDirMon.destroy;
  154. begin
  155.    if FActive then 
  156.       Stop;
  157.    inherited;
  158. end;
  159. procedure TDirMon.SetActive( AActive: Boolean);
  160. begin
  161.   if AActive Then
  162.      Start
  163.   else
  164.      Stop;
  165. end;
  166. procedure TDirMon.Start;
  167. begin
  168.    if FActive then Exit; // Don't start it again
  169.    FNotifyFilter := 0;   // Set MyFilterArray->DWord-Filter in ReadDirectoryChanges
  170.    if (nfFILE_NAME in FWatchFilters) then 
  171.       FNotifyFilter:=FNotifyFilter or FILE_NOTIFY_CHANGE_FILE_NAME;
  172.    if (nfDIR_NAME in FWatchFilters) then 
  173.       FNotifyFilter:=FNotifyFilter or FILE_NOTIFY_CHANGE_DIR_NAME;
  174.    if (nfATTRIBUTES in FWatchFilters) then 
  175.       FNotifyFilter:=FNotifyFilter or FILE_NOTIFY_CHANGE_ATTRIBUTES;
  176.    if (nfSIZE in FWatchFilters) then 
  177.       FNotifyFilter:=FNotifyFilter or FILE_NOTIFY_CHANGE_SIZE;
  178.    if (nfLAST_WRITE in FWatchFilters) then 
  179.       FNotifyFilter:=FNotifyFilter or FILE_NOTIFY_CHANGE_LAST_WRITE;
  180.    if (nfLAST_ACCESS in FWatchFilters) then 
  181.       FNotifyFilter:=FNotifyFilter or FILE_NOTIFY_CHANGE_LAST_ACCESS;
  182.    if (nfCREATION in FWatchFilters) then 
  183.       FNotifyFilter:=FNotifyFilter or FILE_NOTIFY_CHANGE_CREATION;
  184.    if (nfSECURITY in FWatchFilters) then 
  185.       FNotifyFilter:=FNotifyFilter or FILE_NOTIFY_CHANGE_SECURITY;
  186.    if FNotifyFilter = 0 then
  187.       exit;
  188.    FDirectoryHandle := CreateFile(PChar(FPath),
  189.       FILE_LIST_DIRECTORY,
  190.       FILE_SHARE_READ or FILE_SHARE_WRITE or FILE_SHARE_DELETE,
  191.       nil,
  192.       OPEN_EXISTING,
  193.       FILE_FLAG_BACKUP_SEMANTICS or FILE_FLAG_OVERLAPPED,
  194.       0);
  195.    if FDirectoryHandle = INVALID_HANDLE_VALUE then
  196.    begin
  197.       FDirectoryHandle := 0;
  198.       raise EDirMonError.Create(SysErrorMessage(GetLastError));
  199.       exit;
  200.    end;
  201.    FCompletionPort := CreateIoCompletionPort(FDirectoryHandle, 0, Longint(pointer(self)), 0);
  202.    ZeroMemory(@FNotificationBuffer, SizeOf(FNotificationBuffer));
  203.    FBytesWritten := 0;
  204.    if not ReadDirectoryChanges(FDirectoryHandle, @FNotificationBuffer, SizeOf(FNotificationBuffer), FWatchSubTree, FNotifyFilter, @FBytesWritten, @FOverlapped, nil) then
  205.    begin
  206.       CloseHandle(FDirectoryHandle);
  207.       FDirectoryHandle := 0;
  208.       CloseHandle(FCompletionPort);
  209.       FCompletionPort := 0;
  210.       raise EDirMonError.Create(SysErrorMessage(GetLastError));
  211.       exit;
  212.    end;
  213.    // The Thread is the Monitorig Thread
  214.    FWatchThread := TWaitThread.Create(self);
  215.    TWaitThread(FWatchThread).Resume;
  216.    FActive := True;
  217. end;
  218. procedure TDirMon.Stop;
  219. begin
  220.    if not FActive then Exit;
  221.    if FCompletionPort = 0 then
  222.       exit;
  223.    PostQueuedCompletionStatus(FCompletionPort, 0, 0, nil);
  224.    FWatchThread.WaitFor;
  225.    FWatchThread.Free;
  226.    CloseHandle(FDirectoryHandle);
  227.    FDirectoryHandle := 0;
  228.    CloseHandle(FCompletionPort);
  229.    FCompletionPort := 0;
  230.    FActive := False;
  231. end;
  232. procedure TDirMon.cmdCreated( Sender:TObject;FileName:String);
  233. var 
  234.    StrInfo: String;
  235. begin
  236.    if Assigned(FOnCreated) then
  237.    begin
  238.       StrInfo:='30|'
  239.          +Self.Path+FileName;
  240.       FOnCreated(StrInfo);
  241.    end
  242. end;
  243. procedure TDirMon.cmdDeleted(  Sender:TObject;FileName:String);
  244. var 
  245.    StrInfo: String;
  246. begin
  247.    if Assigned(FOnDeleted) then
  248.    begin
  249.       StrInfo:='31|'
  250.         +Self.Path+FileName;
  251.       FOnDeleted(StrInfo);
  252.    end;
  253. end;
  254. procedure TDirMon.cmdModified(  Sender:TObject;FileName:String);
  255. var 
  256.    StrInfo: String;
  257. begin
  258.    if Assigned(FOnModified) then
  259.    begin
  260.       StrInfo:='32|'
  261.          +Self.Path+FileName;
  262.       FOnModified(StrInfo);
  263.    end;
  264. end;
  265. procedure TDirMon.cmdRenamed( Sender: TObject; fromFileName: String; toFileName: String);
  266. var 
  267.    StrInfo: String;
  268. begin
  269.    if Assigned(FOnRenamed) then
  270.    begin
  271.       StrInfo:='33|'
  272.          +Self.Path+toFileName+'|'+fromFileName;
  273.       FOnRenamed(StrInfo);
  274.    end;
  275. end;
  276. procedure TDirMon.SetPath(aPath: String);
  277. {$IFNDEF VER130}
  278. function IncludeTrailingBackslash(const S: string): string;
  279. begin
  280.    if S[length(S)]='' then result:=S else result:=S+'';
  281. end;
  282. {$ENDIF}
  283. begin
  284.    if DirectoryExists(aPath) then
  285.       FPath:=IncludeTrailingBackslash(aPath);
  286.    if FActive then // When You do this at RunTime - We stop and start the Monitoring Process
  287.    begin
  288.       Stop;
  289.       start;
  290.    end;
  291. end;
  292. end.