this slowpoke moves

Directory Sniffer

Wer seine Festplatte im Hintergrund überwachen möchte, um zu ermitteln, was Programme alles so anstellen, kann dieses Projekt dafür verwenden. 

Man benötigt eine EditBox, 2xButton und eine ListBox.

In die EditBox muss der Festplattenbuchstabe mit Doppelpunkt eingetragen werden, wie z. B. : "C:"

Der Sniffer ist schnell und belastet die Festplatte nur in geringen Maßen.



Datei DirSniffer.pas
{$I Directives.inc}

unit DirSniffer;

interface

{unit DirSniffer.pas}

uses
  Windows, SysUtils, Classes;

type
  TDirChangeNotifier = class;
  TDirChangeNotification = (dcnFileAdd, dcnFileRemove, dcnRenameFile,
   dcnRenameDir, dcnModified, dcnLastWrite, dcnLastAccess,
   dcnCreationTime);
  TDirChangeNotifications = set of TDirChangeNotification;
  TDirChangeEvent = procedure (Sender: TDirChangeNotifier;
   const FileName, OtherFileName: WideString;
   Action: TDirChangeNotification) of object;

  TDirChangeNotifier = class(TThread)
  private
    FDir: WideString;
    FDirHandle: THandle;
    FNotifList: TDirChangeNotifications;
    FTermEvent: THandle;
    FOverlapped: TOverlapped;
    FOnChange: TDirChangeEvent;
    FFileName: WideString;
    FOtherFileName: WideString;
    FAction: TDirChangeNotification;
  protected
    function WhichAttrChanged(const AFileName: WideString): TDirChangeNotification;
    procedure Execute; override;
    procedure DoChange;
  public
    constructor Create(const ADirectory: WideString;
     WantedNotifications: TDirChangeNotifications);
    destructor Destroy; override;
    procedure Terminate; reintroduce;
    property OnChange: TDirChangeEvent read FOnChange write FOnChange;
  end;

const
  FILE_LIST_DIRECTORY = $0001;
  FILE_READ_ATTRIBUTES = $0080;
  CNotificationFilters: array[TDirChangeNotification] of Cardinal = (0, 0,
   FILE_NOTIFY_CHANGE_FILE_NAME,
   FILE_NOTIFY_CHANGE_DIR_NAME,
   FILE_NOTIFY_CHANGE_SIZE,
   FILE_NOTIFY_CHANGE_LAST_WRITE,
   FILE_NOTIFY_CHANGE_LAST_ACCESS,
   FILE_NOTIFY_CHANGE_CREATION);
  CAllNotifications: TDirChangeNotifications = [dcnFileAdd, dcnFileRemove,
   dcnRenameFile, dcnRenameDir, dcnModified, dcnLastWrite,
   dcnLastAccess, dcnCreationTime];

implementation

constructor TDirChangeNotifier.Create(const ADirectory: WideString;
 WantedNotifications: TDirChangeNotifications);
begin
  inherited Create(False);
  FreeOnTerminate := True;
  FDir := ExcludeTrailingPathDelimiter(ADirectory);
  FNotifList := WantedNotifications;
end;

destructor TDirChangeNotifier.Destroy;
begin
  //
  inherited Destroy;
end;

function FileTimeToDateTime(FileTime: TFileTime): TDateTime;
var
  SysTime: TSystemTime;
  TimeZoneInfo: TTimeZoneInformation;
  Bias: Double;
begin
  FileTimeToSystemTime(FileTime, SysTime);
  GetTimeZoneInformation(TimeZoneInfo);
  Bias := TimeZoneInfo.Bias / 1440; // = 60 * 24
  Result := SystemTimeToDateTime(SysTime) - Bias;
end;

function TDirChangeNotifier.WhichAttrChanged(const AFileName: WideString):
  TDirChangeNotification;
var
  hFile: THandle;
  FCreation, FModification, FAccess: TFileTime;
  Creation, Modification, Access: TDateTime;
begin
  hFile := CreateFileW(PWideChar(AFileName), FILE_READ_ATTRIBUTES,
    FILE_SHARE_READ or FILE_SHARE_DELETE or FILE_SHARE_WRITE, nil,
    OPEN_EXISTING, 0, 0);

  if hFile = 0 then
  begin
    Result := dcnModified;
    Exit;
  end;

  GetFileTime(hFile, @FCreation, @FAccess, @FModification);
  Creation := FileTimeToDateTime(FCreation);
  Access := FileTimeToDateTime(FAccess);
  Modification := FileTimeToDateTime(FModification);

  if Now - Access <= 20.0 then
    Result := dcnLastAccess
  else if Now - Modification <= 20.0 then
    Result := dcnLastWrite
  else if Now - Creation <= 20.0 then
    Result := dcnCreationTime


  else
    Result := dcnModified;
  CloseHandle(hFile);
