Déclarations d'API
Comme vous le savez sans doute, l'API de Windows contient plus de 2 000 fonctions. Bien sûr, puisque l'API est destinée à être utilisée dans l'environnement VC++, toutes les déclarations sont par défaut dans le langage Visual C++ (c'est-à-dire le langage C++ avec les extensions VC++ de Microsoft). Voici un exemple de déclaration d'API tirée de la documentation Win32 sur le CD du MSDN Library :
- LRESULT SendMessage(
- HWND hWnd, // Identificateur de descripteur de la fenêtre de destination
- UINT Msg, // Message à envoyer
- WPARAM wParam, // Premier paramètre de message
- LPARAM lParam, // Deuxième paramètre de message
- );
Une traduction possible en VB (et il y en a d'autres) est :
Pour y arriver, vous devez connaître quelques principes de base pour réaliser de telles traductions. Nous supposerons que vous êtes familiarisé avec les concepts de passage de paramètres par valeur et par référence. Pour plus de commodité, nous ferons référence à toute procédure (fonction ou sous-programme) résidant dans une DLL et destinée à l'exportation en tant que fonction externe. (La procédure est externe à l'application VB appelant cette fonction.)
L'instruction Declare de Visual Basic
L'instruction Declare de Visual Basic est utilisée pour appeler des fonctions externes résidant dans des DLL. L'instruction doit être utilisée au niveau du module, plutôt qu'au niveau de la procédure. Il existe deux syntaxes - une pour les fonctions et une pour les sous-programmes :
[Public | Private] Declare Sub name Lib "libname" [Alias "aliasname"] [([arglist])] |
et :
[Public | Private] Declare Function name Lib "libname" [Alias "aliasname"] [([arglist])] [As type] |
où les éléments entre crochets sont facultatifs et la barre indique des choix alternatifs.
Public ou Private
Lors de l'utilisation de l'instruction Declare dans un module de code standard, nous pouvons utiliser le mot clef Public pour rendre la fonction accessible à l'ensemble du projet Visual Basic. Dans un module de formulaire ou de classe, cependant, nous devons utiliser Private ou Visual Basic se plaindra.
Nom de l'appelant
Le mot-clef name doit être remplacé par le nom de la fonction, comme nous avons l'intention d'appeler à partir de notre code Visual Basic. Comme nous le verrons, il y a parfois de bonnes raisons pour que ce nom diffère du nom réel de la fonction tel que défini dans la DLL. Pour utiliser un nom différent, nous devons utiliser la syntaxe Alias, décrite ci-dessous. Il est important de noter que, contrairement aux noms en Visual Basic, les noms de fonctions DLL sont sensibles à la casse (comme tout dans le langage VC++) !
La bibliothèque Expert
La phrase :
Lib "libname" |
est utilisé pour indiquer la DLL source exportant la fonction. Pour les appels d'API de Win32, il s'agit généralement (mais pas toujours) de l'un des trois grands DLL maîtresse :
Pour les trois DLL, vous pouvez omettre l'extension .DLL dans libname, comme nous l'avons fait dans l'exemple plus haut.
Alias
Comme mentionné, il y a plusieurs raisons pour appeler une fonction DLL en utilisant un nom différent de son vrai nom, tel que défini dans la DLL. Cela se fait à l'aide du mot clef Alias. Voici trois raisons convaincantes d'utiliser des alias.
Éviter les mots clefs Visual Basic et les caractères illégaux
Certaines fonctions API ont les mêmes noms que les fonctions Visual Basic. La fonction SetFocus en est un bon exemple :
- HWND SetFocus(HWND hWnd);
Nous ne pouvons pas déclarer cela dans Visual Basic comme ceci :
- Declare Function SetFocus Lib "user32" (ByVal hWnd As Long) As Long
car SetFocus est un mot-clef Visual Basic. Mais nous pouvons le déclarer comme ceci :
- Declare Function SetFocusAPI Lib "user32" Alias "SetFocus" (ByVal hWnd As Long) As Long
De plus, certaines fonctions API utilisent des caractères n'étant pas autorisés dans Visual Basic, comme les fonctions de fichier _hread, _hwrite, _lclose,..., commençant par un trait de soulignement. Nous pouvons mettre un alias sur ces noms en omettant le premier trait de soulignement. Heureusement, peu de fonctions API sont des mots-clefs Visual Basic ou contiennent des caractères illégaux, mais lorsque cela se produit, nous ne pourrions pas les utiliser dans Visual Basic sans les alias.
ANSI versus Unicode
Les fonctions d'API de Win32 utilisant des paramètres de chaîne de caractères sont généralement disponibles en deux versions : une pour ANSI et une pour Unicode. La fonction SendMessage définie au début de la page en est un bon exemple. Il existe en fait deux fonctions SendMessage différentes définies dans la bibliothèque USER32.DLL. La version ANSI est appelée SendMessageA et la version Unicode est appelée SendMessageW (le W est pour wide ou large). Dans le jargon, nous dirions qu'il existe deux points d'entrée pour la fonction SendMessage. Plutôt que de saupoudrer notre code avec As ou Ws, il est plus logique de faire le choix une fois dans la déclaration, puis d'utiliser le mot sans ornement SendMessage dans tout le code. D'une part, cela simplifierait les futurs changements. Comme nous l'avons dit, Windows NT prend en charge Unicode. Il met en oeuvre donc les points d'entrée Uncode pour les fonctions API ayant des paramètres de chaîne de caractères. Pour des raisons de compatibilité, Windows NT met en oeuvre également les points d'entrée ANSI, mais ces mises en oeuvre effectuent généralement les conversions nécessaires, appellent la version Unicode correspondante de la fonction et reconvertissent en ANSI !
D'un autre côté, Windows 9x ne prend généralement pas en charge Unicode, sauf dans certaines situations limitées. Selon Microsoft : «Windows 95 n'implémente pas la version Unicode (ou caractères larges) de la plupart des fonctions Win32 acceptant des paramètres de chaîne de caractères. À quelques exceptions près, ces fonctions sont implémentées sous forme de stubs renvoyant simplement le succès sans modifier aucun paramètre.»
Cela semble plutôt mal avisé. Ne serait-il pas préférable de renvoyer une valeur n'indiquant pas de succès lorsque la fonction n'a rien fait ? Dans tous les cas, il existe quelques exceptions à cette règle. En particulier, Windows 9x prend en charge le point d'entrée Unicode dans les fonctions API liées à OLE, ainsi qu'une poignée d'autres fonctions API, comme indiqué dans le tableau suivant :
- EnumResourceLanguages
- EnumResourceNames
- EnumResourceTypes
- ExtTextOut
- FindResource
- FindResourceEx
- GetCharWidth
- GetCommandLine
- GetTextExtentExPoint
- GetTextExtentPoint32
- GetTextExtendPoint
- lstrlen
- MessageBox
- MessageBoxEx
- TextOut
De plus, Windows 9x met en oeuvre deux fonctions de conversion : MultiByteToWideChar et WideCharToMultiByte.
Prenons particulièrement note du fait que Windows 9x met en oeuvre la version Unicode de lstrlen (s'appelant lstrlenW). La fonction renvoie le nombre de caractères dans un tableau de caractères Unicode terminé par null. La meilleure marche à suivre pour un programmeur VB est simplement d'appeler les points d'entrée ANSI, car ils sont compatibles avec Windows 9x et Windows NT.
Déclarations de type de paramètre
La troisième raison d'utiliser des alias concerne les déclarations de type des paramètres dans une instruction Declare. Grâce au alias, nous pouvons vouloir déclarer plusieurs versions d'une seule fonction externe en utilisant différents types de données pour certains des paramètres. Une raison à cela est de tirer parti des capacités de vérification de type de Visual Basic pour détecter les erreurs de déclaration de type avant qu'elles n'atteignent la DLL, alors qu'elles provoqueront probablement une erreur GPF (General Protection Fault). Pour ce faire, nous devrons utiliser des alias.
Liste des paramètres
Le paramètre arglist est une liste de paramètres et de leurs types de données. Sa syntaxe (simplifiée) est :
[ByVal | ByRef] varname[( )] [As type] |
où les parenthèses facultatives suivant varname sont requises pour les variables de tableau. Le mot-clef type peut être l'un des suivants : Byte, Boolean, Integer, Long, Currency, Single, Double, Date, String (longueur de variable seulement), Variant, définit par l'utilisateur, ou objet (en fait, des chaînes de caractères de longueur fixe peuvent apparaître comme paramètres de procédure, mais ils sont convertis en chaînes de caractères de longueur variable avant d'être passés à la fonction.)
Le plan de jeu de traduction VC-à-VB
De manière générale, la traduction d'une déclaration de fonction API de style VC++ en VB implique les étapes suivantes :
- Obtenez le nom de la bibliothèque (nom et chemin de la DLL) pour la clause Lib de la déclaration VB.
- La traduction du type de retour de la fonction d'un type de données VC++ en un type de données VB.
- La traduction de chaque déclaration de paramètre de VC++ vers VB. Cela implique de choisir un type de données VB et de décider également d'utiliser ByVal ou ByRef.
- Choisissez un nom d'alias, si nécessaire. Cela peut être fait pour des raisons descriptives ou pour les raisons évoquées précédemment.
Parmi toutes ses étapes, il ne fait aucun doute que la partie la plus difficile du processus de traduction est le processus de traduction du type de données des paramètres.
Passage de paramètres à une fonction externe
La procédure pour les déclarations de paramètres et le passage de paramètres pour les fonctions DLL externes est assez similaire à celle des fonctions Visual Basic ordinaires, sauf dans trois cas : les chaînes, les adresses et les structures (types définis par l'utilisateur). Cependant, la gestion des chaînes et des structures implique simplement la gestion des adresses, donc tout se résume à des adresses, c'est-à-dire à des pointeurs.
La chose la plus importante à retenir à propos de la déclaration de paramètres et du passage de paramètres en ce qui concerne les fonctions DLL externes est que nous sommes vraiment en conflit avec deux déclarations - la définition de la déclaration dans la DLL ainsi que la déclaration Visual Basic dans l'instruction Declare. Notre travail consiste à faire correspondre l'instruction Declare de Visual Basic à la déclaration DLL de définition.
En particulier, il est important de garder à l'esprit que tous les mots clefs ByVal et ByRef apparaissant dans une instruction Declare sont des instructions destinées à Visual Basic et non à la DLL.