![]() |
|
Marco CantùL'essentiel sur PascalTraduit de l'anglais par Iannis Papageorgiadis [email protected] |
Chapitre 9:
|
Delphi fournit une encapsulation complète pour les API Windows de bas niveau en utilisant Pascal Objet et la bibliothèque des composants visuels (VCL); il est ainsi rarement nécessaire de construire des applications Windows en utilisant le Pascal et en appelant directement des fonctions API Windows. Néanmoins, les programmeurs qui souhaitent utiliser des techniques spéciales non supportées par la VCL ont encore cette possibilité en Delphi. On n'a besoin d'utiliser cette approche que pour des cas spéciaux, comme le développement de nouveaux composants Delphi basés sur des appels API insolites, et nous ne souhaitons pas nous étendre sur les détails. Par contre, nous verrons quelques éléments de l'interaction de Delphi avec le système d'exploitation et l'une ou l'autre technique dont les programmeurs Delphi pourraient tirer profit.
type THandle = LongWord;Les types de données Handle sont implémentés comme des nombres, mais ils ne sont pas utilisés comme tels. En Windows, un handle est une référence vers une structure de données interne du système. Par exemple, lorsque vous travaillez avec une fenêtre (ou une fiche Delphi), le système vous donne un handle vers la fenêtre. Le système vous informe que la fenêtre avec laquelle vous êtes en train de travailler est, par exemple, la fenêtre numéro 142. A partir de ce moment, votre application peut demander au système de travailler sur la fenêtre numéro 142 -- pour la déplacer, modifier sa taille, la réduire à une icône, etc. Beaucoup de fonctions API Windows comportent en fait un handle comme premier paramètre. Ceci ne s'applique pas uniquement aux fonctions agissant sur les fenêtres
En d'autres mots, un handle est un code interne que l'on utilise pour se référer à un élément spécifique que le système répertorie par son handle, y compris des fenêtres, des bitmaps, des icônes, des blocs mémoire, des curseurs, des fontes, des menus, etc. Dans Delphi on devra rarement utiliser directement les handles, puisqu'ils sont cachés à l'intérieur des fiches, des bitmaps et des autres objets Delphi. Ils deviennent utiles lorsqu'on cherche à appeler une fonction API Windows qui n'est pas supportée par Delphi.
Voici, pour compléter cette description, un exemple simple illustrant les handles de Windows. Le programme WHandle comporte une fiche simple, ne contenant qu'un bouton. Dans le code nous répondons à l'événement OnCreate de la fiche et à l'événement OnClick du bouton comme indiqué ci-dessous dans la description textuelle de la fiche principale :
object FormWHandle: TFormWHandle
Caption = ‘Handle de la fenêtre’
OnCreate = FormCreate
object BtnCallAPI: TButton
Caption = ‘Appel API’
OnClick = BtnCallAPIClick
end
endDès la création de la fiche, le programme récupère le handle de la fenêtre correspondante à la fiche en accédant à la propriété Handle de la fiche même. Nous appelons IntToStr pour convertir la valeur numérique du handle en une chaîne et nous l'ajoutons au titre de la fiche, comme on le voit à la figure 9.1 :
procedure TFormWHandle.FormCreate(Sender: TObject);
begin
Caption := Caption + ‘ ‘ + IntToStr (Handle);
end;Puisque FormCreate est une méthode de la classe de la fiche, elle a accès directement aux autres propriétés et méthodes de la classe. Dans cette procédure nous pouvons donc simplement faire référence directement aux propriétés Caption et Handle de la fiche.
Figure 9.1 : L'exemple WHandle affiche le handle de la fenêtre de la fiche. A chaque exécution de ce programme, vous obtiendrez une valeur différente.
Si vous exécutez ce programme plusieurs fois, vous obtiendrez généralement des valeurs de handle différentes. En fait, cette valeur est déterminée par Windows et est retournée à l'application. (Les handles ne sont jamais déterminés par le programme, ils n'ont pas de valeurs prédéfinies; ils sont déterminés par le système qui génère de nouvelles valeurs à chaque exécution du programme).
Lorsque l'utilisateur presse le bouton, le programme appelle simplement une fonction API Windows, SetWindowText, qui modifie le texte ou le titre de la fenêtre passée en tant que premier paramètre. Pour être plus précis, le premier paramètre de cette fonction API est le handle de la fenêtre que nous souhaitons modifier :
procedure TFormWHandle.BtnCallAPIClick(Sender: TObject);
begin
SetWindowText (Handle, ‘Salut’);
end;Ce code a le même effet que celui du gestionnaire d'événement précédent qui modifiait le texte de la fenêtre en donnant une nouvelle valeur à la propriété Caption de la fiche. Dans ce cas, appeler une fonction API n'a pas de sens, parce qu'il existe une technique Delphi plus simple. Cependant, quelques fonctions API n'ont pas de correspondant en Delphi, comme on le verra plus loin dans des exemples plus avancés.
// déclaration forward
function LineTo (DC: HDC; X, Y: Integer): BOOL; stdcall; // déclaration externe (au lieu du code réel)
function LineTo; external ‘gdi32.dll’ name ‘LineTo’;Cette déclaration signifie que le code de la fonction LineTo est stocké dans la bibliothèque dynamique GDI32.DLL (une des plus importantes bibliothèques système de Windows) sous le même nom. En fait, dans une déclaration external, nous pouvons spécifier que notre fonction fait référence à une fonction d'une DLL qui avait à l'origine un nom différent.
On a rarement besoin d'écrire de telles déclarations,
puisqu'elles sont déjà listées dans l'unité
Windows et dans beaucoup d'autres unités système de Delphi.
La seule raison pour laquelle on pourrait être amené à
écrire des déclarations externes serait l'appel de fonctions
d'une DLL personnalisée, ou l'appel de fonctions non documentées
de Windows.
Avant tout, qu'est-ce qu'une fonction de rappel (callback) ? Quelques fonctions API accomplissent une action donnée sur un nombre d'éléments internes du système, comme toutes les fenêtres d'un certain type. Ces fonctions, appelées également fonctions énumérées, demandent comme paramètre l'action à accomplir sur chacun des éléments, passée en tant que fonction ou en tant que procédure compatible avec un type procédural donné. Windows utilise des fonctions de rappel dans d'autres circonstances, mais nous nous limiterons à ce cas simple.
Considérons maintenant la fonction API EnumWindows, dont
le prototype est le suivant (copié depuis le fichier d'aide de Win32)
BOOL EnumWindows( WNDENUMPROC lpEnumFunc, // address of callback function LPARAM lParam // application-defined value );Bien sûr, il s'agit de la définition en C. Nous pouvons voir dans le fichier WINDOWS.PAS la définition correspondante en Pascal
function EnumWindows ( lpEnumFunc: TFNWndEnumProc; lParam: LPARAM): BOOL; stdcall;En consultant le fichier d'aide, nous voyons que la fonction passée par paramètre devrait être du type suivant (encore en C)
BOOL CALLBACK EnumWindowsProc ( HWND hwnd, // handle of parent window LPARAM lParam // application-defined value );Ceci correspond à la définition de type procédural Delphi que voici
type EnumWindowsProc = function (Hwnd: THandle; Param: Pointer): Boolean; stdcall;Le premier paramètre est le handle de la fenêtre principale en exécution, tandis que le second est la valeur que nous avons passée en appelant la fonction EnumWindows. En fait, en Pascal, le type TFNWndEnumProc n'est pas défini complètement; il s'agit simplement d'un pointeur. Ceci veut dire que nous devons fournir une fonction avec le paramètre approprié et l'utiliser alors comme paramètre en prenant l'adresse de la fonction au lieu de l'appeler. Malheureusement, ceci signifie aussi que le compilateur ne fournira pas d'aide en cas d'erreur dans le type d'un des paramètres.
function GetTitle (Hwnd: THandle; Param: Pointer): Boolean; stdcall; var Text: string; begin SetLength (Text, 100); GetWindowText (Hwnd, PChar (Text), 100); FormCallBack.ListBox1.Items.Add ( IntToStr (Hwnd) + ': ' + Text); Result := True; end;La fiche possède une boîte liste (ListBox) occupant presque toute la surface, et un petit panel sur le haut hébergeant un bouton. Lorsque le bouton est pressé, la fonction API EnumWindows est appelée et la fonction GetTitle lui est passée en paramètre
procedure TFormCallback.BtnTitlesClick(Sender: TObject); var EWProc: EnumWindowsProc; begin ListBox1.Items.Clear; EWProc := GetTitle; EnumWindows (@EWProc, 0); end;Nous aurions pu appeler la fonction sans stocker d'abord temporairement la valeur dans une variable de type procédural, mais nous souhaitions voir clairement ce qui se passait dans cet exemple. L'effet de ce programme est vraiment très intéressant, comme on peut le voir à la figure 9.2. L'exemple Callback affiche une liste de toutes les fenêtres principales tournant dans le système. La plupart d'elles sont vraiment des fenêtres cachées qu'habituellement on ne voit jamais (et bon nombre d'entre elles n'ont en fait pas de titre).
Bien que les utilisateurs spécifient rarement des paramètres ligne de commande dans un environnement avec interface utilisateur graphique, les paramètres ligne de commande Windows sont très importants pour le système. Par exemple, une fois que l'on a défini une association entre une extension de fichier et une application, on peut faire tourner un programme en sélectionnant simplement un fichier associé. Pratiquement, lorsqu'on double-clique sur un fichier, Windows démarre le programme associé et passe le fichier sélectionné en tant que paramètre ligne de commande.
Voici le code source complet du projet (un fichier DPR et non pas un fichier PAS) :
program Strparam; uses Windows; begin
// afficher toute la chaîne
MessageBox (0, cmdLine, 'Ligne de commande de StrParam', MB_OK);
// afficher le premier paramètre
if ParamCount > 0 then
MessageBox (0, PChar (ParamStr (1)), '1er paramètre de StrParam', MB_OK)
else
MessageBox (0, PChar ('Il n''y a pas de paramètres'),
'1er paramètre de StrParam', MB_OK);
end.Le code d'affichage utilise la fonction API MessageBox pour éviter simplement d'importer la VCL entière dans le projet. Un pur programme Windows comme celui-ci a l'avantage d'occuper une très petite quantité mémoire; le fichier exécutable du programme est d'environ 16 Kbytes.
Pour fournir un paramètre ligne de commande à ce programme, on peut utiliser la commande Paramètres du menu Exécuter de Delphi. Une autre technique consiste à ouvrir l'Explorateur Windows, à localiser le répertoire (le dossier) qui contient le fichier exécutable du programme et à faire glisser le fichier qu'on souhaite faire exécuter sur le fichier exécutable. L'Explorateur Windows démarrera le programme en utilisant le nom du fichier déposé en tant que paramètre ligne de commande. La figure 9.3 affiche tant l'Explorateur que le résultat correspondant (output).
Figure 9.3 : On peut fournir un paramètre ligne de commande à l'exemple StrParam en faisant glisser un fichier sur le fichier exécutable dans l'Explorateur Windows. Le résultat de cette opération de glissement sur la partie supérieure de la figure est affiché à la portion la plus basse :
Le chapitre suivant traitera des types variant, un ajout très étrange au système de type de Pascal, introduit pour fournir un support OLE complet.
© Copyright Marco Cantù, Wintech Italia Srl 1995-99 |