home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 2001 September
/
Chip_2001-09_cd1.bin
/
zkuste
/
delphi
/
kolekce
/
d6
/
RX275D6.ZIP
/
Units
/
RxNotify.pas
< prev
next >
Wrap
Pascal/Delphi Source File
|
1999-10-12
|
10KB
|
373 lines
{*******************************************************}
{ }
{ Delphi VCL Extensions (RX) }
{ }
{ Copyright (c) 1998 Master-Bank }
{ }
{*******************************************************}
unit RxNotify;
interface
{$I RX.INC}
{$IFDEF WIN32}
uses Windows, SysUtils, Classes, Messages, ExtCtrls;
type
TFileChangeFilter = (fnFileName, fnDirName, fnAttributes, fnSize,
fnLastWrite, fnLastAccess, fnCreation, fnSecurity);
TFileChangeFilters = set of TFileChangeFilter;
TNotifyThread = class;
{ TRxFolderMonitor }
TRxFolderMonitor = class(TComponent)
private
FNotifyThread: TNotifyThread;
FFilter: TFileChangeFilters;
FDelayTimer: TTimer;
FDelayTime: Cardinal;
FMonitorSubtree: Boolean;
FFolderName: string;
FStreamedActive: Boolean;
FOnChange: TNotifyEvent;
function GetActive: Boolean;
function GetDelayTime: Cardinal;
procedure SetActive(Value: Boolean);
procedure SetFilter(Value: TFileChangeFilters);
procedure SetMonitorSubtree(Value: Boolean);
procedure SetFolderName(const Value: string);
procedure SetDelayTime(Value: Cardinal);
procedure Timer(Sender: TObject);
procedure ThreadNotification(Sender: TObject);
protected
procedure Loaded; override;
procedure Changed; dynamic;
procedure FreeNotifyThread;
procedure ResetNotifyThread(Activate: Boolean); virtual;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
published
property Active: Boolean read GetActive write SetActive default False;
property DelayTime: Cardinal read GetDelayTime write SetDelayTime default 0;
property Filter: TFileChangeFilters read FFilter write SetFilter
default [fnFileName, fnDirName, fnSize, fnLastWrite];
property FolderName: string read FFolderName write SetFolderName;
property MonitorSubtree: Boolean read FMonitorSubtree write SetMonitorSubtree
default True;
property OnChange: TNotifyEvent read FOnChange write FOnChange;
end;
{ TNotifyThread }
TNotifyThread = class(TThread)
private
FNotifyHandle: THandle;
FEvent: THandle;
FOnChange: TNotifyEvent;
FFinished: Boolean;
FLastError: DWORD;
procedure CallOnChange;
procedure StopWaiting;
protected
procedure DoChange; virtual;
procedure DoTerminate; override;
procedure Execute; override;
public
constructor Create(const FolderName: string; WatchSubtree: Boolean;
Filter: TFileChangeFilters);
destructor Destroy; override;
procedure Terminate;
property Terminated;
property Finished: Boolean read FFinished;
property LastError: DWORD read FLastError;
property NotifyHandle: THandle read FNotifyHandle;
property OnChange: TNotifyEvent read FOnChange write FOnChange;
end;
function CreateNotifyThread(const FolderName: string; WatchSubtree: Boolean;
Filter: TFileChangeFilters): TNotifyThread;
{$ENDIF WIN32}
implementation
{$IFDEF WIN32}
uses Forms, VCLUtils, FileUtil;
{$IFNDEF RX_D3}
const
FILE_NOTIFY_CHANGE_LAST_ACCESS = $00000020;
FILE_NOTIFY_CHANGE_CREATION = $00000040;
{$ENDIF}
{ TNotifyThread }
constructor TNotifyThread.Create(const FolderName: string;
WatchSubtree: Boolean; Filter: TFileChangeFilters);
const
NotifyFilters: array[TFileChangeFilter] of DWORD = (
FILE_NOTIFY_CHANGE_FILE_NAME, FILE_NOTIFY_CHANGE_DIR_NAME,
FILE_NOTIFY_CHANGE_ATTRIBUTES, FILE_NOTIFY_CHANGE_SIZE,
FILE_NOTIFY_CHANGE_LAST_WRITE, FILE_NOTIFY_CHANGE_LAST_ACCESS,
FILE_NOTIFY_CHANGE_CREATION, FILE_NOTIFY_CHANGE_SECURITY);
var
Filters: DWORD;
I: TFileChangeFilter;
Subtree: Integer;
begin
FLastError := ERROR_SUCCESS;
Filters := 0;
for I := Low(TFileChangeFilter) to High(TFileChangeFilter) do
if I in Filter then Filters := Filters or NotifyFilters[I];
if WatchSubtree then Subtree := 1 else Subtree := 0;
FNotifyHandle := FindFirstChangeNotification(PChar(FolderName),
Bool(Subtree), Filters);
if FNotifyHandle <> INVALID_HANDLE_VALUE then
FEvent := CreateEvent(nil, BOOL(1), BOOL(0), nil)
else FLastError := GetLastError;
inherited Create(False);
end;
destructor TNotifyThread.Destroy;
begin
FOnChange := nil;
StopWaiting;
inherited Destroy;
end;
procedure TNotifyThread.Terminate;
begin
inherited Terminate;
StopWaiting;
end;
procedure TNotifyThread.CallOnChange;
begin
if Assigned(FOnChange) then FOnChange(Self);
end;
procedure TNotifyThread.DoChange;
begin
if Assigned(FOnChange) then Synchronize(CallOnChange);
end;
procedure TNotifyThread.DoTerminate;
begin
if FNotifyHandle <> INVALID_HANDLE_VALUE then
FindCloseChangeNotification(FNotifyHandle);
FNotifyHandle := INVALID_HANDLE_VALUE;
if FEvent <> 0 then CloseHandle(FEvent);
FEvent := 0;
inherited DoTerminate;
end;
procedure TNotifyThread.Execute;
var
Handles: array[0..1] of THandle;
begin
while not Terminated and (FNotifyHandle <> INVALID_HANDLE_VALUE) do
begin
Handles[0] := FNotifyHandle;
Handles[1] := FEvent;
case WaitForMultipleObjects(2, PWOHandleArray(@Handles), False, INFINITE) of
WAIT_OBJECT_0: { notification }
if not Terminated then begin
DoChange;
if not FindNextChangeNotification(FNotifyHandle) then begin
FLastError := GetLastError;
Break;
end;
end;
WAIT_OBJECT_0 + 1: { event is signaled }
Break;
WAIT_FAILED:
begin
FLastError := GetLastError;
Break;
end;
end;
end;
FFinished := True;
end;
procedure TNotifyThread.StopWaiting;
begin
if FEvent <> 0 then SetEvent(FEvent);
end;
function CreateNotifyThread(const FolderName: string; WatchSubtree: Boolean;
Filter: TFileChangeFilters): TNotifyThread;
begin
Result := TNotifyThread.Create(FolderName, WatchSubtree, Filter);
try
if Result.LastError <> ERROR_SUCCESS then
RaiseWin32Error(Result.LastError);
except
Result.Free;
raise;
end;
end;
{ TRxFolderMonitor }
constructor TRxFolderMonitor.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FFilter := [fnFileName, fnDirName, fnSize, fnLastWrite];
FMonitorSubtree := True;
end;
destructor TRxFolderMonitor.Destroy;
begin
if FDelayTimer <> nil then
FDelayTimer.OnTimer := nil;
FreeNotifyThread;
FDelayTimer.Free;
inherited Destroy;
end;
procedure TRxFolderMonitor.Loaded;
begin
inherited Loaded;
try
if FStreamedActive then Active := True;
except
if csDesigning in ComponentState then
Application.HandleException(Self)
else raise;
end;
end;
function TRxFolderMonitor.GetActive: Boolean;
begin
Result := FNotifyThread <> nil;
end;
procedure TRxFolderMonitor.SetActive(Value: Boolean);
begin
if (csReading in ComponentState) then begin
if Value then FStreamedActive := True;
end
else if Active <> Value then begin
ResetNotifyThread(Value);
end;
end;
procedure TRxFolderMonitor.SetFilter(Value: TFileChangeFilters);
var
SaveFilter: TFileChangeFilters;
IsActive: Boolean;
begin
if FFilter <> Value then begin
SaveFilter := FFilter;
IsActive := Active;
FFilter := Value;
try
ResetNotifyThread(IsActive);
except
FFilter := SaveFilter;
if IsActive then
try
ResetNotifyThread(True);
except
end;
raise;
end;
end;
end;
procedure TRxFolderMonitor.SetMonitorSubtree(Value: Boolean);
begin
if FMonitorSubtree <> Value then begin
FMonitorSubtree := Value;
ResetNotifyThread(Active);
end;
end;
procedure TRxFolderMonitor.SetFolderName(const Value: string);
begin
if FFolderName <> Value then begin
FFolderName := Value;
ResetNotifyThread(Active);
end;
end;
procedure TRxFolderMonitor.FreeNotifyThread;
begin
if FNotifyThread <> nil then
with FNotifyThread do begin
OnChange := nil;
if FFinished then Free
else begin
FreeOnTerminate := True;
Terminate;
end;
end;
FNotifyThread := nil;
end;
procedure TRxFolderMonitor.ResetNotifyThread(Activate: Boolean);
begin
FreeNotifyThread;
if Activate and DirExists(FFolderName) then begin
FNotifyThread := CreateNotifyThread(FolderName, MonitorSubtree, Filter);
FNotifyThread.OnChange := ThreadNotification;
end;
end;
function TRxFolderMonitor.GetDelayTime: Cardinal;
begin
if FDelayTimer <> nil then
Result := FDelayTimer.Interval
else Result := FDelayTime;
end;
procedure TRxFolderMonitor.SetDelayTime(Value: Cardinal);
begin
if (FDelayTimer <> nil) then begin
if Value > 0 then
FDelayTimer.Interval := Value
else begin
FDelayTimer.OnTimer := nil;
FDelayTimer.Free;
FDelayTimer := nil;
end;
end;
FDelayTime := Value;
end;
procedure TRxFolderMonitor.ThreadNotification(Sender: TObject);
begin
if FDelayTime <= 0 then
Changed
else if FDelayTimer = nil then begin
FDelayTimer := TTimer.Create(Self);
with FDelayTimer do begin
Interval := FDelayTime;
OnTimer := Timer;
Enabled := True;
end;
end;
end;
procedure TRxFolderMonitor.Timer(Sender: TObject);
begin
FDelayTimer.Free;
FDelayTimer := nil;
Changed;
end;
procedure TRxFolderMonitor.Changed;
begin
if Assigned(FOnChange) then FOnChange(Self);
end;
{$ENDIF WIN32}
end.