📄 jvchangenotify.pas
字号:
begin
Result := TJvChangeItem(inherited GetItem(Index));
end;
procedure TJvChangeItems.SetItem(Index: Integer; Value: TJvChangeItem);
begin
inherited SetItem(Index, Value);
end;
function TJvChangeItems.GetOwner: TPersistent;
begin
Result := FOwner;
end;
procedure TJvChangeItems.Assign(Source: TPersistent);
var
I: Integer;
begin
if Source is TJvChangeItems then
begin
Clear;
for I := 0 to TJvChangeItems(Source).Count - 1 do
Add.Assign(TJvChangeItems(Source)[I]);
end
else
inherited Assign(Source);
end;
//=== { TJvChangeNotify } ====================================================
constructor TJvChangeNotify.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FCollection := TJvChangeItems.Create(Self);
FActive := False;
FInterval := 100;
FFreeOnTerminate := True;
end;
destructor TJvChangeNotify.Destroy;
begin
Active := False;
FCollection.Free;
inherited Destroy;
end;
procedure TJvChangeNotify.CheckActive(const Name: string);
begin
if Active and
not ((csDesigning in ComponentState) or (csLoading in ComponentState)) then //active is now published
raise EJVCLException.CreateResFmt(@RsEFmtCannotChangeName, [Name]);
end;
procedure TJvChangeNotify.SetCollection(const Value: TJvChangeItems);
begin
FCollection.Assign(Value);
end;
procedure TJvChangeNotify.Change(Item: TJvChangeItem);
begin
if Assigned(Item) then
begin
Item.Change;
if Assigned(FNotify) then
FNotify(Self, Item.Directory, Item.Actions);
end;
end;
procedure TJvChangeNotify.SetInterval(const Value: Integer);
begin
CheckActive('Interval');
if Value <= 0 then
Exit;
if FInterval <> Value then
FInterval := Value;
end;
function TJvChangeNotify.NotifyError(const Msg: string): string;
begin
SetLength(Result, 256);
SetLength(Result, FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, nil,
GetLastError, 0, PChar(Result), Length(Result), nil));
raise EJVCLException.CreateResFmt(@RsENotifyErrorFmt, [Result, Msg]);
end;
procedure TJvChangeNotify.DoThreadChangeNotify(Sender: TObject; Index: Integer);
begin
Change(Notifications[Index]);
end;
procedure TJvChangeNotify.DoThreadTerminate(Sender: TObject);
begin
if FreeOnTerminate then
FThread := nil;
end;
procedure TJvChangeNotify.SetActive(const Value: Boolean);
const
cActions: array [TJvChangeAction] of Cardinal =
(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_SECURITY);
var
cA: TJvChangeAction;
Flags: Cardinal;
I: Integer;
S: string;
begin
if (FActive <> Value) then
begin
FActive := Value;
if csDesigning in ComponentState then
Exit; //active is now published
if FActive then
begin
if FCollection.Count > MAXIMUM_WAIT_OBJECTS then
raise EJVCLException.CreateResFmt(@RsEFmtMaxCountExceeded,[MAXIMUM_WAIT_OBJECTS]);
FillChar(FNotifyArray, SizeOf(TJvNotifyArray), INVALID_HANDLE_VALUE);
for I := 0 to FCollection.Count - 1 do
begin
Flags := 0;
{ convert TJvChangeActions to bitfields }
for cA := Low(TJvChangeAction) to High(TJvChangeAction) do
if cA in FCollection[I].Actions then
Flags := Flags or (cActions[cA]);
S := FCollection[I].Directory;
if (Length(S) = 0) or not DirectoryExists(S) then
raise EJVCLException.CreateResFmt(@RsEFmtInvalidPathAtIndex, [S, I]);
FNotifyArray[I] := FindFirstChangeNotification(PChar(S),
BOOL(FCollection[I].IncludeSubTrees), Flags);
if FNotifyArray[I] = INVALID_HANDLE_VALUE then
NotifyError(FCollection[I].Directory);
end;
if FThread <> nil then
begin
FThread.Terminate;
if FreeOnTerminate then
FThread := nil
else
begin
FThread.WaitFor;
FreeAndNil(FThread);
end;
end;
FThread := TJvChangeThread.Create(FNotifyArray, FCollection.Count, FInterval, FFreeOnTerminate);
FThread.OnChangeNotify := DoThreadChangeNotify;
FThread.OnTerminate := DoThreadTerminate;
FThread.Resume;
end
else
if FThread <> nil then
begin
FThread.Terminate;
if FreeOnTerminate then
FThread := nil
else
begin
FThread.WaitFor;
FreeAndNil(FThread);
end;
end;
{
while FActive do
begin
I := WaitForMultipleObjects(FCollection.Count, @FNotifyArray, False, FInterval);
if (I >= 0) and (I < FCollection.Count) then
begin
try
Change(FCollection.Items[I]);
finally
Assert(FindNextChangeNotification(FNotifyArray[I]));
end;
end
else
Application.ProcessMessages;
end;
for I := 0 to FCollection.Count - 1 do // Iterate
FindCloseChangeNotification(FNotifyArray[I]);
}
end;
end;
procedure TJvChangeNotify.Loaded;
begin
inherited Loaded;
if FActive then
begin
FActive := False;
SetActive(True);
end;
end;
//=== { TJvChangeThread } ====================================================
constructor TJvChangeThread.Create(NotifyArray: TJvNotifyArray; Count, Interval: Integer; AFreeOnTerminate:Boolean);
var
I: Integer;
begin
inherited Create(True);
FCount := Count;
FInterval := Interval;
FillChar(FNotifyArray, SizeOf(TJvNotifyArray), INVALID_HANDLE_VALUE);
for I := 0 to FCount - 1 do
FNotifyArray[I] := NotifyArray[I];
FreeOnTerminate := AFreeOnTerminate;
end;
procedure TJvChangeThread.Execute;
var
I: Integer;
begin
// (rom) secure thread against exceptions (Delphi 5 needs it)
try
while not Terminated do
begin
I := WaitForMultipleObjects(FCount, @FNotifyArray[0], False, FInterval);
if (I >= 0) and (I < FCount) then
begin
try
FIndex := I;
Synchronize(SynchChange);
finally
// (rom) raising an exception in a thread is not a good idea
// (rom) Assert removed
//Assert(FindNextChangeNotification(FNotifyArray[I]));
FindNextChangeNotification(FNotifyArray[I]);
end;
end;
end;
if Terminated then
for I := 0 to FCount - 1 do
if FNotifyArray[I] <> INVALID_HANDLE_VALUE then
begin
FindCloseChangeNotification(FNotifyArray[I]);
FNotifyArray[I] := INVALID_HANDLE_VALUE;
end;
except
end;
end;
procedure TJvChangeThread.SynchChange;
begin
if Assigned(FNotify) then
FNotify(Self, FIndex);
end;
{$IFDEF UNITVERSIONING}
initialization
RegisterUnitVersion(HInstance, UnitVersioning);
finalization
UnregisterUnitVersion(HInstance);
{$ENDIF UNITVERSIONING}
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -