下载了Oxygen Dir Watcher, 需要安装控件, 直接改成单元引用了
上代码:
O2DirSpy.pas
{====================================================================}
{ TOxygenDirectorySpy Component, v1.6 c 2000-2001 Oxygen Software }
{--------------------------------------------------------------------}
{ Written by Oleg Fyodorov, delphi@oxygensoftware.com }
{ http://www.oxygensoftware.com }
{====================================================================}
unit O2DirSpy;
interface
uses Classes, Controls, Windows, SysUtils, ShellApi, Dialogs, Messages, FileCtrl;
type
TDirectoryChangeType = (ctNone, ctAttributes, ctSize, ctCreationTime, ctLastModificationTime, ctLastAccessTime, ctLastTime, ctCreate, ctRemove);
TOxygenDirectorySpy = class;
TDirectoryChangeRecord = record
Directory : String;
FileFlag : Boolean; // When True, ChangeType applies to a file; False - ChangeType applies to Directory
Name : String; // Name of changed file/directory
OldTime, NewTime : TDateTime; // Significant only when ChangeType is one of ctCreationTime, ctLastModificationTime, ctLastAccessTime, ctLastTime
OldAttributes, NewAttributes : DWord; // Significant only when ChangeType is ctAttributes
OldSize, NewSize : DWord; // Significant only when ChangeType is ctSize
ChangeType : TDirectoryChangeType; // Describes a change type (creation, removing etc.)
end;
TSpySearchRec = record
Time: Integer;
Size: Integer;
Attr: Integer;
dwFileAttributes: DWORD;
ftCreationTime: TFileTime;
ftLastAccessTime: TFileTime;
ftLastWriteTime: TFileTime;
nFileSizeHigh: DWORD;
nFileSizeLow: DWORD;
end;
TFileData = class
private
FSearchRec : TSpySearchRec;
Name: TFileName;
FFound : Boolean;
public
constructor Create;
procedure Free;
end;
TFileDataList = class(TStringList)
private
function NewFileData(const FileName : String; sr : TSearchRec) : TFileData;
function GetFoundCount : Integer;
public
property FoundCount : Integer read GetFoundCount;
destructor Destroy; override;
function AddFileData(FileData : TFileData) : Integer;
function AddSearchRec(const Directory : String; sr : TSearchRec) : Integer;
procedure Delete(Index : Integer); override;
procedure Clear; override;
procedure SetFound(Value : Boolean);
end;
TReadDirChangesThread = class(TThread)
private
FOwner : TOxygenDirectorySpy;
FDirectories : TStringList;
FHandles : TList;
FChangeRecord : TDirectoryChangeRecord;
FFilesData,
FTempFilesData : TFileDataList;
pHandles : PWOHandleArray;
procedure ReleaseHandle;
procedure AllocateHandle;
procedure ReadDirectories(DestData : TFileDataList);
procedure CompareSearchRec(var srOld, srNew : TSpySearchRec);
protected
procedure Execute; override;
procedure Notify;
public
constructor Create(Owner : TOxygenDirectorySpy);
destructor Destroy; override;
procedure Reset;
end;
TChangeDirectoryEvent = procedure (Sender : TObject; ChangeRecord : TDirectoryChangeRecord) of object;
TOxygenDirectorySpy = class(TComponent)
private
FThread : TReadDirChangesThread;
FEnabled,
FWatchSubTree : Boolean;
FDirectories : TStrings;
FOnChangeDirectory : TChangeDirectoryEvent;
procedure SetEnabled(const Value : Boolean);
procedure CheckDirectories;
procedure SetDirectories(const Value : TStrings);
procedure SetWatchSubTree(const Value : Boolean);
protected
procedure DoChangeDirectory(ChangeRecord : TDirectoryChangeRecord);
published
property Enabled : Boolean read FEnabled write SetEnabled;
property Directories : TStrings read FDirectories write SetDirectories;
property WatchSubTree : Boolean read FWatchSubTree write SetWatchSubTree;
property OnChangeDirectory : TChangeDirectoryEvent read FOnChangeDirectory write FOnChangeDirectory;
public
constructor Create(AOwner : TComponent); override;
destructor Destroy; override;
end;
function ChangeRecord2String(ChangeRecord : TDirectoryChangeRecord) : String;
procedure Register;
implementation
function ChangeRecord2String(ChangeRecord : TDirectoryChangeRecord) : String;
var s : String;
begin
Result := 'No changes';
if ChangeRecord.FileFlag then s := 'File ' else s := 'Directory ';
s := s + '"' + ChangeRecord.Name + '"';
case ChangeRecord.ChangeType of
ctAttributes : Result := s + ' attributes are changed. Old: ' + IntToHex(ChangeRecord.OldAttributes,8) + ', New: ' + IntToHex(ChangeRecord.NewAttributes,8);
ctSize : Result := s + ' size is changed. Old: ' + IntToStr(ChangeRecord.OldSize) + ', New: ' + IntToStr(ChangeRecord.NewSize);
ctCreationTime : Result := s + ' creation time is changed. Old: ' + DateTimeToStr(ChangeRecord.OldTime) + ', New: ' + DateTimeToStr(ChangeRecord.NewTime);
ctLastModificationTime : Result := s + ' last modification time is changed. Old: ' + DateTimeToStr(ChangeRecord.OldTime) + ', New: ' + DateTimeToStr(ChangeRecord.NewTime);
ctLastAccessTime : Result := s + ' last access time is changed. Old: ' + DateTimeToStr(ChangeRecord.OldTime) + ', New: ' + DateTimeToStr(ChangeRecord.NewTime);
ctLastTime : Result := s + ' time is changed. Old: ' + DateTimeToStr(ChangeRecord.OldTime) + ', New: ' + DateTimeToStr(ChangeRecord.NewTime);
ctCreate : Result := s + ' is created';
ctRemove : Result := s + ' is deleted';
end;
end;
function SameSystemTime(Time1, Time2 : TSystemTime) : Boolean;
begin
Result := ((Time1.wYear = Time2.wYear) and (Time1.wMonth = Time2.wMonth) and (Time1.wDay = Time2.wDay) and (Time1.wHour = Time2.wHour) and (Time1.wMinute = Time2.wMinute) and (Time1.wSecond = Time2.wSecond) and (Time1.wMilliseconds = Time2.wMilliseconds));
end;
function ReplaceText(s, SourceText, DestText: String):String;
var st,res:string;
i:Integer;
begin
ReplaceText:='';
if ((s='') or (SourceText='')) then Exit;
st:=s;
res:='';
i:=Pos(SourceText,s);
while (i>0) do
begin
res:=res+Copy(st,1,i-1)+DestText;
Delete(st,1,(i+Length(SourceText)-1));
i:=Pos(SourceText,st);
end;
res:=res+st;
ReplaceText:=res;
end;
///
// TFileData
///
constructor TFileData.Create;
begin
inherited Create;
Name := '';
FillChar(FSearchRec,SizeOf(FSearchRec),0);
FFound := False;
end;
procedure TFileData.Free;
begin
Name := '';
//Finalize(FSearchRec);
inherited Free;
end;
///
// TFileDataList
///
destructor TFileDataList.Destroy;
begin
Clear;
inherited Destroy;;
end;
function TFileDataList.NewFileData(const FileName : String; sr : TSearchRec) : TFileData;
begin
Result := TFileData.Create;
Result.Name := FileName;
with Result.FSearchRec do begin
Time := sr.Time;
Size := sr.Size;
Attr := sr.Attr;
dwFileAttributes := sr.FindData.dwFileAttributes;
ftCreationTime := sr.FindData.ftCreationTime;
ftLastAccessTime := sr.FindData.ftLastAccessTime;
ftLastWriteTime := sr.FindData.ftLastWriteTime;
nFileSizeHigh := sr.FindData.nFileSizeHigh;
nFileSizeLow := sr.FindData.nFileSizeLow;
end;
end;
function TFileDataList.GetFoundCount : Integer;
var i : Integer;
begin
Result := 0;
for i := 1 to Count do if TFileData(Objects[i-1]).FFound then Inc(Result);
end;
function TFileDataList.AddFileData(FileData : TFileData) : Integer;
var fd : TFileData;
begin
fd := TFileData.Create;
fd.Name := FileData.Name;
fd.FSearchRec := FileData.FSearchRec;
Result := AddObject(fd.Name, fd);
end;
function TFileDataList.AddSearchRec(const Directory : String; sr : TSearchRec) : Integer;
var FileName : String;
begin
if (Directory <> '') then FileName := ReplaceText(Directory + '\' + sr.Name,'\\','\') else FileName := sr.Name;
Result := AddObject(FileName, NewFileData(FileName, sr));
end;
procedure TFileDataList.Delete(Index : Integer);
begin
TFileData(Objects[Index]).Free;
inherited Delete(Index);
end;
procedure TFileDataList.Clear;
begin
while (Count > 0) do Delete(0);
inherited Clear;
end;
procedure TFileDataList.SetFound(Value : Boolean);
var i : Integer;
begin
for i := 1 to Count do TFileData(Objects[i-1]).FFound := Value;
end;
function CompareMem(fpBlock1, fpBlock2: Pointer; Size: Cardinal): Boolean; assembler;
asm
PUSH ESI
PUSH EDI
MOV ESI,fpBlock1
MOV EDI,fpBlock2
MOV ECX,Size
MOV EDX,ECX
XOR EAX,EAX
AND EDX,3
SHR ECX,2
REPE CMPSD
JNE @@2
MOV ECX,EDX
REPE CMPSB
JNE @@2
@@1: INC EAX
@@2: POP EDI
POP ESI
end;
///
// TReadDirChangesThread
///
procedure TReadDirChangesThread.CompareSearchRec(var srOld, srNew : TSpySearchRec);
var tt,nt,ot : TSystemTime;
//sro,srn : TSpySearchRec;
begin
FChangeRecord.ChangeType := ctNone;
if CompareMem(@srOld,@srNew, SizeOf(TSpySearchRec)) then Exit;
if (srOld.Time <> srNew.Time) then begin
FChangeRecord.ChangeType := ctLastTime;
FChangeRecord.OldTime := FileDateToDateTime(srOld.Time);
FChangeRecord.NewTime := FileDateToDateTime(srNew.Time);
srOld.Time := srNew.Time;
Exit;
end
else if (srOld.Size <> srNew.Size) then begin
FChangeRecord.ChangeType := ctSize;
FChangeRecord.OldSize := srOld.Size;
FChangeRecord.NewSize := srNew.Size;
srOld.Size := srNew.Size;
Exit;
end
else if (srOld.Attr <> srNew.Attr) or (srOld.dwFileAttributes <> srNew.dwFileAttributes) then begin
FChangeRecord.ChangeType := ctAttributes;
FChangeRecord.OldAttributes := srOld.dwFileAttributes;
FChangeRecord.NewAttributes := srNew.dwFileAttributes;
srOld.dwFileAttributes := srNew.dwFileAttributes;
srOld.Attr := srNew.Attr;
Exit;
end
else begin
FileTimeToSystemTime(srNew.ftCreationTime,nt);
SystemTimeToTzSpecificLocalTime(nil,nt,tt);
nt := tt;
FileTimeToSystemTime(srOld.ftCreationTime,ot);
SystemTimeToTzSpecificLocalTime(nil,ot,tt);
ot := tt;
if not SameSystemTime(nt,ot) then begin
FChangeRecord.ChangeType := ctCreationTime;
FChangeRecord.OldTime := SystemTimeToDateTime(ot);
FChangeRecord.NewTime := SystemTimeToDateTime(nt);
srOld.ftCreationTime := srNew.ftCreationTime;
Exit;
end
else begin
FileTimeToSystemTime(srNew.ftLastAccessTime,nt);
SystemTimeToTzSpecificLocalTime(nil,nt,tt);
nt := tt;
FileTimeToSystemTime(srOld.ftLastAccessTime,ot);
SystemTimeToTzSpecificLocalTime(nil,ot,tt);
ot := tt;
if not SameSystemTime(nt,ot) then begin
FChangeRecord.ChangeType := ctLastAccessTime;
FChangeRecord.OldTime := SystemTimeToDateTime(ot);
FChangeRecord.NewTime := SystemTimeToDateTime(nt);
srOld.ftLastAccessTime := srNew.ftLastAccessTime;
Exit;
end
else begin
FileTimeToSystemTime(srNew.ftLastWriteTime,nt);
SystemTimeToTzSpecificLocalTime(nil,nt,tt);
nt := tt;
FileTimeToSystemTime(srOld.ftLastWriteTime,ot);
SystemTimeToTzSpecificLocalTime(nil,ot,tt);
ot := tt;
if not SameSystemTime(nt,ot) then begin
FChangeRecord.ChangeType := ctLastModificationTime;
FChangeRecord.OldTime := SystemTimeToDateTime(ot);
FChangeRecord.NewTime := SystemTimeToDateTime(nt);
srOld.ftLastWriteTime := srNew.ftLastWriteTime;
Exit;
end;
end;
end;
end;
end;
procedure TReadDirChangesThread.Execute;
var i, Index : Integer;
R : DWord;
fd : TFileData;
begin
while not Terminated do try
if (FDirectories.Count = 0) or (not FOwner.Enabled) then Sleep(0)
else begin
R := WaitForMultipleObjects(FHandles.Count,pHandles,False,200);
if (R < (WAIT_OBJECT_0 + DWord(FHandles.Count))) then begin
FillChar(FChangeRecord,SizeOf(FChangeRecord),0);
FFilesData.SetFound(False);
FTempFilesData.Clear;
ReadDirectories(FTempFilesData);
while (FTempFilesData.Count > 0) do begin
fd := TFileData(FTempFilesData.Objects[0]);
// New file/directory is created
if not FFilesData.Find(fd.Name,Index) then begin
Index := FFilesData.AddFileData(fd);
TFileData(FFilesData.Objects[Index]).FFound := True;
FChangeRecord.ChangeType := ctCreate;
FChangeRecord.Name := fd.Name;
FChangeRecord.FileFlag := ((fd.FSearchRec.Attr and faDirectory) = 0);
FChangeRecord.Directory := FDirectories[R - WAIT_OBJECT_0];
Synchronize(Notify);
end
else begin
// file/directory is modified
TFileData(FFilesData.Objects[Index]).FFound := True;
CompareSearchRec(TFileData(FFilesData.Objects[Index]).FSearchRec, fd.FSearchRec);
while (FChangeRecord.ChangeType <> ctNone) do begin
FChangeRecord.Name := fd.Name;
FChangeRecord.FileFlag := ((fd.FSearchRec.Attr and faDirectory) = 0);
FChangeRecord.Directory := FDirectories[R - WAIT_OBJECT_0];
Synchronize(Notify);
CompareSearchRec(TFileData(FFilesData.Objects[Index]).FSearchRec, fd.FSearchRec);
end;
end;
FTempFilesData.Delete(0);
end;
for i := FFilesData.Count downto 1 do if not TFileData(FFilesData.Objects[i-1]).FFound then begin
// file/directory is deleted
fd := TFileData(FFilesData.Objects[i-1]);
FChangeRecord.ChangeType := ctRemove;
FChangeRecord.Name := fd.Name;
FChangeRecord.FileFlag := ((fd.FSearchRec.Attr and faDirectory) = 0);
FChangeRecord.Directory := FDirectories[R - WAIT_OBJECT_0];
FFilesData.Delete(i-1);
Synchronize(Notify);
end;
FindNextChangeNotification(THandle(FHandles[R - WAIT_OBJECT_0]));
end;
end;
except end;
end;
procedure TReadDirChangesThread.Notify;
var cr : TDirectoryChangeRecord;
begin
cr := FChangeRecord;
if (cr.ChangeType <> ctNone) then FOwner.DoChangeDirectory(cr);
end;
constructor TReadDirChangesThread.Create(Owner : TOxygenDirectorySpy);
begin
inherited Create(True);
FOwner := Owner;
FHandles := TList.Create;
pHandles := nil;
FDirectories := TStringList.Create;
FDirectories.Sorted := True;
FDirectories.Duplicates := dupIgnore;
FreeOnTerminate := True;
FFilesData := TFileDataList.Create;
FFilesData.Sorted := True;
FFilesData.Duplicates := dupIgnore;
FTempFilesData := TFileDataList.Create;
FTempFilesData.Sorted := True;
FTempFilesData.Duplicates := dupIgnore;
//Reset;
end;
procedure TReadDirChangesThread.ReleaseHandle;
var i : Integer;
begin
if (pHandles <> nil) then FreeMem(pHandles,FHandles.Count * SizeOf(THandle));
pHandles := nil;
for i := 1 to FHandles.Count do if (THandle(FHandles[i-1]) <> INVALID_HANDLE_VALUE) then FindCloseChangeNotification(THandle(FHandles[i-1]));//CloseHandle(FHandle);
FHandles.Clear;
end;
destructor TReadDirChangesThread.Destroy;
begin
ReleaseHandle;
FHandles.Free;
FDirectories.Free;
FFilesData.Clear;
FFilesData.Free;
FTempFilesData.Clear;
FTempFilesData.Free;
inherited Destroy;
end;
procedure TReadDirChangesThread.AllocateHandle;
var i : Integer;
h : THandle;
begin
if (FOwner <> nil) then for i := 1 to FDirectories.Count do begin
h := FindFirstChangeNotification(PChar(FDirectories[i-1]), FOwner.WatchSubTree, FILE_NOTIFY_CHANGE_FILE_NAME +
FILE_NOTIFY_CHANGE_DIR_NAME + FILE_NOTIFY_CHANGE_ATTRIBUTES +
FILE_NOTIFY_CHANGE_SIZE + FILE_NOTIFY_CHANGE_LAST_WRITE);
{h := FindFirstChangeNotification(PChar(FDirectories[i-1]), FALSE, FILE_NOTIFY_CHANGE_FILE_NAME +
FILE_NOTIFY_CHANGE_DIR_NAME + FILE_NOTIFY_CHANGE_ATTRIBUTES +
FILE_NOTIFY_CHANGE_SIZE + FILE_NOTIFY_CHANGE_LAST_WRITE);}
if (h <> INVALID_HANDLE_VALUE) then FHandles.Add(Pointer(h)) else raise Exception.Create('Error allocating handle: #'+IntToStr(GetLastError));
end;
GetMem(pHandles,FHandles.Count * SizeOf(THandle));
for i := 1 to FHandles.Count do pHandles^[i-1] := THandle(FHandles[i-1]);
ReadDirectories(FFilesData);
end;
procedure TReadDirChangesThread.ReadDirectories(DestData : TFileDataList);
var i : Integer;
procedure AppendDirContents(const Directory : String);
var sr : TSearchRec;
s : String;
begin
if (Directory[Length(Directory)] <> '\') then s := Directory + '\*.*' else s := Directory + '*.*';
if (FindFirst(s,faAnyFile,sr) = 0) then begin
if (sr.Name <> '.') and (sr.Name <> '..') then begin
DestData.AddSearchRec(Directory,sr);
if ((sr.Attr and faDirectory) <> 0) and FOwner.WatchSubTree then AppendDirContents(Directory + '\' + sr.Name);
end;
while (FindNext(sr) = 0) do if (sr.Name <> '.') and (sr.Name <> '..') then begin
DestData.AddSearchRec(Directory,sr);
if ((sr.Attr and faDirectory) <> 0) and FOwner.WatchSubTree then AppendDirContents(Directory + '\' + sr.Name);
end;
FindClose(sr);
end;
end;
begin
for i := 1 to FDirectories.Count do AppendDirContents(FDirectories[i-1]);
end;
procedure TReadDirChangesThread.Reset;
begin
ReleaseHandle;
if (FDirectories.Count = 0) then Exit;
AllocateHandle;
if (FHandles.Count > 0) then Resume;
end;
/
// TOxygenDirectorySpy
/
constructor TOxygenDirectorySpy.Create(AOwner : TComponent);
begin
inherited Create(AOwner);
FEnabled := False;
FWatchSubTree := False;
FDirectories := TStringList.Create;
TStringList(FDirectories).Sorted := True;
TStringList(FDirectories).Duplicates := dupIgnore;
FOnChangeDirectory := nil;
FThread := nil;
{$IFDEF O2_SW}
if (MessageDlg('This version of TOxygenDirectorySpy is NOT REGISTERED. '+#13#10+
'Press Ok to visit http://www.oxygensoftware.com and register.',
mtWarning,[mbOk,mbCancel],0) = mrOk) then ShellExecute(0,'open','http://www.oxygensoftware.com',nil,nil,SW_SHOWNORMAL);
{$ENDIF}
end;
procedure TOxygenDirectorySpy.SetEnabled(const Value : Boolean);
begin
if (csDesigning in ComponentState) then Exit;
if (Value = FEnabled) then Exit;
CheckDirectories;
if (FDirectories.Count = 0) then FEnabled := False else FEnabled := Value;
if (Win32Platform = VER_PLATFORM_WIN32_WINDOWS) then FWatchSubTree := False;
if FEnabled then begin
FThread := TReadDirChangesThread.Create(Self);
FThread.FDirectories.Clear;
FThread.FDirectories.AddStrings(FDirectories);
FThread.Reset;
end
else if (FThread <> nil) then begin
FThread.Terminate;
FThread.WaitFor;
//TerminateThread(FThread.Handle,0);
FThread := nil;
end;
end;
procedure TOxygenDirectorySpy.CheckDirectories;
var i : Integer;
s : String;
begin
for i := FDirectories.Count downto 1 do begin
s := Trim(FDirectories[i-1]);
if (s = '') or (not DirectoryExists(s)) then FDirectories.Delete(i-1);
end;
while (FDirectories.Count > MAXIMUM_WAIT_OBJECTS) do FDirectories.Delete(FDirectories.Count - 1);
end;
procedure TOxygenDirectorySpy.SetDirectories(const Value : TStrings);
begin
FDirectories.Clear;
FDirectories.AddStrings(Value);
CheckDirectories;
if FEnabled then begin
SetEnabled(False);
SetEnabled(True);
end;
end;
procedure TOxygenDirectorySpy.SetWatchSubTree(const Value : Boolean);
begin
if (Win32Platform = VER_PLATFORM_WIN32_WINDOWS) then begin
FWatchSubTree := False;
Exit;
end;
if (FWatchSubTree = Value) then Exit;
FWatchSubTree := Value;
if FEnabled then begin
SetEnabled(False);
SetEnabled(True);
end;
end;
procedure TOxygenDirectorySpy.DoChangeDirectory(ChangeRecord : TDirectoryChangeRecord);
begin
if Assigned(FOnChangeDirectory) then FOnChangeDirectory(Self, ChangeRecord);
end;
destructor TOxygenDirectorySpy.Destroy;
begin
if (FThread <> nil) then begin
FThread.Terminate;
FThread.WaitFor;
//TerminateThread(FThread.Handle,0);
//FThread.Free;
FThread := nil;
end;
inherited Destroy;
end;
procedure Register;
begin
RegisterComponents('Oxygen', [TOxygenDirectorySpy]);
end;
end.
utMain.pas
unit utMain;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls, O2DirSpy, FileCtrl;
type
TMainForm = class(TForm)
lstChanges: TListBox;
pnl1: TPanel;
pnl2: TPanel;
pnl3: TPanel;
btnAdd: TButton;
btnRemove: TButton;
pnl4: TPanel;
lstDirectoriesListBox: TListBox;
pnl5: TPanel;
lbl1: TLabel;
chkWatchSubTree: TCheckBox;
procedure btnAddClick(Sender: TObject);
procedure btnRemoveClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure chkWatchSubTreeClick(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
OxygenDirectorySpy1: TOxygenDirectorySpy;
procedure OxygenDirectorySpy1ChangeDirectory(Sender: TObject;
ChangeRecord: TDirectoryChangeRecord);
{ Private declarations }
public
{ Public declarations }
end;
var
MainForm: TMainForm;
implementation
{$R *.dfm}
procedure TMainForm.btnAddClick(Sender: TObject);
var s : String;
begin
if not SelectDirectory(s, [sdAllowCreate, sdPerformCreate, sdPrompt],0) then Exit;
with OxygenDirectorySpy1 do begin
Enabled := False;
Directories.Add(s);
Enabled := True;
end;
with lstDirectoriesListBox do try
Items.Clear;
Items.AddStrings(OxygenDirectorySpy1.Directories);
ItemIndex := 0;
except end;
btnRemove.Enabled := True;
end;
procedure TMainForm.btnRemoveClick(Sender: TObject);
var
i : Integer;
begin
if (lstDirectoriesListBox.Items.Count = 0) then Exit;
i := lstDirectoriesListBox.ItemIndex;
if (i = -1) then Exit;
lstDirectoriesListBox.Items.Delete(i);
with OxygenDirectorySpy1 do begin
Enabled := False;
Directories.Delete(i);
if (Directories.Count > 0) then begin
Enabled := True;
lstDirectoriesListBox.ItemIndex := 0;
end;
end;
btnRemove.Enabled := (lstDirectoriesListBox.Items.Count > 0);
end;
procedure TMainForm.chkWatchSubTreeClick(Sender: TObject);
begin
OxygenDirectorySpy1.WatchSubTree := chkWatchSubTree.Checked;
end;
procedure TMainForm.FormCreate(Sender: TObject);
begin
OxygenDirectorySpy1 := TOxygenDirectorySpy.Create(Self);
OxygenDirectorySpy1.OnChangeDirectory := OxygenDirectorySpy1ChangeDirectory;
SendMessage(lstChanges.Handle,LB_SETHORIZONTALEXTENT,1000,0);
end;
procedure TMainForm.FormDestroy(Sender: TObject);
begin
OxygenDirectorySpy1.Free;
end;
procedure TMainForm.OxygenDirectorySpy1ChangeDirectory(Sender: TObject; ChangeRecord: TDirectoryChangeRecord);
begin
lstChanges.Items.Add(DateTimeToStr(SysUtils.Now) + ' ' + ChangeRecord2String(ChangeRecord));
with lstChanges do if (Items.Count > 0) then ItemIndex := Items.Count - 1;
end;
end.
MainForm (utMain.pas窗体文件)
object MainForm: TMainForm
Left = 0
Top = 0
Caption = 'MainForm'
ClientHeight = 388
ClientWidth = 485
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -12
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
OnCreate = FormCreate
OnDestroy = FormDestroy
PixelsPerInch = 106
TextHeight = 14
object lstChanges: TListBox
Left = 0
Top = 105
Width = 485
Height = 283
Align = alClient
ItemHeight = 14
TabOrder = 0
ExplicitLeft = -63
ExplicitWidth = 548
ExplicitHeight = 254
end
object pnl1: TPanel
Left = 0
Top = 0
Width = 485
Height = 105
Align = alTop
TabOrder = 1
ExplicitLeft = -63
ExplicitWidth = 548
object pnl2: TPanel
Left = 405
Top = 1
Width = 79
Height = 103
Align = alRight
BevelOuter = bvNone
TabOrder = 0
ExplicitLeft = 468
object pnl3: TPanel
Left = 4
Top = 0
Width = 75
Height = 103
Align = alRight
BevelOuter = bvNone
TabOrder = 0
object btnAdd: TButton
Left = 4
Top = 24
Width = 69
Height = 21
Caption = 'Add'
TabOrder = 0
OnClick = btnAddClick
end
object btnRemove: TButton
Left = 4
Top = 52
Width = 69
Height = 21
Caption = 'Remove'
Enabled = False
TabOrder = 1
OnClick = btnRemoveClick
end
end
end
object pnl4: TPanel
Left = 1
Top = 1
Width = 404
Height = 103
Align = alClient
BevelOuter = bvNone
TabOrder = 1
ExplicitWidth = 467
object lstDirectoriesListBox: TListBox
Left = 0
Top = 29
Width = 404
Height = 74
Align = alClient
ItemHeight = 14
TabOrder = 0
ExplicitWidth = 467
end
object pnl5: TPanel
Left = 0
Top = 0
Width = 404
Height = 29
Align = alTop
BevelOuter = bvNone
TabOrder = 1
ExplicitWidth = 467
object lbl1: TLabel
Left = 5
Top = 8
Width = 115
Height = 14
Caption = 'Directories to watch:'
end
object chkWatchSubTree: TCheckBox
Left = 220
Top = 4
Width = 125
Height = 17
Caption = 'Watch subdirectories'
Checked = True
State = cbChecked
TabOrder = 0
OnClick = chkWatchSubTreeClick
end
end
end
end
end