Software">
[go: up one dir, main page]

0% ont trouvé ce document utile (0 vote)
142 vues40 pages

Annex 1

Télécharger au format doc, pdf ou txt
Télécharger au format doc, pdf ou txt
Télécharger au format doc, pdf ou txt
Vous êtes sur la page 1/ 40

ANNEXE 1

COMPLÉMENTS SUR DELPHI

 Complément sur les Listbox & les Scrollbar


 Trucs et astuces
 Création dynamique des composants
 Saisie, formatage et présentation des données
 Gérer les messages de Windows
360 Annexe 1 :Compléments sur Delphi

1- Compléments sur les Listbox

Un ListBox est aussi appelé, en français "Zone de liste". Il s'agit d'une liste
d'éléments que l'on peut faire défiler. L'utilisateur peut ajouter, supprimer ou
sélectionner un ou plusieurs éléments de la liste. Une zone de liste dispose de
plusieurs propriétés et méthodes dont nous allons décrire ci-dessous les plus
importantes:
 
ListBox: propriétés et méthodes

 Items
Items, contient l'ensemble des chaînes de caractères de la liste.

Définition:  property Items: TStrings;

Le type TStrings représente une liste de chaînes de caractères.


Exemple:

Liste1.Items.Add (Edit1.Text);

Items possède lui-même des propriétés et des méthodes (voir plus loin). Dans
l'exemple ci-dessus, Add est une méthode de Items permettant d'ajouter une
chaîne de caractères dans la liste existante Items. Dans la liste suivante, 'Vache',
'Cheval', … sont les chaînes de caractères contenues dans Items:
Annexe 1 : Compléments sur Delphi 361

 ItemIndex
La propriété ItemIndex indique le numéro d'ordre de l'élément sélectionné dans
la liste.
Définition:  property ItemIndex: Integer;

ItemIndex est utilisé aussi bien pour sélectionner un élément de la liste,


que pour connaître le numéro de l'élément sélectionné dans la liste au moment de
l’exécution du programme.
Pour sélectionner un élément de la liste, il faut attribuer à la propriété
ItemIndex la valeur désirée, correspondant au numéro d'ordre de l'élément dans la
liste. Le la valeur ItemIndex pour le premier élément est 0. Si aucun élément n'est
sélectionné, cette valeur est de -1.
Lorsque la propriété MultiSelect (voir ci-dessous) est vraie, la valeur
ItemIndex représente le numéro de l'élément qui a le "focus" parmi les éléments
sélectionnés. Si la propriété MultiSelect est vraie la valeur par défaut de ItemIndex
est 0.
Exemple:

Liste2.Items.Add(liste1.Items[Liste1.ItemIndex]);

Dans la liste précédente, la chaîne 'Chat' est l'élément numéro 3 de la liste.


Liste1.Items[Liste1.Itemindex] vaut 'Chat', et donc,
Liste1.Itemindex vaut 3

 MultiSelect
Lorsque cette propriété est vraie, il est possible de sélectionner plusieurs
élément de la liste en même temps.
Petit rappel: pour sélectionner plusieurs éléments d'une liste, il faut
cliquer avec la souris sur l'élément ou les éléments choisis et appuyer en
même temps les touches shift ou contrôle du clavier.

Définition :  property MultiSelect: Boolean;


362 Annexe 1 :Compléments sur Delphi

Exemple:

Liste1.MultiSelect := true;
 SelCount
La propriété SelCount permet de connaître le nombre d'éléments sélectionnés
dans la liste, si la propriété MultiSelect est vraie.

Définition:  property SelCount: Integer;


Cette propriété est consultable, mais n'est pas modifiable. Lorsque la
propriété MultiSelect et fausse, la propriété SelCount vaut toujours -1.

Exemple:

Res.Text := 'Il y a '+IntToStr(Liste1.SelCount)+


' éléments sélectionnés.';

Dans la liste suivante, Selcount vaut 4.

 Selected
La propriété Selected permet de déterminer ou de connaître quels éléments de
la liste sont sélectionnés. Il s'agit en fait d'un tableau de valeurs booléennes.
Définition:  property Selected[Index: Integer]: Boolean;
Cette propriété est très utile lorsque, par exemple, un traitement doit être
appliqué uniquement aux éléments sélectionnés d'une liste.

Exemple:

if Liste1.Selected[4] then…

Dans la liste suivante, Liste1.Selected[1] vaut true, alors que


Liste1.Selected[4] vaut false.
Annexe 1 : Compléments sur Delphi 363

 Sorted
La propriété Sorted indique si la liste doit être automatiquement triée
alphabétiquement.
Définition:  property Sorted: Boolean;
Exemple:

Liste1.Sorted := true;
 
 Clear
Cette méthode permet de vider toute la liste en une seule fois.

Définition:  procedure Clear;


 
 ItemAtPos
Cette méthode permet de connaître le numéro de l'élément situé à une
coordonnée spécifiée. Ceci peut être utile pour retrouver un élément de la liste qui
se trouve sous le curseur de la souris, par exemple.
Définition:  function ItemAtPos(Pos: TPoint; Existing:
Boolean): Integer;

Si Pos se trouve après le dernier élément de la liste, la valeur du


paramètre Existing détermine la valeur retournée par ItemAtPos:

- Si Existing est true, ItemAtPos retourne –1


- Si Existing est false, ItemAtPos retourne l'indice du dernier élément
de la liste, plus 1.
 
364 Annexe 1 :Compléments sur Delphi

Items: propriétés et méthodes

 Count
La propriété Count indique le nombre d'éléments actuellement contenus dans
une liste
Définition:  property Count: Integer;
Exemple:

vide := (Liste1.Items.Count = 0);

Dans la liste précédente, Count vaut 5:

 Strings
Cette propriété permet de spécifier une chaîne de caractères d'une liste
grâce à son indice.
Définition: property Strings[Index: Integer]: string;

Les deux lignes de l'exemple suivant sont équivalentes:


Exemple: 

Liste1.Items.Strings[0] := 'Ceci est la 1ère


chaîne';
Liste1.Items [0] := 'Ceci est la 1ère chaîne';
 
 Add
Cette méthode permet d'ajouter un élément à la fin d'une liste
Définition
function Add(const S: string): Integer; virtual;
Add retourne l'indice du nouvel élément placé dans la liste.
Annexe 1 : Compléments sur Delphi 365

Exemple:

