Utilisation des DLL`s

Transcription

Utilisation des DLL`s
Traitement de données
Création d’une DLL
La DLL, à quoi ça sert ?
Une DLL (Dynamic Link Library) est avant tout un programme
exécutable sans fonction principale (pas de main). Elle regroupe un
ensemble de fonctions que divers programmes peuvent se partager.
Elle permet de modulariser un programme en blocs fonctionnels. Chaque
bloc fonctionne en " boîte noire ", on connaît juste le nom de la fonction,
son rôle bien évidemment, ses paramètres d'entrée et de sortie.
Utiliser une DLL, cela permet de modifier et/ou corriger le driver sans
avoir à toucher aux exécutables qui l'utilisent.
Le principal avantage est qu'on peut dissocier lors de son développement
la partie IHM (visible par l'opérateur) de la partie intelligente, et donc
utiliser pour chaque partie un langage adapté : pour toute la partie
graphique des outils spécialisés (Delphi, Visual Basic,...), et pour la partie
intelligente du C ou de l'assembleur. On conserve la puissance et facilité
de tous les langages possibles.
Les DLL permettent au fabricant de matériel de fournir des drivers
utilisables afin que l’utilisateur dispose d’un accès plus convivial à ce
matériel.
Autre avantage mais nettement moins important de nos jours, lors de
l'utilisation de DLL, l'OS ne charge qu'une seule fois la partie de code en
mémoire, seule la partie DATA est répliquée ; on gagne ainsi quelques
(kilo)octets.
Construction
Avec Visual C++, on crée un nouveau projet de type DLL (donc File/New.../Win32 Dynamic-link library) que
l'on va appeler DLL_test pour l'occasion.
Ensuite il va falloir ajouter quelques fichiers essentiels à notre DLL :
au moins un fichier C contenant le corps de notre projet
un fichier RC contenant des informations de versions (facultatif, mais fortement conseillé pour être
propre)
un fichier DEF contenant les fonctions à exporter dans la DLL
Le minimum
La seule fonction obligatoire dans la DLL, qui est l'équivalent du MAIN dans un exécutable est DllEntryPoint,
cette fonction est appelée au (dé)chargement de la DLL. Curieusement cette fonction n'a pas besoin d'être
exportée !
Le code de retour indique si le chargement s'est bien fait ou pas. Ici, on retourne TRUE systématiquement.
C'est à cet endroit du code que l'on peut faire quelques initialisations, mais personnellement je préfère faire une
fonction xxx_init dédiée.
Donc si on veut faire une DLL vide on fera, par exemple, pour DLL_Test.c :
#include <windows.h>
#Niedercorn LT « la Briquerie » 57100 THIONVILLE
Programmation : les DLLs
& page 1/3
BOOL WINAPI DllEntryPoint (HINSTANCE hInst, DWORD ul_reason_for_call, LPVOID lpReserved)
{
return TRUE;
}
La première fonction
On va ajouter une fonction truc qui affiche une boite de dialogue à l'écran. Notre code devient alors :
#include <windows.h>
#define DllImport __declspec( dllimport )
#define DllExport __declspec( dllexport )
DllExport void pascal DLL_Test_Truc(void);
BOOL WINAPI DllEntryPoint (HINSTANCE hInst, DWORD ul_reason_for_call, LPVOID lpReserved)
{
return TRUE;
}
DllExport void DLL_Test_Truc(void)
{
MessageBox(NULL, "coucou", "DLL Test", MB_OK);
}
Ensuite il faut préciser au compilateur que cette fonction va être exportée : ajouter DllExport avant la
déclaration (ATTENTION : le terme DllExport est une redéfinition conseillé par Visual C++, se reporter à la
doc du compilateur utilisé pour vérification)
Et enfin il faut dire au linker aussi que cette fonction est exportée, on le fait dans le fichier DEF :
DLL_Test.DEF
LIBRARY DLL_Test
CODE MOVEABLE DISCARDABLE
DATA SINGLE
EXPORTS
DLL_Test_Truc
Vous pouvez compiler ce mini projet et vérifier votre DLL grâce à Dependency Walker, un utilitaire fourni sur
le CD du Resource Kit Microsoft Windows NT Server, qui vous permet de voir entre autre les fonctions
exportées, les DLL et leurs fonctions appelées, la version de build.... Un utilitaire très utile pour le développeur.
Le passage de paramètres
Le seule chose importante à retenir est que la DLL n'est chargée qu'une seule fois en mémoire, mais qu'elle crée
un nouveau segment de DATA à chaque chargement, donc on ne peut pas mélanger des données qui
viendraient d'applications diverses.
Tous les types de paramètres habituellement passables entre fonctions du même exécutable sont utilisables
(void, int, pointeurs,....). La seule limite réside en fait dans la facilité de les utiliser dans les différents langages
qui se présentent.
Utilisation de la DLL
Ce n'est pas le tout de savoir développer de belles DLL remplies de fonctions utiles, il faut aussi arriver à les
appeler.
L’utilisation d’une peut s’effectuer de plusieurs façons :
Lors de la compilation :
la DLL se trouve dans le répertoire de l’application, elle est indépendante du compilateur utilisé.
Un fichier d’entête (*.h) permet de lister les fonctions incluses.
Un fichier de librairie (*.lib) permet directement d’utiliser, lors de la compilation, tout ou partie des
fonctions incluses dans la DLL.
Attention, le fichier *.lib et le fichier *.h sont obtenus après compilation de la DLL et sont ainsi de ce
fait adapté à un compilateur donné.
Lors de l’exécution :
la DLL ne se trouve pas obligatoirement dans le répertoire de l’application, elle est indépendante du
compilateur utilisé.
#Niedercorn LT « la Briquerie » 57100 THIONVILLE
Programmation : les DLLs
& page 2/3
Lors de l’exécution du programme, on charge, grâce à des API Windows, la DLL et peut alors utiliser
les fonctions qui s’y trouvent.
Un fichier d’entête (*.h) permet de lister les fonctions incluses.
Dans le premier cas, par exemple pour Visual C++, il faut tout d'abord avoir le fichier .LIB généré lors de la
compilation de la DLL.
Ensuite il faut ajouter ce fichier .LIB, pour cela, allez dans "Projet/Settings", puis onglet "link" et renseignez le
champs "Object/Library modules",
Enfin, dans les sources C il faut déclarer les fonctions. Pour cela on reprend à peu près les mêmes déclarations
que pour l'exportation, mais on remplace DLLExport par DLLImport. Le mieux est de mettre ça dans un fichier
header (.H) qui sera inclut dans chaque source C. Dans notre cas on pourrait faire un DLL_Test.h qui
ressemblerait à :
#include <windows.h>
#define DllImport __declspec( dllimport )
#define DllExport __declspec( dllexport )
DllImport void DLL_Test_Truc(void);
Quand on repense un peu à cette méthode, c'est exactement ce que l'on fait lorsqu'on utilise les fonctions de
l'API standard de Windows, simplement que tout ce travail est fait par défaut dans le compilateur.
Bien sur ici le problème des types de variables est beaucoup plus simple à gérer !
Quelques règles à suivre
Lors du développement et surtout de la maintenance (tant évolutive que corrective) d'une DLL, il faut se tenir à
quelques règles simples qui éviteront un bon nombre de tracas.
D'abord, il faut imposer que la DLL n'existe qu'à un seul exemplaire sur le disque, et pour cela il faut qu'elle
soit dans un répertoire visible du PATH, moi je conseille \WINDOWS\SYSTEM(32).
Ensuite, lors de l'évolution du code, il faut impérativement tenir compte de la compatibilité avec les anciennes
versions de la DLL, ainsi tous les programmes existant continueront à fonctionner normalement et les nouveaux
pourront profiter des nouveautés de la librairie.
Il faut aussi tenir à jour la ressource version (dans le fichier .RC), en cas de doute sur une DLL c'est beaucoup
plus fiable que sa taille ou sa date.
Conclusion
Voilà pour une présentation rapide d'une DLL.
La seule difficulté est dans les déclarations et l'utilisation du fichier .DEF, mystérieusement sous documenté sur
tous les nouveaux compilateurs.
Une toute petite remarque pour finir, l'abus de DLL nuit à votre santé et à celle de votre micro, donc ne prenez
pas la mauvaise habitude de faire plein de DLL pour un oui ou pour un non ; restez thématique dans leurs
fonctions.
#Niedercorn LT « la Briquerie » 57100 THIONVILLE
Programmation : les DLLs
& page 3/3