|
PRÉSENTATION :
Programme d'exemple de l'utilisation de la fonction ReadDirectoryChangesW.
NOTES :
Ce programme montre l'utilisation de la fonction de sureveillance d'un répertoire de Windows NT.
C'est utile pour suivre les modifications apportées aux fichiers dans un répertoire.
Par exemple si vous affichez la liste de certains fichiers dans une ListBox ou un TreeView, il est possible de mettre la liste à jour
seulement quand un fichier est ajouté et/ou supprimé. La surveillance est effectuée dans un autre Thread afin de ne pas bloquer l'application principale.
Attention, ce programme ne fonctionne que sous Windows NT4, Windows 2000 et Windows XP.
CODE :
Unit Unit1;
//
// Sujet : Surveillance des modification dans un répertoire
// Avec la fonction API ReadDirectoryChangesW
//
// Par Nono40 : http://nono40.developpez.com http://nono40.fr.st
// mailTo:nono40@fr.st
//
// Le 15/03/2003
//
// Attention : ne fonctionne qu'avec Windows NT4, Windows2000 et WindowsXP
//
Interface
Uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls;
Type
TForm1 = Class(TForm)
Memo1: TMemo;
Panel1: TPanel;
Label1: TLabel;
Edit1: TEdit;
Button1: TButton;
Procedure FormCreate(Sender: TObject);
Procedure FormClose(Sender: TObject; Var Action: TCloseAction);
Procedure Button1Click(Sender: TObject);
Private
{ Déclarations privées }
Public
{ Déclarations publiques }
End;
TThreadSurveillance = Class(TThread)
Private
{ Déclarations privées }
HandleDirectory : THandle;
OverLapped : TOverlapped;
ListeAjouts : TStrings;
CheminEnCours : String;
Procedure MiseAJourListe;
Protected
Procedure Execute; override;
End;
Var
Form1: TForm1;
Implementation
{$R *.dfm}
Var CheminASurveiller : String = '';
ThreadSurveillance : TThreadSurveillance = Nil;
Const FILE_LIST_DIRECTORY=$0001;
Procedure TThreadSurveillance.Execute;
Var Buffer : Array[0..9999]Of Byte;
Retour : DWord;
i : DWord;
Suivant : DWord;
Action : DWord;
Long : DWord;
Chaine : WideString;
Fin : Boolean;
Begin
// Initialisation ds données du Thread
ListeAjouts := TStringList.Create;
// La structure OverLapped permet à Windows de garder une trace
// de la fonctione en cours. hEvent permet de tester si la fonction
// est finie ou non
FillChar(Overlapped,SizeOf(OverLapped),#0);
OverLapped.hEvent:=CreateEvent(Nil,False,False,Nil);
HandleDirectory := INVALID_HANDLE_VALUE;
CheminEnCours := '';
// Boucle pincipale du Thread
While Not Terminated Do
Begin
// Le chemin demandé à changé => On change la surveillance
If CheminASurveiller<>CheminEnCours
Then Begin
ListeAjouts.Clear;
// Une demande est en cours, on libère le Handle
If HandleDirectory<>INVALID_HANDLE_VALUE
Then Begin
CloseHandle(HandleDirectory);
HandleDirectory:=INVALID_HANDLE_VALUE;
ListeAjouts.Add('<FIN>');
End;
// Prise en compte de la nouvelle demande
CheminEnCours:=CheminASurveiller;
If CheminEnCours<>''
Then Begin
// Suppression du '\' final
CheminEnCours := ExcludeTrailingPathDelimiter(CheminEnCours);
// Création du Handle sur le répertoire à surveiller
HandleDirectory:=CreateFile (
PChar(CheminEnCours), // Chemin a surveiller
FILE_LIST_DIRECTORY, // C'est un chemin qu'il faut ouvrir
FILE_SHARE_READ Or // Mode de partage, l'exemple donné dans le SDK est
FILE_SHARE_DELETE Or // faux, du moins avec Xp car il manque le partage
FILE_SHARE_WRITE, // en écriture
Nil, // sécurité par défaut
OPEN_EXISTING, // Le chemin doit exister
FILE_FLAG_BACKUP_SEMANTICS // Attribut de surcharge des droits liés au dossier
Or FILE_FLAG_OVERLAPPED, // Attribut de fonction effectuée après coup
0); // Pas d'attributs à copier
ListeAjouts.Add('<DEBUT:'+CheminEnCours+'>');
End;
Synchronize(MiseAJourListe);
End;
// Une demande de notification est en cours
If HandleDirectory<>INVALID_HANDLE_VALUE
Then Begin
// Appel de la fonction de test des changements dans le répertoire
If ReadDirectoryChangesW(
HandleDirectory, // Handle du chemin à surveiller
@Buffer, // Adresse du buffer qui contiendra la
// description des modifications
SizeOf(Buffer), // Taille du buffer
True, // On surveille aussi les sous-répertoires
FILE_NOTIFY_CHANGE_FILE_NAME // Tous les changement de nom et modification
Or FILE_NOTIFY_CHANGE_DIR_NAME // sont signalés
Or FILE_NOTIFY_CHANGE_LAST_WRITE, //
@Retour, // Adresse de la longueur retournée dans buffer
@OverLapped, // Structure de réponse différée
Nil) // Pas de fonction de rappel
Then Begin
// Maintenant on attend une modification
Repeat
Fin:=GetOverLappedResult(HandleDirectory,OverLapped,Retour,False);
Until Fin
Or(GetLastError<>ERROR_IO_INCOMPLETE)
Or Terminated
Or(CheminASurveiller<>CheminEnCours);
// Si la fonction a fini correctement
// et que l'on ne doit pas terminer le thread
If Fin And Not Terminated And (CheminASurveiller=CheminEnCours) Then
Begin
// il faut alors décoder le buffer reçu
ListeAjouts.Clear;
i:=0;
Repeat
// Le premier DWord contient le décalage vers l'information suivante
Move(Buffer[i ],Suivant,4);
// Le deuxième DWord contient le type de changement détecté
Move(Buffer[i+4],Action ,4);
// Le troisième DWord contient la longueur en octets du nom concerné
Move(Buffer[i+8],Long ,4);
// Le nom du fichier suit
SetLength(Chaine,Long Div 2);
Move(Buffer[i+12],Chaine[1],Long);
If Action=FILE_ACTION_ADDED Then ListeAjouts.Add('FILE_ACTION_ADDED');
If Action=FILE_ACTION_REMOVED Then ListeAjouts.Add('FILE_ACTION_REMOVED');
If Action=FILE_ACTION_MODIFIED Then ListeAjouts.Add('FILE_ACTION_MODIFIED');
If Action=FILE_ACTION_RENAMED_OLD_NAME Then ListeAjouts.Add('FILE_ACTION_RENAMED_OLD_NAME');
If Action=FILE_ACTION_RENAMED_NEW_NAME Then ListeAjouts.Add('FILE_ACTION_RENAMED_NEW_NAME');
ListeAjouts.Add(CheminEnCours+'\'+Chaine);
// On passe à la donnée suivante
i:=i+Suivant;
Until (i>=Retour)Or(Suivant=0);
// Ajout des fichiers modifiés dans le Memo
// Comme c'est un Thread, il n'est pas possible de modifier directement Memo1
Synchronize(MiseAJourListe);
End;
End;
End;
End;
// Libération du Handle en cas de besoin
If HandleDirectory<>INVALID_HANDLE_VALUE Then CloseHandle(HandleDirectory);
HandleDirectory:=INVALID_HANDLE_VALUE;
// Libération des objets
ListeAjouts.Free;
CloseHandle(OverLapped.hEvent);
End;
// Cette procédure ne doit être appelée que par l'intermédiaire de Synchronize
Procedure TThreadSurveillance.MiseAJOurListe;
Begin
Form1.Memo1.Lines.AddStrings(ListeAjouts);
End;
// Création du Thread
Procedure TForm1.FormCreate(Sender: TObject);
Begin
ThreadSurveillance:=TThreadSurveillance.Create(False);
End;
// Libération du Thread
Procedure TForm1.FormClose(Sender: TObject; Var Action: TCloseAction);
Begin
If ThreadSurveillance<>Nil
Then Begin
ThreadSurveillance.Terminate;
ThreadSurveillance.WaitFor;
End;
End;
Procedure TForm1.Button1Click(Sender: TObject);
Begin
CheminASurveiller:=Edit1.Text;
End;
End.
|
| |