Question

J'ai lu de nombreux tutoriels / articles sur les DLL non gérées en C ++. Pour ma vie, cependant, je n'arrive pas à saisir le concept. Le désaccord apparent sur la nécessité d’un fichier d’en-tête, sur la manière de l’exporter, sur le besoin d’un fichier .lib et sur ce que vous faites me rend perplexe.

Supposons donc que je n'ai qu'une fonction comme celle-ci:

public int calculateSquare(int num)
{
    return num*num;
}

En ignorant le code actuel, de quoi ai-je besoin pour transformer cette fonction simple en une DLL que je peux ensuite appeler? Dois-je simplement ajouter __dllexport ou quoi que ce soit à la première ligne ou ai-je besoin d'un en-tête? Je suis perplexe devant tout cela.

Était-ce utile?

La solution

Je ne saurais trop insister sur ce point, le compilateur C ++ ne voit pas les fichiers d'en-tête. Une fois le préprocesseur terminé, il n'y a qu'un seul gros fichier source (également appelé unité de compilation). Donc, strictement, vous n'avez pas besoin d'un en-tête pour exporter cette fonction à partir d'une dll. Ce dont vous avez besoin est une forme de compilation conditionnelle pour exporter la fonction dans la DLL que vous compilez et l’importer dans le code client.

Généralement, cela se fait avec une combinaison de macros et de fichiers d’en-tête. Vous créez une macro appelée MYIMPORTEXPORT et utilisez des instructions conditionnelles pour les macros comme suit: __declspec (dllexport) dans la dll et __declspec (dllimport) dans le code client.

dans le fichier MYIMPORTEXPORT.h

#ifdef SOME_CONDITION
#define MYIMPORTEXPORT __declspec( dllexport )
#else
#define MYIMPORTEXPORT __declspec( dllimport )
#endif

dans le fichier MyHeader.h

#include <MyImportExport.h>

MYIMPORTEXPORT public int calculateSquare(int num)
{
    return num*num;
}

dans le fichier .cpp dll

#define SOME_CONDITION

#include <MyHeader.h>

dans le fichier .cpp du code client

#include <MyHeader.h>

Bien entendu, vous devez également signaler à l'éditeur de liens que vous construisez une dll avec le option / DLL .

Le processus de construction créera également un fichier .lib, il s’agit d’une librairie statique - appelée le stub dans ce cas - à laquelle le code client doit être lié comme s’il s’agissait de lier une véritable bibliothèque statique. Automagiquement, la DLL sera chargée lors de l'exécution du code client. Bien entendu, le système d'exploitation doit trouver la dll via son mécanisme de recherche, ce qui signifie que vous ne pouvez pas placer la dll n'importe où, mais à un emplacement spécifique. Ici , vous en saurez plus sur ce sujet.

Un outil très pratique pour savoir si vous avez exporté la fonction correcte à partir de la dll et si le code client est correctement importé est dumpbin . Exécutez-le avec / EXPORTS et / IMPORTS respectivement.

Autres conseils

La réponse de QBziZ est juste. Voir DLL non gérées en C ++

Pour le compléter: En C ++, si vous devez utiliser un symbole, vous devez en informer le compilateur, ainsi que son prototype .

.

Dans d’autres langues, le compilateur n’explorera que la bibliothèque et trouvera le symbole et voilà .

En C ++, vous devez en informer le compilateur.

Afficher un en-tête C / C ++ sous forme de table des matières dans un livre

Le meilleur moyen est de mettre dans un endroit commun le code nécessaire. Le "interface", si vous voulez. Cela se fait généralement dans un fichier d'en-tête, appelé en-tête, car ce n'est généralement pas un fichier source indépendant. L’en-tête est uniquement un fichier dont le but est d’être inclus (c'est-à-dire copier / coller par le pré-processeur) dans les vrais fichiers source.

En substance, il semble que vous deviez déclarer deux fois un symbole (fonction, classe, peu importe). Ce qui est presque une hérésie par rapport aux autres langues.

Vous devriez le voir comme un livre, avec un tableau récapitulatif ou un index. Dans le tableau, vous avez tous les chapitres. Dans le texte, vous avez les chapitres et leur contenu.

Et parfois, vous êtes juste content d'avoir la liste des chapitres.

En C ++, il s'agit de l'en-tête.

Qu'en est-il de la DLL?

Revenons donc au problème de la DLL: le but d'une DLL est d'exporter les symboles que votre code utilisera.

Ainsi, en mode C ++, vous devez tous les deux exporter le code lors de la compilation (c’est-à-dire que, sous Windows, utilisez __declspec, par exemple) et "publier". un tableau de ce qui est exporté (c.-à-d. que vous avez des en-têtes "publics" contenant les déclarations exportées).

Liste de contrôle pour l'exportation de fonctions:

  • La convention d'appel convient-elle à l'appelant? (cela détermine la manière dont les paramètres et les résultats sont transmis, et qui est responsable du nettoyage de la pile). Vous devez énoncer explicitement votre convention d'appel.
  • Sous quel nom le symbole sera exporté? C ++ a généralement besoin de décorer ("mangle") les noms de symboles, par ex. faire la distinction entre différentes surcharges.
  • Indiquez à l'éditeur de liens de rendre la fonction visible en tant qu'exportation de DLL

Sur MSVC:

  • __ stdcall (convention d’appel pascal) est la convention d’appel typique des symboles exportés - prise en charge par la plupart des clients, je suppose.
  • extern " C " permet d’exporter le symbole de style C sans modifier le nom
  • utilisez __ declspec (dllexport) pour marquer un symbole à exporter, ou liez un fichier .def séparé dans lequel les symboles à exporter sont répertoriés. Avec un fichier .def, vous pouvez également exporter uniquement par ordinal (pas par nom) et modifier le nom du symbole exporté.

Vous devez exporter la fonction à l'aide de __ declspec (dllexport) ou en ajoutant la fonction à un fichier de définition de module (.def). Puis compilez le projet en tant que DLL.

Du côté client, vous avez deux options. Utilisez une bibliothèque d'importation (.lib) générée lors de la compilation de la DLL. La simple liaison avec votre projet client avec cette bibliothèque vous donnera accès aux fonctions exportées de la DLL. Et vous avez besoin d'un fichier d'en-tête, car le compilateur a besoin de connaître la signature de votre fonction - qu'il retourne int et prend un int. Pour récapituler, vous devez créer un lien avec une bibliothèque d'importation (.lib) et un fichier d'en-tête contenant l'en-tête de votre fonction.

Vous pouvez également charger la DLL de manière dynamique à l'aide de WinAPI , appelez LoadLibrary , puis GetProcAddress pour obtenir un pointeur sur la fonction. Le pointeur sur la fonction doit avoir le type correct pour que le compilateur puisse lui donner les paramètres corrects et que la convention d'appel correcte soit utilisée.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top