Je vais maintenant vous parler des bibliothèques dynamiques. Alors là cela va être un peu plus compliqué.
Le projet de la dll
Tout d'abord dans Code::Blocks vous devez créer un nouveau projet en choisissant "Dynamic Link Library". Cochez la case "Do not create any files" et appuyez sur le bouton create.
Ajouter un fichier .c à votre projet. Moi je le nomme dll.c (pas très original c'est vrai).
Alors que mettre dans ce fichier ?
En fait ce n'est pas très compliqué, il suffit d'avoir une fonction. Je vais prendre l'exemple d'une fonction qui renvoie la somme de deux entiers passés en paramètre. Bon ça devrait aller je pense :
Code : C | int addition(int entier1, int entier2) {
return entier1 + entier2;
}
|
Donc, on met cette fonction dans le fichier dll.c mais cela ne suffit pas. En effet, il faut indiquer que cette fonction devra être exporté pour être utilisé par votre programme.
Pour cela, on utilise __declspec (dllexport) placé entre le type de la fonction et son nom. On obtient donc la fonction suivante:
Code : C | int __declspec (dllexport) addition(int entier1, int entier2) {
return entier1 + entier2;
}
|
Si vous avez plusieurs fonctions il est intéressant de faire la macro suivante pour faciliter le travail:
Code : C | #define DllExport __declspec(dllexport)
int DllExport addition(int entier1, int entier2) {
return entier1 + entier2;
}
|
Et voilà c'est presque finit. Il faut juste créer un fichier header dll.h.
Comme vous le savez sûrement déjà (sinon relisez les cours de M@teo) ce fichier contiendra les prototypes des fonctions de la dll:
Code : C | int addition(int entier1, int entier2);
|
Mais ici la fonction sera importée de la dll donc il faut rajouter __declspec (dllimport). La encore on place ce code entre le type de la fonction et son nom. On obtient:
Code : C | #define DllImport __declspec(dllimport)
int DllImport addition(int entier1, int entier2);
|
Voilà c'est fini. Vous n'avez plus qu'à compiler votre projet. Après la compilation vous obtenez deux fichier importants: sample.dll et libsample.a (ne jetez pas non plus le fichier dll.h).
Ces deux fichiers vont vous êtres utiles par la suite.
Votre programme pour une bibliothèque à chargement implicite
Maintenant il faut utiliser cette belle bibliothèque. Pour ce projet nous allons encore faire un projet console.
Une fois votre projet créé, vous devez lui rajouter un fichier main.c contenant votre fonction main(). Puis vous mettez le code pour pouvoir tester l'importation de fonctions de la dll.
Par exemple:
Code : C 1
2
3
4
5
6
7
8
9
10
11
12 | #include <stdio.h>
#include <stdlib.h>
#include "dll.h"
int main(int argc, char *argv[]) {
int resultat = 0;
resultat = addition(3, 7);
printf("Le resultat est %d\n", resultat);
printf("Appuyez sur une touche pour continuer...");
getchar();
return 0;
}
|
Pensez bien à inclure le fichier dll.h pour avoir le prototype des fonctions de la bibliothèque. Maintenant vous compilez votre projet et ...
Et cela ne marche pas. Vous obtenez un horrible "undefined reference to `_imp__addition`".
C'est à ce moment là qu'il faut se rappeler du fichier libsample.a qui a été généré par Code::Blocks à la compilation du projet de dll. Vous devez donc linker votre projet avec ce fichier.
Vous recompilez et quelle joie cela fonctionne correctement.
Maintenant vous placez votre fichier dll.dll dans le même répertoire que votre exécutable. Vous exécutez et heureusement pour moi la console affiche:
Code : Console | Le resultat est 10
Appuyez sur une touche pour continuer... |
Votre programme pour une bibliothèque à chargement explicite
Dans ce cas, c'est un peu plus compliqué. Il n'est plus nécessaire d'inclure le fichier dll.h dans votre code ni de linker avec libsample.a (au moins vous ne l'oublierez pas

). Par contre, il faut inclure windows.h (donc ce code ne sera pas portable). Comme exemple je vais prendre le même que précédemment.
Code : C 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 | #include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
HINSTANCE DLLHandle;
typedef int(*Type_Pointeur_De_Fonction)(int, int);
Type_Pointeur_De_Fonction Pointeur_Fonction;
DLLHandle = LoadLibrary("dll.dll");
Pointeur_Fonction = (Type_Pointeur_De_Fonction)GetProcAddress(DLLHandle,"addition");
int resultat = 0;
resultat = Pointeur_Fonction(3,7);
printf("Le resultat est: %d\n", resultat);
printf("Appuyez sur une touche pour continuer...");
getchar();
FreeLibrary(DLLHandle);
return 0;
}
|
Alors là je crois que des explications s'imposent non ? On va faire ça ligne par ligne (enfin pas toutes quand même).
Code : C
Déclare une variable de type HINSTANCE. Cela permet de garder le handle pour notre programme. Comme Windows est multitâche cela lui permet de savoir ce que fait notre programme.
Code : C | typedef int(*Type_Pointeur_De_Fonction)(int, int);
|
Là on définit un type de pointeur de fonction. Je vais juste vous expliquer un petit peu ce qu'est un pointeur de fonctions.
Ce n'est pas très compliqué si vous savez ce qu'est un pointeur. Un pointeur est une variable contenant l'adresse d'une autre variable. Pour une fonction, le pointeur contient donc l'adresse de la fonction. Où plus précisément l'adresse du point d'entrée dans la fonction.
Pour plus d'informations sur les pointeurs de fonctions, vous pouvez aller voir le tuto
Les pointeurs de fonction de
mleg.
Code : C | Type_Pointeur_De_Fonction Pointeur_Fonction;
|
Ici on déclare un pointeur de fonction du type ci-dessus. Ce pointeur pointera (c'est son métier

) vers la fonction que l'on va importer de la dll.
Code : C | DLLHandle = LoadLibrary("dll.dll");
|
La fonction LoadLibrary permet de charger en mémoire notre bibliothèque. Celle ci est pointée par DLLHandle.
Code : C | Pointeur_Fonction = (Type_Pointeur_De_Fonction)GetProcAddress(DLLHandle,"addition");
|
GetProcAddress renvoie l'adresse de la fonction. Le premier paramètre sert à identifier la dll que l'on utilise et le second est le nom de la fonction que l'on veut importer.
Code : C | resultat = Pointeur_Fonction(3,7);
|
Maintenant on utilise le pointeur de la même manière que si on utilisait la fonction.
Code : C
Et enfin il ne faut pas oublier de décharger la bibliothèque de la mémoire.
Et là votre programme marche correctement (surtout si vous pensez à mettre la dll dans le même répertoire que l'exécutable

).