Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi ReadDirectoryChangesW (https://www.delphipraxis.net/110205-readdirectorychangesw.html)

Cylence 14. Mär 2008 18:06


ReadDirectoryChangesW
 
Hi,

ich möchte in einen MediaPlayer eine Möglichkeit einbauen das dieser eins oder wenn möglich mehrere Ordner automatisch überwacht und in liste hinzufügt oder entfernt was halt grad passiert...

Dazu hab ich 2 ansätze gefunden aber der erste geht einmal und das wars und der zweite geht garnich

kennt sich einer von euch da aus?

Delphi-Quellcode:

type
  FileNotifyInformation = Record
                             NextEntryOffset : DWORD;
                             Action : DWORD;
                             FileNameLength : DWORD;
                             FileName : Array[0..MAX_PATH] Of WCHAR;
                         end;
PFileNotifyInformation = ^FileNotifyInformation;

//---------------------------------------------------Version 1------------

procedure TcsDirThread.Execute;
var
  pBuf        : Pointer;
  dwBufLen    : DWORD;
  dwRead      : DWORD;
  FNI         : FileNotifyInformation;
  pWork       : Pointer;
  sFileName   : Widestring;
  dwWaitStatus : DWORD;
  FhFile : THandle;
  hNotifity : Cardinal;
  FsFileName : String;
  ReNode : TTreeNode;
  tempX : String;
  i : Integer;
begin

  Form1.Memo1.Lines.Add('Überwachung gestartet');
  FhFile   := CreateFile(PChar(Form1.FolderToWatch1), GENERIC_READ or GENERIC_WRITE, FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_ATTRIBUTE_DIRECTORY or FILE_FLAG_BACKUP_SEMANTICS, 0);
  Priority := tpLower;
                         
  hNotifity := FindFirstChangeNotification(PChar(Form1.FolderToWatch1),                   //Verzeichnis
                                           True,                              //unterverzeichnisse überwachen
                                           FILE_NOTIFY_CHANGE_FILE_NAME or
                                           FILE_NOTIFY_CHANGE_LAST_WRITE or
                                           FILE_NOTIFY_CHANGE_SIZE or
                                           FILE_ACTION_ADDED or
                                           FILE_ACTION_REMOVED or
                                           FILE_ACTION_MODIFIED);
  if (FhFile = INVALID_HANDLE_VALUE) or (FhFile = 0) then
  begin
    RaiseLastWin32Error;
    Terminate;
  end;
  if (hNotifity = INVALID_HANDLE_VALUE) then
  begin
    RaiseLastWin32Error;
    Terminate;
  end;

  dwBufLen := 65536;
  pBuf    := AllocMem(dwBufLen);
  try
    while ((FindNextChangeNotification(hNotifity)) and (not terminated)) do
    begin
      Synchronize(Application.ProcessMessages);
      dwWaitStatus := WaitForSingleObject(hNotifity, 1000);
      if (dwWaitStatus = WAIT_FAILED) then
      begin
        RaiseLastWin32Error;
        Terminate;
      end;
      if (dwWaitStatus = WAIT_OBJECT_0) then
      begin
        ReadDirectoryChangesW(FhFile,pBuf,dwBufLen,true,
                              FILE_NOTIFY_CHANGE_FILE_NAME or
                              FILE_NOTIFY_CHANGE_DIR_NAME or
                              FILE_NOTIFY_CHANGE_ATTRIBUTES or
                              FILE_NOTIFY_CHANGE_SIZE or
                              FILE_NOTIFY_CHANGE_LAST_WRITE or
                              FILE_NOTIFY_CHANGE_CREATION or
                              FILE_ACTION_ADDED or
                              FILE_ACTION_REMOVED or
                              FILE_ACTION_MODIFIED,
                              @dwRead,nil,nil);
        pWork := pBuf;
        repeat
          StrMove(@FNI,pWork,12);
          PChar(pWork) := PChar(pWork)+12;
          sFileName   := StringOfChar(#00,FNI.FileNameLength);
          StrMove(@sFileName[1],pWork,FNI.FileNameLength);
          FsFileName := WideCharToString(PWideChar(sFileName));
          FsFileName := copy(FsFileName,1,length(FsFileName) shl 1);

          //Synchronize(AddFileToList);

          PChar(pWork) := PChar(pBuf)+FNI.NextEntryOffset;
           if FNI.Action = FILE_ACTION_ADDED then begin
              Form1.Memo1.Lines.Add('+ ' + FsFileName);
           end;
           if FNI.Action = FILE_ACTION_REMOVED then begin
              Form1.Memo1.Lines.Add('- ' + FsFileName);
           end;
         { FILE_NOTIFY_CHANGE_FILE_NAME or
          FILE_NOTIFY_CHANGE_DIR_NAME or
          FILE_NOTIFY_CHANGE_ATTRIBUTES or
          FILE_NOTIFY_CHANGE_SIZE or
          FILE_NOTIFY_CHANGE_LAST_WRITE or
          FILE_NOTIFY_CHANGE_LAST_ACCESS or
          FILE_NOTIFY_CHANGE_CREATION {or
          FILE_NOTIFY_CHANGE_SECURITY}

          //break;

        until FNI.NextEntryOffset = 0;
      end;
    end;

   { if (LowerCase(ExtractFileExt(FsFileName)) = '.bmp') then
    begin
      PostMessage(MainForm.Handle, Verzeichnisaenderung_bmp, 0, ProjektID);
    end; }

  finally
    FreeMem(pBuf,dwBufLen);
  end;
end;

//------------------------------------------------------Version2--------------------------

procedure TMonitorThread.Execute;
var
  pBuf:        Pointer;
  dwBufLen:    DWORD;
  dwRead:      DWORD;
  FNI:         FileNotifyInformation;
  pWork:       Pointer;
  sFileName:   Widestring;
  FsFileName : String;
  i : Integer;
  temp : string;
  ReNode : TTreeNode;
  DirectoryHandle : THandle;
begin
  DirectoryHandle := CreateFile( PCHar(Form1.FolderToWatch2), GENERIC_READ or GENERIC_WRITE, FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_ATTRIBUTE_DIRECTORY or FILE_FLAG_BACKUP_SEMANTICS, 0);
  Priority := tpLower;
  Form1.Memo2.Lines.Add('Überwachung gestartet');
  dwBufLen := 65536;
  pBuf    := AllocMem(dwBufLen);
  while not terminated do
  begin
    ReadDirectoryChangesW(DirectoryHandle, pBuf, dwBufLen, True,
                          FILE_NOTIFY_CHANGE_LAST_WRITE,
                          @dwRead, nil, nil);
    pWork := pBuf;
    repeat
      StrMove(@FNI,pWork,12);
      PChar(pWork) := PChar(pWork)+12;
      sFileName   := StringOfChar(#00,FNI.FileNameLength);
      StrMove(@sFileName[1],pWork,FNI.FileNameLength);
      FsFileName := WideCharToString(PWideChar(sFileName));
      FsFileName := copy(FsFileName,1,length(FsFileName) shl 1);
      PChar(pWork) := PChar(pBuf)+FNI.NextEntryOffset;
           if FNI.Action = FILE_ACTION_ADDED then begin
              Form1.Memo2.Lines.Add('+ ' + FsFileName);
           end;
           if FNI.Action = FILE_ACTION_REMOVED then begin
              Form1.Memo2.Lines.Add('- ' + FsFileName);
           end;
         { FILE_NOTIFY_CHANGE_FILE_NAME or
          FILE_NOTIFY_CHANGE_DIR_NAME or
          FILE_NOTIFY_CHANGE_ATTRIBUTES or
          FILE_NOTIFY_CHANGE_SIZE or
          FILE_NOTIFY_CHANGE_LAST_WRITE or
          FILE_NOTIFY_CHANGE_LAST_ACCESS or
          FILE_NOTIFY_CHANGE_CREATION {or
          FILE_NOTIFY_CHANGE_SECURITY}

          //break;
         
    until FNI.NextEntryOffset = 0;
  end;
  FreeMem(pBuf,dwBufLen);
end;

//-------------------------------------------------------------------------------------------------------------------------------------v
was mach ich falsch und mach ich was falsch?

Thanx

Tom

ManfredG 15. Mär 2008 17:26

Re: ReadDirectoryChangesW
 
Hallo Tom,
ich habe heute leider nicht den Nerv deinen Code zu überprüfen, hatte aber in der Vergangenheit schon mal ein ähnliches Problem und deshalb eine Komponente entwickelt. Vielleicht hilft dir das weiter.

Hier die Komponenten:
Delphi-Quellcode:
unit FldrControl;  

interface

uses
  Windows, SysUtils, Classes, cThread, SyncObjs;
// dieser Typ steht für die dwFilter-Konstanten von ReadDirectoryChangesW
// er ist erfoderlich, da die Filter-Konstanten nicht direkt verwendet werden können,
// da ihr Wertbereich 128 überschreitet und nicht mehr in einen SET OF passen
type
  opTyp = set of (fncFileName,fncDirName,fncAttributes,fncSize,fncLastWrite,fncLastAccess,fncCreation,fncSecurity);
// die Funktion dient der Datenübergabe an ein übergeordnetes Fenster
Type
  TOnGetData = Procedure(Folder: String; Action: Integer) of Object;
{ Nichtvisuelle Komponente zur Ordnerüberwachung
  Properties:
    Folder - (lesen/schreiben) der Ordner, ab dem die Struktur überwacht werden soll
    ThreadExists - (lesen) TRUE, wenn der Überwachungsthread existiert
    ThreadSuspended - (lesen) TRUE, wenn der Thread suspendiert ist.
    CtrlTyp - (lesen/schreiben) Ersatz für dwFilter-Konstanten im Objektinspektor
    OnGetResult - Datenübergabeereignis
  Funktionen:
    Create, Destroy
    GetData - Verbindungsfunktion für Datenübergabe im Objektinspektor
    StartThread   - Start des Überwachungsthreads
    StopThread    - Beenden des Überwachungsthreads
    SuspendThread - Suspendieren des Überwachungsthreads
    ResumeThread; - Wiederaufnehme des Überwachungsthreads
}
type
  TFldrControl = class(TComponent)
  private  { Private-Deklarationen }
    ControlThread: CtrlThread; // Zeiger auf das Thread-Objekt
    FOrdnerName : String;    // zu überwachender Ordner
    SuspEventName: String;    // benamter Event für die Einleitung von Suspend
    TermEventName: String;    // benamter Event für die Einleitung von Terminate
    FOnData     : TOnGetData;
    ThrdExists  : boolean;   // Kennzeichen für die Existenz des Threads
    wSelChg     : DWORD;     // Filter für ReadDirectoryChangesW
    TypSelChg   : opTyp;     // Alias für Filter (Objektinspektor)
  protected { Protected-Deklarationen }
    procedure     SetOrdnerName(NewFolder: String); // ändern Ordnername
    function      GetThreadStatus: boolean;        // Abfrage Threadstatus
    procedure     SetTypSelChg(Value: opTyp);      // ändern Filter
  public   { Public-Deklarationen }
    EvOrdner    : String;     // Rückgabedaten Ordnername bei Ereignis
    EvAction    : integer;    // Rückgabedaten Ereignis
    Constructor   Create(AOwner: TComponent); override;
    Destructor    Destroy; override;
    Procedure     StartThread;
    Procedure     StopThread;
    Procedure     SuspendThread;
    Procedure     ResumeThread;
    procedure     GetData;
    function      GetReason(const AdwReasonCode: DWORD): String;
  published { Published-Deklarationen }
    Property      Folder       : String Read FOrdnerName write SetOrdnerName;
    Property      ThreadExists : boolean read ThrdExists default TRUE;
    Property      ThreadSuspend : boolean read GetThreadStatus;
    Property      OnGetResult  : TOnGetData read FOnData write FOnData;
    Property      CtrlTyp      : opTyp read TypSelChg write SetTypSelChg;
  end;

procedure Register;
{*R *.res}
implementation

procedure Register;
begin
  RegisterComponents('Eigene', [TFldrControl]);
end;

Constructor TFldrControl.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  ControlThread:=NIL;  // überflüssig
  ThrdExists  :=FALSE; // Ausgangssituation
  SetTypSelChg([fncFileName,fncDirName]); // Standartwert für Filter
end;

Destructor TFldrControl.Destroy;
begin
  inherited Destroy;
end;

// Umwandlung opTyp (SET OF) in DWORD für Filterkonstanten
procedure TFldrControl.SetTypSelChg;
var res: DWORD;
begin
  res:=0;
  if fncFileName  in Value then res:=res or FILE_NOTIFY_CHANGE_FILE_NAME;
  if fncDirName   in Value then res:=res or FILE_NOTIFY_CHANGE_DIR_NAME;
  if fncAttributes in Value then res:=res or FILE_NOTIFY_CHANGE_ATTRIBUTES;
  if fncSize      in Value then res:=res or FILE_NOTIFY_CHANGE_SIZE;
  if fncLastWrite in Value then res:=res or FILE_NOTIFY_CHANGE_LAST_WRITE;
  if fncLastAccess in Value then res:=res or FILE_NOTIFY_CHANGE_LAST_ACCESS;
  if fncCreation  in Value then res:=res or FILE_NOTIFY_CHANGE_CREATION;
  if fncSecurity  in Value then res:=res or FILE_NOTIFY_CHANGE_SECURITY;
  wSelChg:=res;
  TypSelChg:=Value;
  // nach einer Filteränderung muß der Thread eventuell neu gestartet werden!
  if not ThrdExists then Exit; // außer er existiert nicht
  // wenn der Thread suspendiert ist..
  if ControlThread.Suspended then begin
    ControlThread.Resume; // dann aktivieren
    StopThread;          // vernichten
    StartThread;         // neu starten
  end else begin // wenn er schon läuft
    StopThread;  // vernichten
    StartThread; // neu starten
  end;
end;

// 
function TFldrControl.GetThreadStatus: boolean;
begin
  if  ThrdExists
  then Result:=ControlThread.Suspended
  else Result:=TRUE;
end;

procedure TFldrControl.SetOrdnerName;
begin
  FOrdnerName:=NewFolder;
  if not ThrdExists then Exit;
  if ControlThread.Suspended then begin
    ControlThread.Resume;
    StopThread;
    StartThread;
  end else begin
    StopThread;
    StartThread;
  end;
end;

procedure TFldrControl.GetData;
begin
  if Assigned(OnGetResult)
  then OnGetResult(EvOrdner,EvAction);
end;

Procedure  TFldrControl.StartThread;
var SelfName: String;
begin
  if ThrdExists then exit;
  if (Length(FOrdnerName)=0) or (Not DirectoryExists(FOrdnerName)) then begin
    MessageBox(0,'Ordner nicht angegeben','Fehler',MB_OK);
    Exit;
  end;
  if wSelChg=0 then begin
    MessageBox(0,'Überwachungskriterium nicht angegeben','Fehler',MB_OK);
    Exit;
  end;
  ControlThread:=CtrlThread.Create(self,FOrdnerName,wSelChg);
  ThrdExists  :=TRUE;
  SelfName    :=IntToStr(ControlThread.Handle);
  SuspEventname:=SelfName+'W';
  TermEventName:=SelfName+'N';
  ControlThread.SetEventNames(SuspEventname,TermEventName);
  ControlThread.Resume;
end;

Procedure  TFldrControl.StopThread;
var StopEvent: TEvent;
begin
  StopEvent:=TEvent.Create(nil,FALSE,FALSE,TermEventName);
  PulseEvent(StopEvent.Handle);
  StopEvent.Free;
  (**)// am 09.09.2007 zugefügt
      // wenn der Thread nicht durch Terminate vernichtet wird (FreeOnTerminate=TRUE)
      // bleibt er nach Änderung des Ordnernamens auf dem alten Ordner stehen !
  if ThrdExists then ControlThread.Terminate;
  (**)
  ThrdExists:=FALSE;
end;

Procedure  TFldrControl.SuspendThread;
var SuspEvent: TEvent;
begin
  SuspEvent:=TEvent.Create(nil,FALSE,FALSE,SuspEventName);
  SuspEvent.SetEvent;
  SuspEvent.ResetEvent;
  SuspEvent.Free;
end;

Procedure  TFldrControl.ResumeThread;
begin
  ControlThread.Resume;
end;

// Ereignisgrung in Text umwandeln
function TFldrControl.GetReason(const AdwReasonCode: DWORD): String;
begin
  case AdwReasonCode of
    FILE_ACTION_ADDED           : Result := 'hinzugefügt';
    FILE_ACTION_REMOVED         : Result := 'gelöscht';
    FILE_ACTION_MODIFIED        : Result := 'verändert';
    FILE_ACTION_RENAMED_OLD_NAME : Result := 'umbenannt. Alter Name.';
    FILE_ACTION_RENAMED_NEW_NAME : Result := 'umbenannt. Neuer Name.';
    else                          Result := 'Ungültiger Reason Code: '+IntToHex(AdwReasonCode,8);
  end;
end;

end.
Zu dieser Komponente gehört noch folgender Thread:

Delphi-Quellcode:
unit cThread;

interface

uses
  SysUtils, Classes, Controls, SyncObjs, Windows, ShellApi, ComCtrls;

const
  FILE_LIST_DIRECTORY = $0001;
  WaitDir = WAIT_OBJECT_0;
  WaitTerm = WAIT_OBJECT_0+1;
  WaitSusp = WAIT_OBJECT_0+2;

type
  CtrlThread = class(TThread)
  private
    FhFile    : DWORD;     // Handle von CreateFile auf die kontrollierte Ordnerstruktur
    FsDirPath : string;    // der Pfad zu der Ordnerstruktur, die zu überwachen ist
    FsFileName : string;    // ein Dateiname aus einen Überwachungsereignis der Ordner
    FAction   : DWORD;     // Verzeichnisaktion, die erfolgte
    FileEvent : THandle;   // Handle für das Ordnerüberwachungsereignis
    SuspEvent : TEvent;    // Ereignis für das suspendieren des Threads
    SuspEvName : String;    // Name dieses Ereignisses
    TermEvent : TEvent;    // eigenes Ereignis, das für den Abbruch des Threads erforderlich ist
    TermEvName : String;    // Name des Abbruchereignisses
    Owner     : TComponent; // Besitzer des Threads
    FFilter   : DWord;     // Filter für
    procedure   SendData;  // eine Beispielfunktion für die Datenübergabe
  public
    constructor Create(AOwner: TComponent; const AsDirPath: string; AFilter: DWORD);
    destructor Destroy; override;
    procedure  Execute; override;
    Procedure  SetEventNames(AwEvName,AnEvName: string);
  end;

  PFILE_NOTIFY_INFORMATION = ^FILE_NOTIFY_INFORMATION; // Strukturzeiger
  FILE_NOTIFY_INFORMATION = packed record // Ereignisrecord für !ein! überwachungsereignis
    dwNextEntryOffset : DWORD;           // Offset zum nächsten Eintrag
    dwAction         : DWORD;           // Ereignisgrund
    dwFileNameLength : DWORD;           // Länge des Dateinamens
    dwFileName       : WideString;      // Dateiname
  end;



implementation
uses FldrControl;

constructor CtrlThread.Create(AOwner: TComponent; const AsDirPath: string; AFilter: DWORD);
begin
  inherited Create(TRUE);      // Thread erstellen und nicht laufen lassen
  FsDirPath      := AsDirPath; // der zu überwachende Pfad
  Owner          := AOwner;   // der Besitzer des Threads
  FFIlter        := AFilter;  // Filter für .. übernehmen
  FreeOnTerminate := true;     // Thread nach Beendigung vernichten lassen
end;

// Namen für die Ereignisse:
// werden von der Komponente aus gesetzt, was aber erst geschehen kann,
// wenn der Thread creiert ist
Procedure CtrlThread.SetEventNames(AwEvName,AnEvName: String);
begin
  SuspEvName:=AwEvName;
  TermEvName:=AnEvName;
end;

procedure CtrlThread.Execute;
var
  pBuffer  : Pointer; // Puffer für die Rückgabedaten von ReadDirectoryChangesW
  dwBufLen : DWORD;  // Größe des Puffers
  dwRead   : DWORD;  // Anzahl der Daten im Puffer
  PInfo    : PFILE_NOTIFY_INFORMATION; // Maske für die Pufferdaten
  dwNextOfs : DWORD;  // Position des Folgesatzes im Puffer (bei 0 - keiner)
  dwFnLen  : DWORD;  // Dateinamenlänge
  Overlap  : TOverlapped; // Asynchronstruktur
  WaitResult: DWORD;  // Rückgabewert von WaitForMultipleObjects
  EventArray  : Array[0..2] of THandle; // Array der Handles für WaitForMultipleObjects
begin
  // Handle auf das zu überwachende Verzeichnis
  FhFile:= CreateFile(PChar(FsDirPath),
                      FILE_LIST_DIRECTORY or GENERIC_READ,
                      FILE_SHARE_READ or FILE_SHARE_WRITE or FILE_SHARE_DELETE,
                      nil,
                      OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS or FILE_FLAG_OVERLAPPED,
                      0);
  if (FhFile = INVALID_HANDLE_VALUE) or (FhFile = 0) then exit;
  // Ereignis für Asynchronbehandlung von ReadDirectoryChangesW
  FileEvent:=CreateEvent(nil,FALSE,FALSE,nil);
  // Asynchronstruktur mit Ereignis besetzen
  Overlap.hEvent:=FileEvent;

  // Neues Ereignis erstellen, um später WaitForMultipleObjects abzubrechen
  // der Abbruch erfolgt von außen durch die Erzeugung des gleichen Events
  // welcher dann auf signaled gesetzt werden muß
  TermEvent:=TEvent.Create(nil,FALSE,FALSE,TermEvName);

  // Neues Ereignis erstellen, um später WaitForMultipleObjects abzubrechen
  // und den Thread auf suspendet zu setzen
  // der Abbruch erfolgt von außen durch die Erzeugung des gleichen Events
  // welcher dann auf signaled gesetzt werden muß
  SuspEvent:=TEvent.Create(nil,FALSE,FALSE,SuspEvName);

  // die drei Ereignishandles für WaitForMultipleObjects in ein Array füllen
  EventArray[0]:=FileEvent;        // Ordneränderung
  EventArray[1]:=TermEvent.Handle; // Abbruch
  EventArray[2]:=SuspEvent.Handle; // Suspend

  // Rückgabepuffer für ReadDirectoryChangesW erstellen
  dwBufLen    := 65535;
  pBuffer     := AllocMem(dwBufLen);
  try
    // Ablauf starten ...
    while not terminated do begin
      // Ordnerüberwachung asynchron erstellen
      dwRead:=0;
      if ReadDirectoryChangesW(FhFile,pBuffer,dwBufLen,true,
                               FFilter, //FILE_NOTIFY_CHANGE_FILE_NAME or FILE_NOTIFY_CHANGE_DIR_NAME,
                               @dwRead,@Overlap,NIL) then
      begin
        // unendliches warten bis eines der Ereignisse eintritt
        WaitResult:=WaitForMultipleObjects(3,@EventArray,FALSE,infinite);
        // wenn das Warten beendet wird, dann ...
        case WaitResult of
          // ... weil sich etwas in den Ordnern getan hat
          WaitDir: begin
                   // Maske über den Puffer legen, um auf die Daten zuzugreifen
                   PInfo:= pBuffer;
                   // und dies wiederholen ...
                   repeat
                     // Offset zum folgenden Datensatz
                     dwNextOfs :=PInfo.dwNextEntryOffset;
                     // Aktion, die im Ordnerbaum sattfand
                     fAction  :=PInfo.dwAction;
                     // Länge des betroffenen Ordners oder der Datei
                     dwFnLen  :=PInfo.dwFileNameLength;
                     // Dateinamen in AnsiString umsetzen
                     fsFileName:=WideCharLenToString(@PInfo.dwFileName,dwFnLen div 2);
                     // Daten in den Haupttread übergeben
                     Synchronize(SendData);
                     // Maske auf den nächsten Datensatz verschieben
                     pChar(PInfo):=pChar(PInfo)+dwNextOfs;
                     // wenn keiner mehr vorhanden ist, beenden
                   until dwNextOfs=0;
                 end;
          // ... oder das Abbruchereignis eingetreten ist
          WaitTerm: Terminate;
          // ... oder das Ereignis zum suspendieren eingetreten ist
          WaitSusp: Suspend;
          else break;
        end;
      end;
    end;
  finally
    FreeMem(pBuffer,dwBufLen);
  end;
end;

destructor CtrlThread.Destroy;
begin // diverse Handles freigeben
  try
    if FhFile <> INVALID_HANDLE_VALUE then CloseHandle(FhFile);
    CloseHandle(FileEvent);
    TermEvent.Free;
    SuspEvent.Free;
  except
  end;
end;

// Daten an das Control-Objekt übergeben
procedure CtrlThread.SendData;
begin
  TFldrControl(Owner).EvAction:=FAction;
  TFldrControl(Owner).EvOrdner:=fsFileName;
  // und dort die Benachrichtigungsfunktion aufrufen
  TFldrControl(Owner).GetData;
end;

end.
Also dann das Ganze als Komponente registrieren un in des Formulat legen.
Die Ereignisbehandlungsroutine aufbauen, Pfad setzen und mit StartTread aktivieren.

Gruß, Manfred

Cylence 17. Mär 2008 07:33

Re: ReadDirectoryChangesW
 
Hi,

WOW Cool, danke das sieht perfekt aus werd ich dann gleich mal testen SUPER

THANX

Cylence

Cylence 17. Mär 2008 12:02

Re: ReadDirectoryChangesW
 
Hi,

ok klappt perfekt das teil, danke Dir.
nur eine frage noch, gehen da auch irgendwie mehrere davon gleichzeitig? Habs mal getestet aber irgendwie ging nur einer...


Gruß

tom

Ganymed 26. Mär 2009 09:03

Re: ReadDirectoryChangesW
 
Hallo!

Ich habe mir deinen Code auch mal "ausgeliehen" ;), bekomme aber fast immer bei CloseHandle(FhFile); im Destructor eine AV bzw. einen Memory-leak...

Muss man irgendwas bestimmtes machen, bevor man den freigibt?

Mein Code sieht grob so aus:
Delphi-Quellcode:
constructor TAutomatics.Create(AOwner: TControl; ASettings: TAutomaticsSetting; ASequenceIndex: Integer);
begin
  inherited Create;
  FOwner := AOwner;

  iSequenceIndex := ASequenceIndex;
  rSettings := ASettings;
  bEnabled := False;

  oFileQueue := TStringList.Create;
  oFolderControler := TFldrControl.Create(AOwner);
  oFolderControler.Folder := rSettings.sInputFolder;
  oFolderControler.OnGetResult := FolderControlEvent;
end;

destructor TAutomatics.Destroy;
begin
  oFolderControler.StopThread;
  oFolderControler.Free;
  oFileQueue.Free;
  inherited;
end;
Gestartet wird der Thread an anderer Stelle mit StartThread().

Achja, noch eine Frage:
Das Event triggert ja, sobald eine Datei erstellt wird. Wenn man nun eine sehr große Datei kopiert, triggert das Event, sobald der Dateiname da ist, und lange bevor die Datei komplett erstellt/kopiert wurde. Gibt es einen Trick, wie man ermitteln kann, ob die Datei vollständig erstellt wurde? Mit schwebt da was mit einer Schreife auf TFileStream.Create(..., fmShareExclusive) vor, bis der exklusive Zugriff erfolgreich ist...

MuTzE.Y85 18. Mai 2014 12:34

AW: ReadDirectoryChangesW
 
Ich muss das Thema mal aufleben lassen.

Ich bin dabei mir ein Tool zu schreiben, dass Ordner überwacht und diese bei Änderungen spiegelt. Das klappt soweit auch.
Dabei nutze ich die SHChangeNotify API. Damit kann ich mehrere Ordner gleichzeitig überwachen, jedoch kommt es ab und an vor, dass einige Änderungen nicht wahrgenommen oder weitergeleitet werden.

Jetzt habe ich schon gelesen, dass das normal ist, dass einige Events untergehen und die Methode "ReadDirectoryChangesW" dafür besser geeignet ist.

Die Frage ist jetzt: Kann man denn damit mehrere Verzeichnisse gleichzeitig überwachen?

hathor 18. Mai 2014 14:19

AW: ReadDirectoryChangesW
 
Liste der Anhänge anzeigen (Anzahl: 1)
Dafür gibt es fertige Komponenten:
- HDDWatch
- DirectoryWatch

Für jedes Laufwerk eine Kompo aufs Formular:

MuTzE.Y85 18. Mai 2014 14:34

AW: ReadDirectoryChangesW
 
Aha, und was machen die anders als die oben gepostete?

Sorry, aber deine Antwort bringt mir nix, denn meine Frage war eine Andere.

hathor 18. Mai 2014 14:52

AW: ReadDirectoryChangesW
 
Zitat:

Zitat von MuTzE.Y85 (Beitrag 1259184)
Die Frage ist jetzt: Kann man denn damit mehrere Verzeichnisse gleichzeitig überwachen?

Das IST Deine Frage!

MuTzE.Y85 18. Mai 2014 15:05

AW: ReadDirectoryChangesW
 
Zitat:

Zitat von hathor (Beitrag 1259192)
Für jedes Laufwerk eine Kompo aufs Formular:

Ja und diesen Teil hätte ich mir vor der Bearbeitung deines Posts gewünscht :wink:

Problem ist nur, dass die Anzahl, der zu überwachenden Verzeichnisse ja bei der Entwicklung nicht vor liegt.
Das wird ja dann im Programm selbst festgelegt. Soll ja auch anpassbar sein.

Wie mache ich das dann?
Die Komponente zur Laufzeit erstellen, aber wie halte ich sie dann auseinander?

EDIT: Alles klar, habs hinbekommen mit einem Array.


Alle Zeitangaben in WEZ +1. Es ist jetzt 01:22 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz