IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

La programmation Win32 en Virtual Pascal avec OWL


précédentsommairesuivant

III. Création de petits programmes avec l'unité WinCRT

L'unité WinCRT permet d'utiliser une fenêtre Windows un peu comme un écran DOS; elle est toutefois très limitée et ne pourra raisonnablement servir que pour faire de tout petits programmes. Elle mérite cependant que nous nous y attardions un peu.

Il ne faut pas confondre la fenêtre générée par l'unité WinCRT avec la console de Windows ! Il ne s'agit nullement ici d'émulation de MS-DOS mais bien d'un programme Windows à part entière !

III-A. Déclarations

Voici la déclaration des variables, constantes et routines de l'unité WinCRT :

 
Sélectionnez
Const
  WindowOrg : tPoint = (X : cw_UseDefault; Y : cw_UseDefault);   
     (* Coordonnées de la fenêtre *)
  WindowSize : tPoint = (X : cw_UseDefault; Y : cw_UseDefault);  
     (* Taille de la fenêtre *)
  ScreenSize : tPoint = (X : 80; Y : 25);    
     (* Taille de l'écran virtuel en caractères *)
  Cursor : tPoint = (X : 0; Y : 0);          
     (* Coordonnées du curseur *)
  Origin : tPoint = (X : 0; Y : 0);          
     (* Coordonnées de la zone client de la fenêtre *)
  InactiveTitle : pChar = '(Inactive %s)';   
     (* Format du titre de la fenêtre inactive *)
  AutoTracking : Boolean = True;             
     (* Défilement automatique ? *)
  CheckEOF : Boolean = False;                
     (* Ctrl-Z marque la fin de fichier ? *)
  CheckBreak : Boolean = True;               
     (* Ctrl-C interrompt l'exécution ? *)

(* ---------- PROCEDURES ET FONCTIONS ---------- *)

Procedure InitWinCrt;
   (* Création de la fenêtre *)
Procedure DoneWinCrt;
   (* Destruction de la fenêtre *)

Procedure AssignCrt (var F : Text);
   (* Assigne un fichier texte à la fenêtre WinCRT (entrées/sorties) *)

Function KeyPressed : Boolean;
   (* Indique si une touche a été pressée *)
Function ReadKey : Char;
   (* Lecture d'un caractère sans écho *)
Function ReadBuf (Buffer : PChar; Count : Word) : Word;
   (* Lecture d'une chaîne - retourne le nombre de caractères *)

Procedure WriteBuf (Buffer : PChar; Count : Word);
   (* Ecriture d'une chaîne *)
Procedure WriteChar (Ch : Char);
   (* Ecriture d'un caractère - appelle WriteBuf en réalité *)

Procedure GotoXY (X, Y : Integer);
   (* Déplacement du curseur *)
Procedure CursorTo (X, Y : Integer);
   (* Déplacement du curseur *)
Procedure ScrollTo (X, Y : Integer);
   (* Défilement de la fenêtre - X et Y deviennent (0,0) *)
Function WhereX : Integer;
   (* Retourne l'abscisse du curseur *)
Function WhereY : Integer;
   (* Retourne l'ordonnée du curseur *)
Procedure TrackCursor;
   (* Défilement de la fenêtre pour rendre le curseur visible *)

Procedure ClrScr;
   (* Efface la fenêtre entière *)
Procedure ClrEol;
   (* Efface la ligne courante à partir de la position du curseur *)

Nous n'allons bien sûr pas passer chacune de ces routines en revue. Nous allons prendre un cas concret qui nous permettra d'utiliser les plus courantes d'entre elles. Par la même occasion, nous rencontrerons de nombreuses utilisations des procédures et fonctions de l'unité Strings.

III-B. Programme de démonstration : DIRTOT.PAS

Le programme DIRTOT affiche le nom de tous les fichiers .PAS contenus dans un dossier ainsi que dans ses sous-dossiers.
Une procédure récursive, appelée RECHERCHE_RECURSIVE, affiche le nom de tous les fichiers du dossier passé comme paramètre et s'exécute elle-même pour chacun des sous-dossiers rencontrés. A part l'utilisation de la récursivité, la structure générale du programme ne présente rien de particulier.

Voici le source du programme :

 
Sélectionnez
Program DIRTOT;

(* Démonstration des unités Strings et WinCRT.
   Recherche récursive et affichage du contenu d'une arborescence de dossiers.

   Réalisé par Alcatîz pour Developpez.com - 14-05-2006 *)

Uses WinCRT, Strings, Windows;

Const Masque = '\*.*';      
         (* Masque de nom de fichier à rechercher *)
      Extension = '.PAS';
         (* Extension des fichiers à rechercher *)

Var BufferChemin : Array [0..MAX_PATH] of Char;    
       (* Chaîne de construction d'un chemin *)

Procedure RECHERCHE_RECURSIVE (Dossier : pChar);
(* Procédure récursive de recherche de tous les fichiers dans un dossier *)
Var hRecherche : tHandle;
       (* Handle de la session de recherche *)
    FindData : tWin32FindData;
       (* Structure complétée par FindFirstFile *)
    NomDossier : pChar;
       (* Nom du dossier actuel sauvegardé sur le tas *)
    Chemin : pChar;
       (* Chemin complet de recherche sauvegardé sur le tas *)
    ContinuerRecherche : LongBool;
       (* Indique si la recherche peut être poursuivie *)
Begin
  WriteBuf(Dossier,StrLen(Dossier));
  WriteBuf(#10#13,2);
  // WriteLn(Dossier);
  NomDossier := StrNew(Dossier);   (* Sauvegarde du nom de dossier sur le tas *)
  StrCopy(BufferChemin,Dossier);
  StrCat(BufferChemin,Masque);
  Chemin := StrNew(BufferChemin);   (* Sauvegarde du chemin complet sur le tas *)
  hRecherche := FindFirstFile(Chemin,FindData);
  if hRecherche <> Invalid_Handle_Value
     then
       begin
         ContinuerRecherche := True;
         while ContinuerRecherche do
           begin
             if (FindData.dwFileAttributes and File_Attribute_Directory) <> 0
                then   (* Il s'agit d'un nom de dossier : récursion *)
                  begin
                    if FindData.cFileName[0] <> '.'
                       then
                         begin
                           StrCopy(BufferChemin,NomDossier);
                           if BufferChemin[StrLen(BufferChemin) - 1] <> '\'
                              then
                                StrCat(BufferChemin,'\');
                           StrCat(BufferChemin,FindData.cFileName);
                           (* Traitement du sous-dossier *)
                           RECHERCHE_RECURSIVE(BufferChemin);
                         end;
                  end
                else   (* Il s'agit d'un fichier : affichage de son nom *)
                  if StrPos(StrUpper(FindData.cFileName),Extension) <> Nil
                     then   
                       begin
                         CursorTo(3,Cursor.Y);
                         WriteBuf(FindData.cFileName,StrLen(FindData.cFileName));
                         WriteBuf(#10#13,2);
                         // WriteLn('   ',FindData.cFileName);
                         StrCopy(BufferChemin,NomDossier);
                         StrCat(BufferChemin,'\');
                         StrCat(BufferChemin,FindData.cFileName);
                       end;
             ContinuerRecherche := FindNextFile(hRecherche,FindData);
           end;
         FindClose(hRecherche);
       end;
  (* Désallocation des chaînes allouées dynamiquement *)
  if NomDossier <> Nil
     then
       StrDispose(NomDossier);
  if Chemin <> Nil
     then
       StrDispose(Chemin);
End;

(* ========== Programme principal ========== *)

BEGIN
  CheckBreak := False;
  ScreenSize.X := 128;
  StrCopy(WindowTitle,'D'#233'monstration de WinCRT et Strings');
  InitWinCRT;
  StrCopy(BufferChemin,'C:\');
  RECHERCHE_RECURSIVE(BufferChemin);
  WriteBuf(#10#13,2);  
  // WriteLn;
  WriteBuf('Pressez une touche : ',22);
  // Write('Pressez une touche : ');
  ReadKey;
  DoneWinCRT;
END.

III-B-1. Variables

Avant tout, il est utile d'expliquer la logique des déclarations de données dans notre programme.
Les variables locales d'une fonction sont réservées dans le segment de pile. Comme nous utilisons la récursivité, nous nous trouvons dans le cas où la fonction RECHERCHE_RECURSIVE va s'appeler elle-même, très probablement sur plusieurs niveaux (correspondant aux niveaux de l'arborescence des dossiers). A chaque appel, outre le dépôt des paramètres sur la pile, l'espace nécessaire aux variables locales est réservé. Par sécurité, pour éviter un éventuel débordement de pile (quoique peu probable), nous réduisons au strict minimum les variables locales et privilégions l'allocation de chaînes dynamiques dans le tas global (routines StrNew et StrDispose, voir ).

La seule variable globale est la chaîne qui va servir à construire les chemins tout au long de l'exécution du programme :

 
Sélectionnez
Var BufferChemin : Array [0..MAX_PATH] of Char;

Il s'agit d'une chaîne AZT dont la longueur doit être suffisante pour recevoir n'importe quel nom de chemin. La constante MAX_PATH, déclarée dans l'unité Windows (voir immédiatement après), correspond à cette taille maximale.

III-B-2. L'unité Windows

Outre les unités Strings et WinCRT, l'unité Windows est utilisée. Cette unité contient la grande majorité des déclarations de types, constantes, procédures et fonctions du SDK de Windows (Software Development Kit, kit de développement d'applications). Si vous avez programmé avec Borland Pascal for Windows, vous vous rappelez certainement que vous déclariez les unités WinTypes et WinProcs; eh bien, l'unité Windows de Virtual Pascal est en quelque sorte la réunion de ces deux unités.

Pourquoi déclarons-nous ici l'unité Windows ? Parce que nous avons besoin de fonctions de l'API :

  • FindFirstFile (recherche de la 1ère coccurence d'un fichier)
  • FindNextFile (recherche de l'occurence suivante)
  • FindClose (fermeture de la session de recherche)

Ces fonctions nécessitent un paramètre de type tWin32FindData, dont vous pouvez trouver tous les détails dans la documentation du SDK (structure WIN32_FIND_DATA).
Le principe est à peu près identique aux fonctions de recherche de fichiers de l'unité DOS de Turbo Pascal qui, elles, nécessitaient un paramètre de type SearchRec.

III-B-3. Initialisation de la fenêtre WinCRT

Au début du programme principal, nous assignons la variable CheckBreak à False, pour éviter que le programme puisse être interrompu par un Ctrl-Alt-Del ou un Ctrl-C. Ensuite, nous décidons d'élargir la fenêtre : 128 caractères au lieu des 80 par défaut. Pour cela, nous assignons 128 au champ X de la variable ScreenSize. Avant d'afficher la fenêtre, nous lui donnons un titre en assignant une chaîne à la variable WindowTitle à l'aide de la fonction StrCopy (voir ).
Une fois que tout est correctement initialisé, nous pouvons afficher la fenêtre à l'aide de la procédure InitWinCRT.

Immédiatement, la procédure RECHERCHE_RECURSIVE est appelée avec, comme paramètre, le dossier racine C:\.

III-B-4. La procédure récursive de recherche

III-B-3-a. Affichage du nom de dossier

La première chose que fait la procédure RECHERCHE_RECURSIVE est d'afficher le nom du dossier en cours, dont l'adresse, de type pChar, lui est passée comme paramètre. Pour afficher le nom de dossier à l'écran, nous utilisons la procédure WriteBuf :

 
Sélectionnez
  WriteBuf(Dossier,StrLen(Dossier));
  WriteBuf(#10#13,2);

Les paramètres de WriteBuf sont l'adresse de la chaîne à afficher ainsi que sa longueur, que nous déterminons à l'aide de la fonction StrLen (voir ). Comme vous le voyez également, pour passer à la ligne nous affichons un saut de ligne (#10) et un retour chariot (#13).

WriteBuf est une routine beaucoup moins sophistiquée que WriteLn et ne permet pas de profiter des mêmes possibilités (surtout, le nombre quelconque de paramètres). Mais son grand avantage est qu'elle est beaucoup plus rapide !

III-B-3-b. Allocation dynamique de chaînes

A l'intérieur de la procédure récursive, nous avons besoin de sauvegarder le nom de dossier actuel ainsi que le chemin de recherche complet. Comme nous l'avons dit en introduction, nous préférons l'allocation dynamique sur le tas à l'utilisation de variables locales. Plus exactement, ce ne sont pas les chaînes de caractères qui sont déclarées comme variables locales mais uniquement leur adresse, de type pChar.

 
Sélectionnez
  NomDossier := StrNew(Dossier);   (* Sauvegarde du nom de dossier sur le tas *)
  StrCopy(BufferChemin,Dossier);
  StrCat(BufferChemin,Masque);
  Chemin := StrNew(BufferChemin);   (* Sauvegarde du chemin complet sur le tas *)

La fonction StrNew alloue exactement l'espace nécessaire sur le tas et y copie la chaîne.

Pour construire le chemin complet de recherche, nous devons concaténer le nom de dossier courant et le masque du nom de fichier (dans ce programme, '*.PAS'). La concaténation de chaînes s'effectue à l'aide de la fonction StrCat (voir ).

III-B-4-c. Changement de position du curseur

Lorsqu'un fichier .PAS est trouvé, il est affiché à l'écran. Afin de produire un décalage, nous décidons de l'afficher à la colonne 3 :

 
Sélectionnez
  CursorTo(3,Cursor.Y);
  WriteBuf(FindData.cFileName,StrLen(FindData.cFileName));
  WriteBuf(#10#13,2);

La variable Cursor de l'unité WinCRT contient en permanence les coordonnées du curseur à l'écran. Il nous suffit donc de déplacer le curseur à la colonne 3 de la ligne courante, à l'aide de la procédure CursorTo.

Nous aurions pu ici utiliser le classique GotoXY au lieu de CursorTo. Mais la raison est identique à celle qui nous a fait préférer WriteBuf à WriteLn : CursorTo est plus rapide !

III-B-4-d. Libération des chaînes dynamiques

Très important, bien sûr : avant de se terminer, la procédure RECHERCHE_RECURSIVE doit libérer les chaînes qu'elle a allouées dans le tas :

 
Sélectionnez
  if NomDossier <> Nil
     then
       StrDispose(NomDossier);
  if Chemin <> Nil
     then
       StrDispose(Chemin);

Les détails de la procédure StrDispose se trouvent dans .

III-B-5. Terminaison du programme

A la toute dernière ligne du programme se trouve la procédure DoneWinCRT. Faites l'expérience de passer cette ligne en commentaire : lorsque le programme se termine, la fenêtre WinCRT n'est pas détruite :

Image non disponible

Le titre est changé en (Inactive ... ) et il faut fermer la fenêtre manuellement. DoneWinCRT est une manière plus propre de fermer la fenêtre WinCRT.

III-C. Téléchargement des sources des programmes de cette page


précédentsommairesuivant

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 œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2005-2007 Jean-Luc Gofflot. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.