Num := Liste1.Items.Add('Ligne ajoutée à la


liste');
Liste1.Items.Add ('Ligne aussi ajoutée à la
liste');
 

 AddStrings
Cette méthode permet d'ajouter une liste de chaîne de caractères dans la
liste courante.

Définition:
procedure AddStrings(Strings: TStrings); virtual;
Dans l'exemple suivant, tous les éléments de la liste Liste2 sont ajoutés en
une seule fois dans la liste Liste1:
Exemple:

Liste1.Items.AddStrings (Liste2.Items)
 
 Append
Cette méthode est équivalente à la méthode Add, sauf qu'elle ne retourne
pas l'indice du nouvel élément ajouté.
Définition:  procedure Append(const S: string);
Exemple:

Liste1.Items.Append ('Ligne ajoutée à la liste');


 
 Delete
Cette méthode permet de supprimer une chaîne de caractères de la liste
courante.
Définition: 
procedure Delete(Index: Integer); virtual; abstract;
Exemple:

Liste1.Items.Delete (2)
366 Annexe 1 :Compléments sur Delphi

Voici le résultat:
 

devient

 Exchange
Cette méthode permet de permuter deux éléments d'une liste en indiquant
leurs indices respectifs.

Définition: 
procedure Exchange(Index1, Index2: Integer); virtual;
Exemple:

Liste1.Items.Exchange (0, 3);

Voici le résultat:

devient

 Insert
Cette méthode permet d'insérer un élément à une position donnée dans la
liste courante.
Définition:
procedure Insert(Index: Integer; const S: string);
virtual; abstract;
Exemple:

Liste1.Items.Insert (3, 'Coq');


Voici le résultat:
Annexe 1 : Compléments sur Delphi 367

devient

 LoadFromFile
Cette méthode permet de placer dans la liste courante les lignes du fichier
texte passé comme paramètre.
Définition: 
procedure LoadFromFile(const FileName: string);
virtual;
L'exemple suivant permet d'afficher dans la liste Liste1 le contenu du
fichier c:\config.sys.
Exemple:

Liste1.Items.LoadFromFile ('c:\config.sys');
 
 Move
Cette méthode permet de déplacer un élément dans la liste courante.
Définition: 
procedure Move(CurIndex, NewIndex: Integer); virtual;
Exemple:

Liste1.Items.Move (0,3);

Voici le résultat:
 

devient

 SaveToFile
368 Annexe 1 :Compléments sur Delphi

Cette méthode permet d'enregistrer les éléments de la liste courante dans le


fichier texte passé comme paramètre.
Définition: 
procedure SaveToFile(const FileName: string); virtual;
Exemple:

Liste1.Items.SaveToFile ('c:\config.sys'):

2- Complément sur les ScrollBar


Un ScrollBar est aussi appelé, en français "barre de défilement". Il s'agit
d'une barre avec un curseur. L'utilisateur peut déplacer le curseur de plusieurs
manières.
Ci-dessous sont présentées les propriétés et les méthodes les plus
importantes:
 
ScrollBars: propriétés et méthodes
 Kind
Kind est une propriété qui détermine si un ScrollBar est vertical ou
horizontal.
Définition : property Kind: TScrollBarKind;
Deux constantes sont prédéfinies: sbHorizontal et sbVertical.
Exemple :

Scroll1.Kind := sbVertical;
 

 Min
Cette propriété permet de définir la valeur entière correspondant à la
position minimale du ScrollBar.
Définition:  property Min: Integer;
 
 Max
Cette propriété permet de définir la valeur entière correspondant à la
position maximale du ScrollBar.
Définition :  property Max: Integer;
 
Annexe 1 : Compléments sur Delphi 369

 Position
Cette propriété permet de fixer ou de connaître la position actuelle du
ScrollBar
Définition :  property Position: Integer;
Exemple :

Form1.Color := RGB (0, 0, Scroll1.Position);


 
 SmallChange
Cette propriété détermine de combien la Position du ScrollBar change
quand on clique sur les flèches du ScrollBar ou quand on appuie sur les flèches du
clavier.
Définition : 
TscrollBarInc = 1..32767; property SmallChange:
TScrollBarInc;
 
 LargeChange
Cette propriété détermine de combien la Position du ScrollBar change
quand on clique au-dessus ou au-dessous de l'"ascenseur du ScrollBar ou quand
on appuie sur les touches PgUp ou PgDn du clavier.
Définition : 
TScrollBarInc = 1..32767; property LargeChange:
TScrollBarInc;
 
 SetParams
Cette méthode permet de spécifier en une seule fois les valeur Min et Max
d'un ScrollBar.
Définition : 
procedure SetParams(APosition, AMax, AMin: Integer);
Exemple :

Scroll1.SetParams (0, 200);


370 Annexe 1 :Compléments sur Delphi

3- Trucs & astuces


Dans ce paragraphe seront regroupés un certain nombre de trucs et astuces
pour Delphi.

 Avoir accès, dans l'environnement de développement à un composant


caché par un autre
Lorsque que vous avez un composant en AlClient dans une fenêtre d'un
autre composant ex: une Image dans un Panel lui même dans une Form, il est
impossible de cliquer sur le panel pour avoir accès à ses propriétés dans
l'inspecteur d'objet car c'est l'image que vous sélectionnez et non le panel.
Astuce: Après avoir cliqué sur l'image, appuyez sur la touche Echap (Esc) vous
vous retrouvez avec les propriétés du Panel dans l'inspecteur d'objet. Si vous
recommencez, vous vous retrouvez avec les propriétés de la Form. En réalité,
Echap fait basculer vers le composant parent de celui précédemment sélectionné.

 Mettre un panel sous un composant déjà en place sur la Form


Astuce:Cliquez sur le composants, faire couper (Ctrl+X) puis cliquez sur le Panel
et faire coller (Ctrl+V).

 Comment placer des marques (des signets) dans un source pour


pouvoir y revenir ultérieurement :
vous êtes sur un bout de source et vous vous aller voir ailleurs dans l'unité
et revenir rapidement :
Astuce
- tapez : CTRL+SHIFT+1 (ou un chiffre de 1 a 9 au dessus des lettres)
l'éditeur met un "1" dans la marge.
- pour revenir vous faite CTRL+1
- pour annuler la marque, soit vous vous placez sur la ligne et vous refaite
CTRL+SHIFT+1 soit vous vous placez ailleurs et vous refaite
CTRL+SHIFT+1 ( déplace la marque)

 Comment faire appel aux modèles de code :


Astuce : De Christophe Dassise : utilisez le raccourci Ctrl+j
Nota : les modèles de code permettent d'écrire du code "tout fait" par exemple: en
choisissant le modèle de code if then else après avoir fait Crtl+j, on obtient

if then
begin

end
Annexe 1 : Compléments sur Delphi 371

else
begin
end;

Autre astuce : chaque modèle de code possède une abréviation. Tapez cette
abréviation puis Crtl+j. Tapez par exemple ifeb puis Crtl+j. Les lignes
correspondant à if then else s'écrivent à votre place. Les abréviations
disponibles sont visibles en faisant Crtl+j.

 Comment indenter plusieurs lignes à la fois


Comment passer de

begin

if X>0 then x=0;


if X<0 then x=-1;

A:=truc+machintruc;

end;

begin
if X>0 then x=0;
if X<0 then x=-1;
A:=truc+machintruc;
end;

Sans le faire ligne par ligne ?

Astuce : Sélectionnez les lignes puis faire Ctrl+Maj+i pour déplacer les lignes
vers la droite ou Ctrl+Maj+u pour les déplacer vers la gauche.

 Comment positionner ou dimensionner au pixel près un composant


Astuce :A la conception des fiches, il n'est pas inutile de rappeler que l'on peut
positionner ou dimensionner au pixel près un composant en utilisant
Maj+<touche flèchée> et Ctrl+<touche fléchée>
372 Annexe 1 :Compléments sur Delphi

 Comment dans l'éditeur de code (= l'éditeur dans lequel vous rentrez le


programme) stocker en mémoire une chaîne de caractères afin de pouvoir
vous en servir plus tard ?

Astuce : Faire Maj+Ctrl+R puis tapez vos caractères puis de nouveau


Maj+Ctrl+R.
Vous pouvez inclure dans votre chaîne des combinaisons de touches du
style Ctrl+F ou F9
Pour utiliser cette chaîne : faire Maj+Ctrl+P. Une fois mémorisé, on peut
s'en servir autant de fois que l'on veut.
Alors, on met 'begin' ou 'end' dans la chaîne ? (Bon d'accord,
'end' c'est trois touches et Maj+Ctrl+P aussi.. je vous fait confiance pour
trouver une meilleure utilisation).

 Dans un TEdit : comment empêcher le beep lorsque l'on appuie sur la


touche entrée ?
Tout simplement en créant une réponse à l'événement OnKeyPressed du
TEdit faisant croire que la touche #13 (= entrée) est la touche #0 :

procedure TForm1.Edit1KeyPress(Sender: TObject;


var Key: Char);
begin
if key=#13 then key:=#0;
end;

 Dans un TEdit : comment empêcher l'entrée de certaines touches, par


exemple n'autoriser que les valeurs numériques?
Tout simplement en créant une réponse à l'événement OnKeyPressed du
TEdit faisant croire que les touches non souhaitées ont la valeur #0 :

procedure TForm1.Edit1KeyPress(Sender: TObject;


var Key: Char);
begin
if not (key in [#8,'0'..'9',DecimalSeparator,
'+','-']) then key:=#0;
end;
Annexe 1 : Compléments sur Delphi 373

 Comment voir si l'utilisateur appuie sur une touche de direction ou


une touche de fonction sur une fenêtre ou un composant :

Dans l'événement OnKeyDown de votre composant ou votre TForm mettre le


code suivant:

procedure TForm1.FormKeyDown(Sender: TObject; var


Key: Word; Shift: TShiftState);
begin
if Key=VK_LEFT then
begin
{ici vous mettez le traitement à faire}
end;
end;

Si vous voulez également intercepter dans l'événement OnKeyDown d'une form


tous les événements clavier destinés aux composants situés sur cette form, il faut
mettre sa propriété KeyPreview à true.
Liste des valeurs possibles pour Key: (merci Raphaël Létocart pour cette liste)

VK_LBUTTON : bouton Gauche Souris


VK_RBUTTON : bouton Droite Souris
VK_MBUTTON : bouton Central Souris
VK_CANCEL : Arrêt Exec. programme
VK_BACK : Retour Arrière
VK_TAB : Tabulation
VK_RETURN : Entrée
VK_SHIFT : Touche de contrôle MAJ
VK_CONTROL : Touche de contrôle CTRL
VK_MENU : Touche de contrôle ALT
VK_PAUSE : Pause
VK_ESCAPE : Echappement
VK_SPACE : Barre d'espacement
VK_PRIOR : Page Haut
VK_NEXT : Page Bas
VK_END : Fin
VK_HOME : Début
VK_LEFT : Flèche gauche
VK_UP : Flèche haut
374 Annexe 1 :Compléments sur Delphi

VK_RIGHT : Flèche droite


VK_DOWN : Flèche bas
VK_SNAPSHOT : Impression d'écran
VK_INSERT : Insérer
VK_DELETE : Supprimer
VK_HELP : Aide
VK_NUMPAD0..VK_NUMPAD9 : Touche pavé numérique 0 à 9
VK_MULTIPLY : Touche pavé numérique *
VK_ADD : Touche pavé numérique +
VK_SEPARATOR : Touche pavé numérique Entrée
VK_SUBTRACT : Touche pavé numérique -
VK_DECIMAL : Touche pavé numérique . (décimal)
VK_DIVIDE : Touche pavé numérique /
VK_F1..VK_F12 : Touches de fonction F1 à F12
VK_NUMLOCK : Verrouillage pavé numérique
VK_SCROLL : Verrouillage scrolling
VK_CAPITAL : Verrouillage majuscules

Remarque
S'il existe des composants fenêtrés sur la fiche (boutons par exemple), les
touches fléchées ne peuvent pas être interceptées en positionnant simplement
KeyPreview à true. Si par exemple je veux dessiner sur une paintbox à l'aide
des touches fléchées, ce sont les boutons qui reçoivent systématiquement les
messages des touches de direction, ainsi que ceux produits par <Tab>. Voici
une solution :

Implémentez l'événement OnCreate de votre TForm ainsi :

procedure TForm1.FormCreate(Sender: TObject);


var
bmp : Tbitmap;
i : integer;
begin
Application.OnMessage := TraiteMessages;
......  

dans la déclaration de la Tform, juste sous

procedure FormCreate(Sender: TObject);


Annexe 1 : Compléments sur Delphi 375

Ajoutez :

procedure TraiteMessages(Var msg : TMsg; Var


Handled: boolean);
{ Gestionnaire de message au niveau application }

Puis dans la partie implémentation :

{ Intercepte les messages clavier et en


particulier les touches flèchées }
Procedure Tform1.TraiteMessages(Var msg : TMsg;
Var Handled: boolean);
var
dx, dy : integer;
begin   dx: 0; dy := 0;
With msg do
begin
IF Message = WM_KEYDOWN then
Case  wparam of
VK_LEFT  : dx := -1;
VK_RIGHT : dx :=  1;
VK_UP    : dy := -1;
VK_DOWN  : dy :=  1;
end;
end;
IF (dy = 0) AND (Dx = 0) then Handled := false
else
begin
handled := true;     // message traité
Mouvement(dx, dy)    // exécution du tracé
end;
end;

 Comment voir les fonctions qui sont dans une DLL (et un tas d'autres
renseignements)
Tout simplement à l'aide de l’apperçu rapide de windows 95 ou 98 : Dans
l'explorateur de windows, cliquez sur votre fichier DLL avec le bouton droit de la
souris et choisissez apperçu rapide. Vous pouvez faire la même manip sur les
fichiers .exe.
376 Annexe 1 :Compléments sur Delphi

 Comment connaître les modules (.DLL...) utilisés par votre programme


Dans Delphi, lancez votre programme (F9) puis allez dans Voir / Fenêtres
de déboguage / Modules. La fenêtre contient les modules en cours d'utilisation
par votre application.
Une astuce de JP Bouret : comment, pour un ComboBox, avoir directement
la liste déroulante en position déroulée
Dans mes programmes de compta, j'utilise souvent le ComboBox et comme
les données sont entrées au clavier il est intéressant lors de la tabulation sur le
ComboBox d'avoir la liste déroulante sans avoir à utiliser la souris pour cliquer
sur le bouton. J'ai regardé dans la VCL et j'ai trouvé une propriété non publiée qui
est bien utile. J'ai simplement ajouté dans l'événement OnEnter :
MonComboBox.DroppedDown:= true;

 Comment écrire dans une caption sur plusieurs lignes

Utilisez le caracrère #13 (retour chariot) :

Label1.Caption:='première ligne' + #13 +


'deuxième ligne';

 Simuler la fonction SendKey de Visual Basic


Récupérez sur votre CD de Delphi le fichier Sndkey32.pas qui se trouve dans
le dossier Info\Extras\Sendkeys

 Simuler la fonction DELAY


Utilisez la fonction Sleep(nombre_de_millisecondes);

 Récupérer les paramètres passés à notre application

for I := 1 to ParamCount do
ShowMessage(ParamStr(I));
Annexe 1 : Compléments sur Delphi 377

4- Erreurs de compilation  !!!!!!!


Ce paragraphe a pour but de vous aider à comprendre les différentes
erreurs de compilation que Delphi annonce lors de la compilation qui ne sont pas
décrites dans l'aide en ligne (ou mal). Chaque titre de paragraphe (en bleu)
correspond au texte de l'erreur que Delphi indique en bas de la fenêtre du code
source. En rouge correspondent les lignes impliquées dans l'erreur.
Le type (TYPE) nécessite une finalisation - non autorisé dans type fichier.
(par Romain)
Cette erreur n'est pas expliquée dans l'aide. Voici un exemple de code où
elle surviendrait:

type
TPersonne = record
Nom: string;
Prenom: string;
Age: integer;
end;

procedure SauverUnePersonne(NomDuFichier: string;


var PersonneASauver: TPersonne);
var Fichier: file of TPersonne;
begin
AssignFile(Fichier, NomDuFichier);
Rewrite(Fichier);
Writeln(Fichier, PersonneASauver);
CloseFile(Fichier);
end;

Explication:
Les String de Delphi 32 sont de 2 types: les chaînes longues et les
chaînes... courtes. La taille des chaînes courtes est définie par l'utilisateur dans le
source, le programme, mais si cette taille est indéfinie, le string devient une
chaîne longue. Le fait de ne pas définir la taille de ce string provoque une erreur
lors de sa sauvegarde dans un fichier de type "file of string" (ou, comme
dans notre exemple, "file of record" si le record en question contient une
chaîne longue), car le programme ne sait pas où se termine la chaîne (et peut
déborder sur la mémoire). Pour l'ouverture d'un fichier, c'est encore pire: on
déborde du fichier (théoriquement; mais Delphi empêche ce débordement). Delphi
génère un message d'erreur à la compilation pour empêcher ce genre de problème.
378 Annexe 1 :Compléments sur Delphi

Le fait de définir la taille du string pour le transformer en chaîne courte


crée une finalisation au string (ou au record si le string est contenu dans un
enregistrement), d'où le texte du message d'erreur, qui indique une absence de
cette finalisation.
Afin de définir cette finalisation, il faut mettre la taille du string entre
crochets juste après le mot string. Un nom et un prénom ne contiennent
rarement plus de 20 lettres, on va donc définir une taille de 20 caractères pour
chaque string de l'enregistrement (record). Voici le programme corrigé:

type
TPersonne = record
Nom: string[20];
Prenom: string[20];
Age: integer;
end;

procedure SauverUnePersonne(NomDuFichier: string;


var PersonneASauver: TPersonne);
var Fichier: file of TPersonne;
begin
AssignFile(Fichier, NomDuFichier);
Rewrite(Fichier);
Writeln(Fichier, PersonneASauver);
CloseFile(Fichier);
end;

Et voilà, ça marche!

Type de fichier non autorisé ici.


Cette erreur n'est pas non plus expliquée dans l'aide. Voici un exemple de
code où elle surviendrait:

interface
procedure Enregistrer(fic: textfile);

implementation
procedure Enregistrer(fic: textfile);
begin

end;
Annexe 1 : Compléments sur Delphi 379

Explication:
Vous avez oublié de mettre var devant la déclaration de variable. En
effet, de toute façon vous ne pouvez pas utiliser une variable de type fichier dans
une procedure sans le var. Voici la correction:

interface
procedure Enregistrer(var fic: textfile);

implementation
procedure Enregistrer(var fic: textfile);
begin
end;

5- Création dynamique de composants


Avec Delphi il est possible de créer des composants au moment de
l'exécution d'une application, par opposition à les placer sur une fiche au moment
de la conception de l'application. Avant d'aborder cette possibilité, il convient de
préciser deux concepts importants de Windows:
 propriétaire
 parent

Un composant Windows possède généralement un propriétaire et un parent,


pas nécessairement disjoints. Par exemple, une fiche peut être à la fois le
propriétaire d'un bouton placer sur elle et son parent. De même, si une fiche
contient un GroupBox, dans lequel on a placé un bouton, le GroupBox est le
parent du bouton, mais le propriétaire du bouton est la fiche.
En principe, chaque objet doit avoir un parent, alors qu'il n'est pas
indispensable qu'il ait un propriétaire.

 Le propriétaire:
- Est chargé de gérer l'allocation mémoire d'un composant
- Doit, lorsqu'il est supprimé, libérer la place mémoire occupée par les
composants qu'il possède
- Possède une propriété Components, tableau dynamique des composants
qu'il contient. ComponentCount indique le nombre de composants et
chaque composant a un numéro d'ordre donné par ComponentIndex.
380 Annexe 1 :Compléments sur Delphi

 Le parent
- Est un attribut inhérent à Windows
- Détermine comment est affiché un composant fils.
- Est automatiquement attribué lors de la conception d'une application. Il doit
être spécifié lors de la création dynamique de composants.

La création dynamique de composant comprend les points suivants:

- Appel à la méthode Create en spécifiant le propriétaire du composant à


créer
- Indication du parent
- Spécification des propriétés et méthodes du nouveau composant.

Exemple de création dynamique de composant

Nous pouvons, par exemple, créer une fiche possédant un bouton (appelé
Go). Lorsque l'utilisateur clique sur le bouton, l'application doit créer une boîte de
texte (appelée dyna) contenant le mot 'OK'. De plus quand l'utilisateur tape le
mot 'Fin' dans la boîte de texte, l'application doit se terminer.

Voici comment procéder:

 Créer une fiche ayant l'aspect suivant

 Déclarer la méthode suivante en réponse au clic sur le bouton:


procedure Tdynamique.GoClick(Sender: TObject);
begin
dyna := TEdit.Create (Self);
with dyna do begin
dyna.parent := Self;
Annexe 1 : Compléments sur Delphi 381

dyna.left := 100;
dyna.top := 50;
dyna.text := 'OK';
dyna.OnChange := clique;
end;
end;

 Déclarer le composant dyna et la méthode clique dans la partie privée des


déclarations de la fiche:

type
Tdynamique = class(TForm)
Go: TButton;
procedure GoClick(Sender: TObject);
private
{ Déclarations privées }
dyna : TEdit;
procedure clique (Sender: TObject);
public
{ Déclarations publiques }
end;

 Ecrire le code de la méthode clique, en mimant Delphi:


procedure Tdynamique.clique (Sender: TObject);
begin
if (Sender as TEdit).text = 'Fin' then
Application.terminate;
end;

Voici comment se présente la fiche après avoir cliqué sur le bouton:


382 Annexe 1 :Compléments sur Delphi

On voit qu'il est très facile de créer dynamiquement des composants et de


leur affecter des propriétés et, surtout, des méthodes

6- Saisie, formatage et présentation des données


On est souvent amené, lors du développement d'un programme, à effectuer
des tests pour lesquels on doit saisir ou afficher des informations. Plusieurs
possibilités sont offertes par Delphi dans ce but. De plus, on aimerait parfois
afficher des informations formatées d'une certaine manière. Là aussi Delphi
dispose de routines prenant en charge l'aspect des informations présentées à
l'utilisateur.

 Affichage d'informations sur une fiche


Le moyen le plus simple pour afficher des informations sur une fiche est de les
écrire directement sur le "Canvas" de la fiche. Canvas est une propriété des
plusieurs objets ou composants de Delphi. Le canvas représente la surface de
l'objet sur laquelle on peut dessiner. Dans ce cas, c'est sur le bitmap sous-jacent
que le dessin est reporté. Canvas est un objet d'une très grande importance dans la
programmation Windows, car Delphi y a encapsulé tout le système de dessin de
Windows. Ainsi, une fiche ou un composant de type Timage possèdent une
propriété Canvas accessible au moment de l'exécution. En revanche Delphi ne
propose pas, par exemple, directement de propriété Canvas pour un bouton ou un
label.
Pour afficher une information de type chaîne de caractère sur une fiche on peut
utiliser la méthode TextOut de l 'objet Canvas:

canvas.textout (20, 50, 'Texte à afficher');

Le texte s'affiche à partir du point de coordonnées (20,50).

Pour afficher des informations numériques ou mixtes il est possible de faire


appel aux diverses routines de conversion fournies par Delphi. Par exemple:

canvas.textout (20, 50, '4*3=' + inttostr(4*3));

ou encore

canvas.textout(20,50,'4*3.5='+floattostr(4*3.5));
Annexe 1 : Compléments sur Delphi 383

 Affichage d'information avec MessageDlg


Si l'on ne désire pas encombrer une fiche, il est possible d'afficher des
informations par une boîte de message. Deux variantes existent: la version
simplifiée de Delphi ou la version complète de l'API de Windows.
 
Utilisation de MessageDlg
La syntaxe de cette fonction est la suivante:

function MessageDlg(const Msg: string; AType:


TMsgDlgType; AButtons: TMsgDlgButtons; HelpCtx:
Longint): Word;

La fonction MessageDlg affiche une boîte de message au centre de


l'écran. La boîte de message affiche la valeur du paramètre Msg
.
Le paramètre AType détermine le type utilisé de boîte de message. Les
valeurs possibles sont :

Valeur Signification
Une boîte de message contenant un signe point d’exclamation
mtWarning
jaune.
mtError Une boîte de massage contenant un signe de stop rouge
mtlnformation Une boîte de message contenant un « l » bleu
mtConfimation Une boîte de message contenant un point d’interrogation vert
Une boîte de message ne contenant pas d’image. Le titre de la
mtCustom boîte de dialogue est le nom du fichier exécutable de
l’application.

Le paramétere AButton détermine les boutons apparaissant dans la boîte


de message. AButtons est de type TMsgDlgBtns, qui est un ensemble, il est
donc possible d'inclure plusieurs boutons dans l'ensemble. Les valeurs qu'il est
possible d'inclure dans l'ensemble sont :

Valeur Signification
mbyes Un bouton avec une marque verte et le texte ‘oui’
mbNo Un bouton avec un cercle rouge barré et le texte ‘non’
mbOk Un bouton avec une marque verte et le texte ‘ok’
mbCancel Un bouton avec un X rouge et le texte ‘annuler’.
mbHelp Un bouton avec un point d’interrogation cyan et le texte ‘ aide ’
mbAbort Un bouton avec une marque rouge et le texte ‘abandonner’
384 Annexe 1 :Compléments sur Delphi

Valeur Signification
Un bouton avec deux flèches circulaires vertes et le texte
mbRetry
‘réessayer’.
mbIgnore Un bouton avec un bonhomme vert marchant et le texte ‘lgnore’
mbAll Un bouton avec une double marque verte et le texte ‘tous’

Outre les valeurs individuelles de l'ensemble, Delphi définit trois


ensembles correspondant aux combinaisons les plus courantes :

Valeur Signification
Un ensemble plaçant les boutons oui, non et annuler dans la
mbYesNoCancel
boîte de message
Un ensemble plaçant les boutons Abandonner Réessayer et
mbOkCancel
Ignorer dans la boîte de message
MbAbortRetryIgn Un ensemble plaçant les Abandons, Réessayer et lgnorer dans la
ore boîte de message.

Lors de la spécification de ces constantes, il ne faut pas oublier d'utiliser


les crochets [ ], car constituent des ensembles prédéfinis.

Le paramètre HelpCtx détermine la rubrique d'aide utilisée pour la boîte


de message. Si on ne désire pas d'aide il suffit d'indiquer la valeur 0.
La fonction MessageDlg renvoie la valeur du bouton sélectionné par
l'utilisateur. Les valeurs renvoyées possibles sont :

mrNone mrAbort mrYes mrOk mrRetry


mrNo mrCancel mrIgnore mrAll

Par exemple, le code suivant:

if MessageDlg('Voulez-vous quitter?',
mtInformation, [mbYes, mbNo], 0) = mrYes then
Application.terminate;
Annexe 1 : Compléments sur Delphi 385

Provoque l'affichage de la boîte de message

La fonction MessageDlg affiche la boîte de message au centre de l'écran.


Si l'on désire l'afficher à une position donnée on peut faire appel à la fonction
MessageDlgPos, dont la syntaxe est la suivante:

function MessageDlgPos(const Msg: string; AType:


TMsgDlgType; AButtons: TMsgDlgButtons; HelpCtx:
Longint; X, Y: Integer): Word;

Qui ne se différentie de MessageDlg que par les deux paramètres


supplémentaires indiquant la position.

Utilisation de MessageBox
La fonction MessageBox est une méthode de Tapplication qui
encapsule la fonction MessageBox de l'API de Windows. Elle est plus souple
que MessageDlg. Sa syntaxe est la suivante:

function MessageBox(Text, Caption: PChar; Flags:


Word): Integer;

La méthode MessageBox affiche une boîte de dialogue générique indiquant


un message et un ou plusieurs boutons. La valeur du paramètre Text indique le
message (qui peut dépasser les 255 caractères). Les passages à la ligne sont
automatiques. La valeur de la propriété Caption indique le texte apparaissant
dans la barre de titre de la boîte de dialogue.

Le paramètre correspondant à Flags détermine les boutons apparaissant dans


la boîte de message et son comportement. Les valeurs peuvent être combinées
pour obtenir l'effet voulu.
386 Annexe 1 :Compléments sur Delphi

La méthode MessageBox renvoie 0 s'il n'y a pas assez de mémoire pour créer
la boîte de message ou les valeurs suivantes sinon:

Constante Valeur Signification


IDABORT 3 L’utilisateur a choisi le bouton Abandonner
IDCANCEL 2 L’utilisateur a choisi le bouton Annuler
IDIGNORE 5 L’utilisateur a choisi le bouton ignorer
IDNO 7 L’utilisateur a choisi le bouton Non.
IDOK 1 L’utilisateur a choisi le bouton OK
IDRETRY 4 L’utilisateur a choisi le bouton Réessayer
IDYES 6 L’utilisateur a choisi le bouton Oui
Le paramètre Flags peut prendre beaucoup de valeurs dont la plupart des
constantes correspondantes ont un nom explicite. La liste qui suit ne spécifie donc
que les constantes et non la signification. Pour plus de renseignements il faut
chercher "MessageBox" dans l'aide de Delphi.

MB_ABORTRETRYIGNORE
MB_APPLMODAL
MB_DEFAULT_DESKTOP_ONLY
MB_DEFBUTTON1
MB_DEFBUTTON2
MB_DEFBUTTON3
MB_DEFBUTTON4
MB_HELP
MB_ICONASTERISK
MB_ICONERROR
MB_ICONEXCLAMATION
MB_ICONHAND
MB_ICONINFORMATION
MB_ICONQUESTION
MB_ICONSTOP
MB_ICONWARNING
MB_OK
MB_OKCANCEL
MB_RETRYCANCEL
MB_RIGHT
MB_RTLREADING
MB_SERVICE_NOTIFICATION
MB_SETFOREGROUND
MB_SYSTEMMODAL
Annexe 1 : Compléments sur Delphi 387

MB_TASKMODAL
MB_YESNO
MB_YESNOCANCEL

Saisie d'information à l'aide de la fonction InputBox


Chaque fois que l'on veut saisir une donnée numérique ou non dans une
application sans toutefois vouloir utiliser une boîte de texte de type Tedit, on peut
faire appel à la fonction InputBox dont voici la syntaxe:

function InputBox(const ACaption, APrompt,


ADefault: string): string;

Où Acaption est le titre de la boîte de saisie, Aprompt est le libellé de la


question posée et Adefault est la valeur par défaut proposée. A noter que la
valeur saisie est de type chaîne de caractères. Pour saisir une valeur numérique il
faut prendre soin d'effectuer les conversions nécessaires.
Voici un exemple:

procedure TForm1.Button1Click(Sender: TObject);


var age : integer;
begin
age := 66;
age := strtoint (InputBox ('Sondage', 'Votre
âge:',inttostr (age)));
end;

Voici la boîte de saisie affichée par ce fragment de code:


388 Annexe 1 :Compléments sur Delphi

Dans les cas où il est indispensable de savoir si l'utilisateur à choisi OK ou


Annuler l'utilisation de la fonction analogue InputQuery s'avère plus adéquate. En
voici la syntaxe:

function InputQuery(const ACaption, APrompt:


string; var Value: string): Boolean;

La fonction InputQuery renvoie True si l'utilisateur a choisi OK et False


si l'utilisateur a choisi Annuler ou appuyé sur la touche <Esc>. La valeur saisie est
récupérée à l'aide du paramètre Value.

Formatage des données de type réel


Il est parfois nécessaire de mettre en forme des informations de différents
types
Voyons, par exemple, avec plus de détails la fonction FormatFloat
dont la déclaration est la suivante:

function FormatFloat(const Format: string; Value:


Extended): string;

Cette fonction permet de choisir le format du paramètre Value en utilisant


la chaîne de caractères Format. Les spécificateurs de format suivants sont
reconnus dans la chaîne de caractères Format :

Spécificateur. Signification
Indique l’emplacement d’un chiffre. Un zéro apparaît si la
o
valeur n’a pas de chiffre à cet emplacement.
Indique l’emplacement d’un chiffre. Rien n’apparaît si la valeur
#
formatée n’a pas de chiffre à cet emplacement.
Indique le séparateur décimal. Le premier caractère. Dans la
. chaîne de format détermine l’emplacement du séparateur
décimal dans la valeur formatée.
Indique le séparateur des milliers, si le spécificateur contient un
’ ou plusieurs’' un séparateur des milliers sera inséré entre chaque
groupe de trois chiffres situés à gauche de la virgule.
E+ Indique la notation scientifique. Si l’une des quatre chaînes de
caractères E+, E-, e+, ou e-, est contenue dans la chaîne de
format, le nombre est formaté en utilisant la notation
scientifique. Un groupe de quatre caractères ‘0’ au plus peut
immédiatement suivre la chaîne ‘E+’, E-, e+, ou e-, afin de
Annexe 1 : Compléments sur Delphi 389

Spécificateur. Signification
déterminer le nombre de chiffres de l’exposant..
Les caractères compris entre des guillemets ou apostrophes sont
XX / XX
affichés tels quel.

Remarques:
- Les nombres formatés sont arrondis en fonction du nombre de décimales
du spécificateur de format.
- Si on ne spécifie pas assez de chiffres à gauche de la virgule, les chiffres
en trop sont tout de même affichés.
- La chaîne de format peut contenir une, deux ou trois sections séparées par
des points-virgule pour différencier le format des valeurs positives,
négatives et nulles. S'il y a une seule section, celle-ci s'applique à toutes les
valeurs. S'il y a deux sections, la première s'applique aux valeurs positives
et nulles et la deuxième aux valeurs négatives. S'il y a trois sections, la
première s'applique aux valeurs positives, la deuxième aux valeurs
négatives, et la troisième aux valeurs nulles.

Voici quelques exemples tirés de l'aide de Delphi permettant de mieux


comprendre les diverses possibilités de format.

Spécificateur 1234 -1234 0.5 0


0 1234 -1234 1 0
0.00 1234.00 -1234.00 0.50 0.00
#.## 1234 -1234 .5
#,##0.00 1,234.00 -1,234.00 0.50 0.00
#,##0 ;(#,##0.00) 1,234.00 (1,234.00) 0.50 0.00
#,##0.00; ;zero 1,234.00 -1,234.00 0.50 Zero
0.000 E+00 1.234 E+03 -1,234 E+03 5.000 E-01 0.000E+00
#.### E-0 1.234 E3 -1.234 E3 5 E-1 0E0
390 Annexe 1 :Compléments sur Delphi

Formatage des données à l'aide de la fonction Format


Plusieurs routines permettent d'obtenir une chaîne de caractères formatée:
Format, FormatBuf, FmtStr, StrFmt et StrLfmt. Nous décrivons
uniquement la fonction Format dont voici la déclaration:

function Format(const Format: string; const Args:


array of const): string;

Cette fonction formate une série d'arguments contenus dans le tableau


ouvert Args. Le formatage est géré par la chaîne de caractères Format . La
fonction retourne une chaîne de caractères formatée. La chaîne de caractères
Format peut contenir des caractères simples et/ou des spécificateurs de format.
La syntaxe d'un spécificateur de format est la suivante:

"%" [index ":"] ["-"] [width] ["." prec] type

Le spécificateur de format commence par %, puis est suivi de:


- Le spécificateur d'indice de l'argument, [index ":"] (facultatif)
- L'indicateur d'alignement à gauche, ["-"] (facultatif)
- Le spécificateur de taille, [width] (facultatif)
- Le spécificateur de précision, ["." prec] (facultatif)
- Le caractère de type de conversion.

Le caractère indiquant le type de conversion peut prendre diverses valeurs


que l'on retrouve d'ailleurs en partie dans le langage C. Voici les caractères
utilisables:

Valeur Signification
Décimal : L’argument doit être une valeur entière. La valeur est
D
convertie en une chaîne de chiffres décimaux.
Scientifique : L’argument doit être une valeur réelle qui est convertie en
E
une chaîne de caractères de la forme ‘’-d.ddd… E+ddd.
Fixe : l’argument doit être une valeur réelle. La valeur est convertie en
une chaîne de caractères de la forme ‘’-ddd.ddd…’ la chaîne résultante
débute par un signe moins si le nombre est négatif. Le nombre de
F
chiffres après la virgule est indiqué par le spécificateur de précision de la
de la chaîne de format ; 2 décimales sont prises en compte par défaut si
aucun spécificateur de précision n’est spécifié
G Général : L’argument doit être une valeur réelle qui est convertie en une
chaîne de caractères la plus courte possible en utilisant le format fixe ou
Annexe 1 : Compléments sur Delphi 391

Valeur Signification
scientifique.
Numérique : La valeur est convertie en une chaîne de caractères de la
N forme ‘-d ddd ddd,ddd…’. Ce format est analogue au format ‘f’ sauf que
des séparateurs des milliers sont utilisés.
Monétaire : l’argument doit être une valeur réelle. La valeur est
convertie en une chaîne de caractères représentant un montant monétaire.
M
La conversion est paramétrée par les choix de la section international du
panneau de configuration windows.
Pointeur : l’argument doit être une valeur de type pointeur. Celle-ci
convertie en une chaîne de caractères de la forme ‘XXXX:YYYY’ où
P
XXXX et YYYY sont les parties segment et offset du pointeur ; sous
forme de quatre chiffres hexadécimaux
Chaîne de caractères : L’argument doit être un caractère, une chaîne de
S caractères ou une valeur de type PChar. La chaîne de caractère ou le
caractère est inséré à la place du spécificateur de format.
Hexadécimal : L’argument doit être une valeur entière qui est convertie
X
en une chaîne de chiffres hexadécimaux.

Remarques:
- les caractères de formatage peuvent être en majuscules ou en minuscules
- Les spécificateurs d'indice, de taille et de précision peuvent être spécifiés
directement comme dans

Format('%8.2f', [123.456]).
ou indirectement comme dans:
Format('%*.*f', [8, 2, 123.456])
392 Annexe 1 :Compléments sur Delphi

7- Envoi et création d'un message par notre


application
Envoyer un message a l'aide de PostMessage et SendMessage

L'API Windows met à notre disposition les procédures PostMessage et


SendMessage qui permettent d'envoyer un message. Contrairement à
PostMessage, SendMessage attend que le message soit traité.
SendMessage envoie directement le message à une procédure de fenêtre sans
passer par la file d'attente. L'événement Application.OnMessage n'est donc
pas déclenché.
PostMessage est plutôt utilisé pour des notifications ou des traitements
asynchrones. PostMessage ne poste rien si la file d'attente est pleine (donc
toujours tester le résultat de PostMessage et récidiver éventuellement).

Exemple :
Placez sur une fiche un button, deux TEdit et un panel puis placez ce code
dans l'événement OnClick du bouton:

procedure TForm1.Button1Click(Sender: TObject);


{ PostMessage place un message dans la file
d'attente d'une fenêtre ou d'un contrôle
SendMessage fait la même chose mais attend
qu'il soit traité }
begin
Edit1.selectall; {sélectionne tout le texte de
l'édit1}
PostMessage(Form1.Panel1.Handle,WM_CLOSE,0,0);
{ferme le panel (pas besoin d'attendre que ce
soit fait pour passer à la suite}
SendMessage(Form1.Edit1.Handle,WM_COPY,0,0);
{message servant à copier le texte sélectionné
de l'édit1}
SendMessage(Form1.Edit2.Handle,WM_PASTE,0,0);
{message servant à copier dans l'edit2}
SendMessage(Form1.Edit2.Handle,WM_CHAR,
ord('k'),0);{envoi d'un caractère à l'édit2}
end;
pour voir un exemple d'application, envoyer un message à l'aide de
TControl.Perform :
Annexe 1 : Compléments sur Delphi 393

TControl.Perform répond comme si le contrôle avait reçu le message


Windows spécifié.

function Perform(Msg: Cardinal; WParam, LParam:


Longint): Longint;

Perform permet de court-circuiter la file d'attente des messages Windows


et d'envoyer directement un message à la procédure de fenêtre du contrôle.
Voir son utilisation dans l'exemple de Interception des messages destinés à
une fenêtre ou un composant; WindProc

Création d'un message


Avant la déclaration du type TForm1, ajoutez

const
WM_MESSAGEPERSO = WM_USER + 1; { le 1 peut être
remplacé par le chiffre de votre choix ne pas
utiliser le même chiffre pour un autre message}

Dans la partie private, ajoutez la déclaration de la procédure qui réagira au


message WM_MESSAGEPERSO

private
procedure WMMessagePerso(var Msg : TMessage);
message WM_MESSAGEPERSO; { procédure destinée à
recevoir le message WM_MESSAGEPERSO
394 Annexe 1 :Compléments sur Delphi

8- Utiliser les HOOKS

A quoi servent les HOOKS ?


Les Hooks permettent de récupérer les messages à destination des autres
applications.

Introduction
Cet exemple a été fait d'après un exemple que m'avait fourni Daniel
Drouin. Merci à lui. Sans lui, je n'aurai pas réussi à comprendre cette technique
très peu documentée.

Principe général
Au départ, on crée un Hook en indiquant à Windows la fonction qui doit
être déclenchée à chaque fois que transite un message d'un certain type.

HookHandle:=SetWindowsHookEx(WH_MOUSE,HookActionC
allBack,HInstance,0);

- WH_MOUSE indique que l'on souhaite intercepter tous les messages de type
"souris".
- HookActionCallBack est le nom de notre procédure qui devra être
appelée lorsque circulera un message de type "souris"
- HookHandle récupère la valeur retournée par SetWindowsHookEx,
c'est à dire le Handle de notre Hook. Ce Handle nous servira par la
suite pour libérer le Hook à l'aide de la fonction
UnHookWindowsHookEx.

Exemple de code (attention, ce code ne peut fonctionner tel quel, voir plus bas, il
n'est là que pour la compréhension) :
Dans ce morceau de code exemple :

- La fonction InitializeHook devra être appelée par notre programme,


par exemple dans le OnCreate de la Form principale de notre application.
- La fonction FinalizeHook pourra être appelée à la fermeture de notre
programme. (Ex: dans l'événement OnDestroy de la fiche principale)

function HookActionCallBack(Code: integer; Msg:


WPARAM; MouseHook: LPARAM):LRESULT; stdcall;
Annexe 1 : Compléments sur Delphi 395

{cette fonction reçoit tous les messages


détournés elle bip si le message est de type
WM_LBUTTONDOWN}
begin
if Msg=WM_LBUTTONDOWN then messageBeep(1);
Result:=CallNextHookEx(HookHandle,Code,Msg,
MouseHook);{afin que le message continue à se
propager}
end;

function InitializeHook(AWndCallBack:HWnd):HWnd;
stdcall; export; {SetWindowsHookEx permet de
donner à Windows le nom de la fonction qui sera
exécutée à chaque fois qu'il reçoit un message
de type WH_MOUSE }
begin
HookHandle:=SetWindowsHookEx(WH_MOUSE,HookActionC
allBack,HInstance,0);
end;

procedure FinalizeHook; stdcall; export;


begin
UnhookWindowsHookEx(HookHandle);
end;

L'appel à SetWindowsHookEx et la fonction appelée doivent être dans une


DLL

Le but de la fonction SetWindowsHook est donc de donner à Windows


le nom d'une fonction qu'il doit déclencher lui-même à chaque fois que certains
messages transitent.
Il ne peut le faire que si cette fonction est placée dans une DLL.
Exactement comme un programme normal qui ne peut se servir d'une fonction
développée par un tiers que si elle se trouve dans une DLL (et autres ActiveX...)
et non dans un programme normal.
Donc, il faut d'abord savoir créer une DLL puis y placer les fonctions du
style de celles figurant dans l'exemple ci-dessus.
Certaines variables de la DLL doivent être dans un "espace partagé" !
Notre application fait appel à la DLL et certaines valeurs doivent être
conservées en mémoire pour être réutilisée par la suite. Par exemple,
SetWindowsHookEx renvoie le Handle du Hook, qu'il faut garder en
396 Annexe 1 :Compléments sur Delphi

mémoire afin de pouvoir utiliser CallNextHookEx dans la fonction appelée


(HookActionCallBack dans notre exemple). Or, notre application va appeler
à sa création SetWindowsHookEx et donc obtenir HookHandle. Mais,
lorsque Windows fera appel à la fonction HookCallBack de notre DLL, il le
fera dans une autre instance. C'est le même phénomène que lorsque vous lancez
deux (02) fois la même application en simultané, si on ne fait rien de spécial, la
première instance ne partage pas ses variables avec la deuxième.

Pour faire ce partage de variable, nous allons employer un "File-Mapping":

{le $FFFFFFFF indique seulement que ce n'est pas


un fichier qui sera mappé, mais des données}
{TDonneesHook.InstanceSize permet de donner à
Windows la bonne taille de mémoire à réserver}
HookMap:=CreateFileMapping($FFFFFFFF,nil,
PAGE_READWRITE,0,TDonneesHook.InstanceSize,
'Michel');
{Ensuite faire un View indiquant la structure
dans laquelle seront stockées nos données.}
DonneesHook:=MapViewOfFile(HookMap,
FILE_MAP_WRITE,0,0,0);

Pour libérer la mémoire, il suffit, à la fin de l'utilisation de notre DLL de faire :

UnMapViewOfFile(DonneesHook);
CloseHandle(HookMap);

DonneesHook contiendra toutes les variables que l'on souhaite partager.

Exemple de déclaration :

TDonneesHook=class
HookHandle:HHook; {Handle retourné par
SetWindowsHookEx}
//autres variables à partager
end;
.......
Var DonneesHook : TDonneesHook;
......
Annexe 1 : Compléments sur Delphi 397

Pour utiliser ces données partagées, il faut, par exemple, remplacer

HookHandle:=SetWindowsHookEx(WH_MOUSE,
HookActionCallBack,HInstance,0);

Par

DonneesHook.HookHandle:=SetWindowsHookEx
(WH_MOUSE,HookActionCallBack,HInstance,0);

Et

Result:=CallNextHookEx(HookHandle,Code,Msg,
MouseHook);

par

Result:=CallNextHookEx(DonneesHook.HookHandle,
Code, Msg,MouseHook);

Où mettre le CreateFileMapping et le MapViewOfFile ?

Lorsqu'une DLL est chargée, une procédure désignée par la variable


DllProc est exécuté en lui passant le paramètre DLL_PROCESS_ATTACH.
Cela permet de lancer du code d'initialisation.
Il faut :

-Initialiser la variable DllProc en lui passant l'adresse de la procédure


contenant notre code d'initialisation. Pour cela, il suffit de placer par
exemple, DllProc:=@LibraryProc; entre un begin et le end.
final de notre dll
- Implémenter la procédure dont l'adresse est contenue dans DllProc (ici
LibraryProc) en testant si le paramètre transmis est égal à
DLL_PROCESS_ATTACH.
Cette même procédure désignée par DllProc permet de désigner du code à
exécuter à la fin de l'utilisation de la DLL. En ce cas, le paramètre transmis à cette
procédure est égal à DLL_PROCESS_DETACH. On l'utilisera pour libérer les
ressources prises par notre FileMapping. Dans notre exemple :
UnMapViewOfFile(DonneesHook);
CloseHandle(HookMap);
398 Annexe 1 :Compléments sur Delphi

D'où le code complet de notre LibraryProc :

procedure LibraryProc(AReason:Integer);
begin
case AReason of
DLL_PROCESS_ATTACH:begin
{Il faut d'abord créer le FileMapping}
{le $FFFFFFFF indique seulement que ce n'est pas
un fichier qui sera mappé, mais des données }
{TDonneesHook.InstanceSize permet de donner à
Windows la bonne taille de mémoire à réserver}
HookMap:=CreateFileMapping($FFFFFFFF,nil,
PAGE_READWRITE,0,TDonneesHook.InstanceSize,
'Michel');
{Ensuite faire un View sur tout le fichier}
DonneesHook:=MapViewOfFile(HookMap,
FILE_MAP_WRITE,0,0,0);
end;
DLL_PROCESS_DETACH:begin {libérer les ressources
prisent par notre FileMapping}
UnMapViewOfFile(DonneesHook);
CloseHandle(HookMap);
end;
DLL_THREAD_ATTACH:;
DLL_THREAD_DETACH:;
end;
end;

exports
InitializeHook,
FinalizeHook;

begin
DllProc:=@LibraryProc;
LibraryProc(DLL_PROCESS_ATTACH);
end.

Et si on veut récupérer les messages dans notre application et non dans la


DLL
Et bien ce n'est pas compliqué, il suffit que notre DLL envoie un message
à notre application déclenchant ainsi une procédure dans notre application.

Vous aimerez peut-être aussi