end;

procedure TDirChangeNotifier.Execute;
var
  Buffer: array[0..4095] of Byte;
  BytesReturned: Cardinal;
  WaitHandles: array[0..1] of THandle;
  NotifyFilter, I, Next, Action, FileNameLength: Cardinal;
  FileName: WideString;
  FmtSettings: TFormatSettings;
  N: TDirChangeNotification;
begin
  FTermEvent := CreateEvent(nil, True, False, nil);
  FillChar(FOverlapped, SizeOf(TOverlapped), 0);
  FOverlapped.hEvent := CreateEvent(nil, True, False, nil);
  FDirHandle := CreateFileW(PWideChar(FDir), FILE_LIST_DIRECTORY,
    FILE_SHARE_READ or FILE_SHARE_DELETE or FILE_SHARE_WRITE, nil,
    OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS or FILE_FLAG_OVERLAPPED, 0);
  WaitHandles[0] := FTermEvent;
  WaitHandles[1] := FOverlapped.hEvent;
  GetLocaleFormatSettings(LOCALE_USER_DEFAULT, FmtSettings);

  NotifyFilter := 0;
  for N := Low(TDirChangeNotification) to High(TDirChangeNotification) do
    if N in FNotifList then
      Inc(NotifyFilter, CNotificationFilters[N]);

  while True do
  begin
    ReadDirectoryChangesW(FDirHandle, @Buffer, SizeOf(Buffer), True,
     NotifyFilter, nil, @FOverlapped, nil);

    if WaitForMultipleObjects(2, @WaitHandles, False,
      INFINITE) = WAIT_OBJECT_0 then
      Break;

    GetOverlappedResult(FDirHandle, FOverlapped, BytesReturned, False);
    I := 0;
    repeat
      Move(Buffer[I], Next, 4);
      Move(Buffer[I + 4], Action, 4);
      case Action of
        FILE_ACTION_ADDED: FAction := dcnFileAdd;
        FILE_ACTION_REMOVED: FAction := dcnFileRemove;
        FILE_ACTION_MODIFIED: FAction := dcnModified;
        FILE_ACTION_RENAMED_OLD_NAME,
        FILE_ACTION_RENAMED_NEW_NAME: FAction := dcnRenameFile;
      end;

      Move(Buffer[I + 8], FileNameLength, 4);
      SetLength(FileName, FileNameLength div 2);
      Move(Buffer[I + 12], FileName[1], FileNameLength);
      if (FAction = dcnModified) and FileExists(FDir + '\' + FileName) then
        FAction := WhichAttrChanged(FDir + '\' + FileName);

      if Action = FILE_ACTION_RENAMED_NEW_NAME then
      begin
        FOtherFileName := FDir + '\' + FileName;
        if DirectoryExists(FOtherFileName) then
          FAction := dcnRenameDir;
      end
      else
      begin
        FFileName := FDir + '\' + FileName;
        FOtherFileName := '';
      end;

      if (Action <> FILE_ACTION_RENAMED_OLD_NAME)
      and (FAction in FNotifList) then
        Synchronize(DoChange);

      Inc(I, Next);

    until Next = 0;
  end;

  CloseHandle(FTermEvent);
  FTermEvent := 0;
  CloseHandle(FOverlapped.hEvent);
  CloseHandle(FDirHandle);
end;

procedure TDirChangeNotifier.Terminate;
begin
  if FTermEvent <> 0 then
    SetEvent(FTermEvent);
end;

procedure TDirChangeNotifier.DoChange;
begin
  if Assigned(FOnChange) then
    FOnChange(Self, FFileName, FOtherFileName, FAction);
end;

end.
Datei Directives.inc
{ debugging }
{$DEFINE Debugging}

{$IFDEF FinalVersion}
  {$UNDEF Debugging}
{$ENDIF}

{ Version of Delphi }
{$IFDEF VER180}
  {$DEFINE DELPHI_10}
  {$DEFINE DELPHI_9}
  {$DEFINE DELPHI_8}
  {$DEFINE DELPHI_7}
  {$DEFINE DELPHI_6}
  {$DEFINE DELPHI_5}
{$ENDIF}

{$IFDEF VER170}
  {$DEFINE DELPHI_9}
  {$DEFINE DELPHI_8}
  {$DEFINE DELPHI_7}
  {$DEFINE DELPHI_6}
  {$DEFINE DELPHI_5}
{$ENDIF}

{$IFDEF VER160}
  {$DEFINE DELPHI_8}
  {$DEFINE DELPHI_7}
  {$DEFINE DELPHI_6}
  {$DEFINE DELPHI_5}
{$ENDIF}

{$IFDEF VER150}
  {$DEFINE DELPHI_7}
  {$DEFINE DELPHI_6}
  {$DEFINE DELPHI_5}
{$ENDIF}

{$IFDEF VER140}
  {$DEFINE DELPHI_6}
  {$DEFINE DELPHI_5}
{$ENDIF}

{$IFDEF VER130}
  {$DEFINE DELPHI_5}
{$ENDIF}

{$IFDEF DELPHI_7}
  {$DEFINE EnableXPMan}
{$ENDIF}

{$IFDEF DELPHI_9}
  {$DEFINE EnableRGN}
  {$DEFINE EnableInline}
{$ENDIF}

(*
  {$IFDEF EnableXPMan}, XPMan{$ENDIF}
  {$IFDEF EnableRGN}{$REGION ''}{$ENDIF}
  {$IFDEF EnableRGN}{$ENDREGION}{$ENDIF}
  {$IFDEF EnableInline}inline;{$ENDIF}
  {$IFDEF EnableInline}{$INLINE ON}{$ENDIF}
*)

{$ALIGN 8}
{$LONGSTRINGS ON}
{$WRITEABLECONST OFF}
{$IOCHECKS ON}
{$BOOLEVAL OFF}

{$IFDEF HighDebugging}
  {$OPTIMIZATION OFF}
{$ELSE}
  {$OPTIMIZATION ON}
{$ENDIF}


{$SAFEDIVIDE OFF}


{$IFDEF Debugging}
  {$ASSERTIONS ON}
  {$DEBUGINFO ON}
  {$OVERFLOWCHECKS ON}
  {$RANGECHECKS ON}
{$ELSE}
  {$ASSERTIONS OFF}
  {$DEBUGINFO OFF}
  {$OVERFLOWCHECKS OFF}
  {$RANGECHECKS OFF}
{$ENDIF}
Unit1
uses DirSniffer,
  {$WARNINGS OFF}FileCtrl{$WARNINGS ON}
  {$IFDEF EnableXPMan}, XPMan{$ENDIF}
  
//

private
    FChangeThread: TDirChangeNotifier;
    procedure SthChange(Sender: TDirChangeNotifier; const FileName,
     OtherFileName: WideString; Action: TDirChangeNotification);
    procedure ThreadTerminated(Sender: TObject);
    
 //
 
 
procedure TForm1.FormCreate(Sender: TObject);
var
  Buf: array[0..255] of Char;
begin
  GetWindowsDirectory(@Buf, SizeOf(Buf));
  EdtDir.Text := ExtractFileDrive(Buf);
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  if Assigned(FChangeThread) then
    FChangeThread.Terminate;
end;

procedure TForm1.StatusBar1Resize(Sender: TObject);
begin
  StatusBar1.Panels[0].Width := StatusBar1.ClientWidth - 150;
end;

procedure TForm1.SthChange(Sender: TDirChangeNotifier;
 const FileName, OtherFileName: WideString; Action: TDirChangeNotification);
var
  Fmt, Line: WideString;
begin
  case Action of
    dcnFileAdd:                   Fmt := 'Creation file %s';
    dcnFileRemove:                Fmt := 'Remove file %s';
    dcnRenameFile, dcnRenameDir:  Fmt := '%s renamed to %s';
    dcnModified:                  Fmt := 'Modification file %s';
    dcnLastAccess:                Fmt := 'Date last access file %s  modified';
    dcnLastWrite:                 Fmt := 'Date last write file %s modified';
    dcnCreationTime:              Fmt := 'Create time file %s modified';
  end;

  Line := FormatDateTime('"["hh":"nn":"ss","zzz"] "', Now);
  Line := Line + Format(Fmt, [FileName, OtherFileName]);
  ListBox1.Items.Insert(0, Line);
  if ListBox1.Items.Count > 1 then
    StatusBar1.Panels[1].Text := Format('%d elements', [ListBox1.Items.Count])
  else
    StatusBar1.Panels[1].Text := '1 element';
end;

procedure TForm1.ThreadTerminated(Sender: TObject);
begin
  FChangeThread := nil;
  Button1.Enabled := True;
  Button2.Enabled := False;
  StatusBar1.Panels[0].Text := 'Sniffer stopped';
end;
Beispiel Start / Stop :
procedure TForm1.Button1Click(Sender: TObject);
begin
  FChangeThread := TDirChangeNotifier.Create(EdtDir.Text, CAllNotifications);
  FChangeThread.OnChange := SthChange;
  FChangeThread.OnTerminate := ThreadTerminated;

  Button1.Enabled := False;
  Button2.Enabled := True;
  ListBox1.Items.Clear;
  StatusBar1.Panels[1].Text := '0 element';
  StatusBar1.Panels[0].Text := 'Sniff on File System Changes';
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  FChangeThread.Terminate;
end;

Keine Kommentare:

Kommentar veröffentlichen

Beliebte Posts

Translate