 |
|
 |
|
 |
18 - SURVEILLANCE MULTIPLE DE REPERTOIRES
|
|
|
|
PRÉSENTATION :
Programme d'exemple de l'utilisation des notifications de modification de Windows.
NOTES :
Ce programme montre l'utilisation des notifications de modification de répertoire. C'est utile pour suivre les modifications apportées aux fichiers dans un répertoire.
Le principe est le même que celui de la surveillance d'un répertoire, mais appliqué plusieurs fois... La liste des demandes est stockée dans un TList.
Ce programme est donc un exemple de mise en oeuvre des points suivants :
- Thread
- Notification de changement
- Gestion d'un TList
CODE :
Unit Unit1;
Interface
Uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls;
Type
TForm1 = Class(TForm)
lbMessages: TMemo;
Panel1: TPanel;
Label1: TLabel;
Edit1: TEdit;
Button1: TButton;
lbOrdres: TListBox;
Button2: TButton;
Procedure FormCreate(Sender: TObject);
Procedure FormClose(Sender: TObject; Var Action: TCloseAction);
Procedure Button1Click(Sender: TObject);
Procedure Button2Click(Sender: TObject);
Private
{ Déclarations privées }
Public
{ Déclarations publiques }
End;
TThreadSurveillance = Class(TThread)
Private
{ Déclarations privées }
ListeOrdres : TList;
ListeAjouts : TStrings;
OrdreEnCours : String;
Procedure MiseAJourListeMessages;
Procedure MiseAJourListeOrdres;
Function Recherche(Chemin:String):Integer;
Protected
Procedure Execute; override;
End;
Var
Form1: TForm1;
Implementation
{$R *.dfm}
Type
PSurveille = ^TSurveille;
TSurveille = Record
sChemin : String[255];
sHandle : Cardinal;
sDateHeure : TDateTime;
End;
Var
OrdreAFAire : String='';
ThreadSurveillance : TThreadSurveillance = Nil;
Function TThreadSurveillance.Recherche(Chemin:String):Integer;
Var i:Integer;
Begin
Result:=-1;
With ListeOrdres Do For i:=0 To Count-1 Do
If (Items[i]<>Nil)And(PSurveille(Items[i]).sChemin=Chemin)
Then Result:=i;
End;
Procedure TThreadSurveillance.Execute;
Var CheminAZT :Array[0..255]Of Char;
Infos :TSearchRec;
Position :Integer;
Chemin :String;
Ajout :PSurveille;
Handles :TWOHandleArray;
i :Integer;
CodeRetour :Integer;
Begin
// Initialisation des données du Thread
ListeOrdres := TList.Create;
ListeAjouts := TStringList.Create;
OrdreEnCours := '';
// Boucle pincipale du Thread
While Not Terminated Do
Begin
// On à reçu un ordre de changement dans la liste
If (OrdreAFAire<>OrdreEnCours)And(OrdreAFaire<>'')
Then Begin
OrdreEnCours:=OrdreAFaire;
ListeAjouts.Clear;
// Recherche si le chemin est déjà demandé
Chemin := Copy(OrdreEnCours,2,Length(OrdreEnCours)-1);
// Suppression du '\' final
Chemin := ExcludeTrailingPathDelimiter(Chemin);
Position := Recherche(Chemin);
// Suivant le premier caractère de OrdreEnCours, il s'agit d'un ajout ou d'une suppression
Case OrdreAFAire[1] Of
'+':Begin // Ajout d'un chemin
// Le chemin est ajouté seulement s'il n'est pas déjà dans la liste
If (Position=-1)And(Chemin<>'')
Then Begin
// Création du nouvel ordre
New(Ajout);
Ajout.sChemin :=Chemin;
Ajout.sHAndle :=INVALID_HANDLE_VALUE;
Ajout.sDateHeure :=Now;
ListeOrdres.Add(Ajout);
// Création de la demande de notification
Ajout.sHandle := FindFirstChangeNotification(
StrPCopy(CheminAZT,Chemin), // Chemin à surveiler
False, // Ne pas surveiller les sous-répertoires
File_NOTIFY_CHANGE_File_NAME //
+File_NOTIFY_CHANGE_LAST_WRITE); // Surveiller les écriture et changement de noms
// Petit message
ListeAjouts.Add('<DEBUT:'+Chemin+'>');
End;
End;
'-':Begin // Supression d'un chemin
// Bien sur, seul un élément existant est supprimé !
If Position<>-1
Then Begin
With PSurveille(ListeOrdres.Items[Position])^ Do
Begin
// Petit message
ListeAjouts.Add('<FIN:'+sChemin+'>');
// Libération du handle
If sHandle<>INVALID_HANDLE_VALUE
Then Begin
FindCloseChangeNotification(sHandle);
sHandle:=INVALID_HANDLE_VALUE;
End;
// Libération de la mémoire
Dispose(ListeOrdres.Items[Position]);
// Supression de l'ordre
ListeOrdres.Delete(Position);
End;
End;
End;
End;
// Mise à jour de la fenêtre
Synchronize(MiseAJourListeMessages);
Synchronize(MiseAJourListeOrdres);
// Préparation de la liste des Handles
With ListeOrdres Do For i:=0 To Count-1 Do Handles[i]:=PSurveille(ListeOrdres.Items[i]).sHandle;
End;
// Une demande de notification est en cours ( <=> la liste n'est pas vide )
If ListeOrdres.Count<>0
Then Begin
// Il faut donc demander à Windows d'être prévenu en cas de modification
// La sortie de WaitForMultipleObjects est effectuée dans le cas d'une notification
// ou dans le cas d'un TimeOut. Il ne faut pas ici utiliser le timeout INFINITE
// sinon le thread risque d'être bloqué en permanence.
CodeRetour:=WaitForMultipleObjects(ListeOrdres.Count,@Handles,False,200);
If (CodeRetour>=WAIT_Object_0)And(CodeRetour<WAIT_Object_0+ListeOrdres.Count)
Then Begin
// Dans le cas d'une notification il faut rechercher
// les fichiers modifiés depuis le dernier appel
With PSurveille(ListeOrdres.Items[CodeRetour-WAIT_Object_0])^ Do
Begin
ListeAjouts.Clear;
If FindFirst(sChemin+PathDelim+'*.*',faAnyFile,Infos)=0
Then Begin
Repeat
// Le fichier à été modifié, on l'ajoute à la liste
If FileDateToDateTime(Infos.Time)>sDateHeure
Then Begin
// FindData.CFileName n'est utilisable que sous Windows
ListeAjouts.Add(FormatDateTime('DD/MM/YYYY HH:NN:SS',
FileDateToDateTime(Infos.Time))+'='+StrPas(Infos.FindData.cFileName));
End;
Until FindNext(Infos)<>0;
FindClose(Infos);
// Ajout des fichiers modifiés dans le Memo
// Comme c'est un Thread, il n'est pas possible de modifier directement Form1.lbMessages
Synchronize(MiseAJourListeMessages);
End;
// Mémorisation de l'heure en cours pour le prochain test
sDateHeure:=Now;
// Le handle doit être mis à jour pour pouvoir effectuer une nouvelle demande
// Seul le handle testé doit être mis à jour par FindNextChangeNotification, Car
// en cas de modifications multiple simultannée ceci permet de voir toutes les
// modifications.
FindNextChangeNotification(sHandle);
End;
End;
End;
End;
// Libération des objets
ListeAjouts.Free;
With ListeOrdres Do For i:=0 To Count-1 Do With PSurveille(Items[i])^ Do
Begin
// Libération Handle
If sHandle<>INVALID_HANDLE_VALUE Then FindCloseChangeNotification(sHandle);
// Libération
If Items[i]<>Nil Then Dispose(Items[i]);
// Suppression de la référence
ListeOrdres.Items[i]:=Nil;
End;
ListeOrdres.Free;
End;
// Cette procédure ne doit être appelée que par l'intermédiaire de Synchronize
Procedure TThreadSurveillance.MiseAJOurListeMessages;
Begin
Form1.lbMessages.Lines.AddStrings(ListeAjouts);
End;
// Cette procédure ne doit être appelée que par l'intermédiaire de Synchronize
Procedure TThreadSurveillance.MiseAJOurListeOrdres;
Var i:Integer;
Begin
Form1.lbOrdres.Items.Clear;
With ListeOrdres Do For i:=0 To Count-1 Do Form1.lbOrdres.Items.Add(PSurveille(Items[i]).sChemin);
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
OrdreAFAire:='+'+Edit1.Text;
End;
Procedure TForm1.Button2Click(Sender: TObject);
Begin
With lbOrdres Do If ItemIndex>=0
Then OrdreAFaire:='-'+Items[ItemIndex]
Else ShowMessage('Vous devez sélectionner un chemin dans la liste !');
End;
End.
|
| |
 |
|
 |
Les sources présentées sur cette page sont libres de droits,
et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation
constitue une oeuvre intellectuelle protégée par les droits d'auteurs. Copyright ©
2003 Bruno Guérangé. Aucune reproduction,
même partielle, ne peut être faite de ce site et de l'ensemble de son contenu :
textes, documents, images, etc sans l'autorisation expresse de l'auteur.
Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E
de dommages et intérêts.
Cette page est déposée à la
SACD.
|