Question

La plupart de mon développement C/C++ implique des fichiers de modules monolithiques et absolument aucune classe, donc généralement lorsque j'ai besoin de créer un DLL avec des fonctions accessibles je les exporte simplement en utilisant le standard __declspec(dllexport) directif.Accédez-y ensuite soit de manière dynamique via LoadLibrary() ou au moment de la compilation avec un en-tête et un fichier lib.

Comment procéder lorsque vous souhaitez exporter une classe entière (et toutes ses méthodes et propriétés publiques) ?

Est-il possible de charger dynamiquement cette classe au moment de l'exécution et si oui, comment ?

Comment feriez-vous avec un en-tête et une bibliothèque pour la liaison au moment de la compilation ?

Était-ce utile?

La solution

Qu’en est-il des liaisons tardives ?Comme pour le charger avec LoadLibrary () et GetProcAddress ()?J’ai l’habitude de pouvoir pour charger la bibliothèque au moment de l’exécution et qu’il Ce serait formidable si vous pouviez le faire ici.

Il existe donc deux manières de charger la DLL.La première consiste à référencer un ou plusieurs symboles de la DLL (votre nom de classe, par exemple), à ​​fournir un fichier .LIB d'importation approprié et à laisser l'éditeur de liens comprendre tout.

La seconde consiste à charger explicitement la DLL via LoadLibrary.

Les deux approches fonctionnent bien pour les exportations de fonctions de niveau C.Vous pouvez soit laisser l'éditeur de liens le gérer, soit appeler GetProcAddress comme vous l'avez noté.

Mais lorsqu'il s'agit d'exportations Des classes, généralement seule la première approche est utilisée, c'est-à-dire un lien implicite vers la DLL.Dans ce cas, la DLL est chargée au démarrage de l'application et l'application ne parvient pas à se charger si la DLL est introuvable.

Si vous souhaitez créer un lien vers une classe définie dans une DLL et que vous souhaitez que cette DLL soit chargée dynamiquement, quelque temps après le lancement du programme, vous disposez de deux options :

  1. Créez des objets de la classe à l'aide d'une fonction d'usine spéciale, qui devra en interne utiliser (un tout petit peu) d'assembleur pour "connecter" les objets nouvellement créés à leurs décalages appropriés.Cela doit être fait au moment de l'exécution APRÈS que la DLL ait été chargée, évidemment.Une bonne explication de cette approche peut être trouvée ici.

  2. Utiliser un DLL à chargement différé.

Tout bien considéré...il est probablement préférable d'opter pour une liaison implicite, auquel cas vous souhaitez absolument utiliser la technique de préprocesseur présentée ci-dessus.En fait, si vous créez une nouvelle DLL dans Visual Studio et choisissez l'option « exporter les symboles », ces macros seront créées pour vous.

Bonne chance...

Autres conseils

Lorsque vous construisez la DLL et le module qui utilisera la DLL, ayez une sorte de #define que vous pouvez utiliser pour distinguer l'un de l'autre, vous pouvez alors faire quelque chose comme ceci dans votre fichier d'en-tête de classe :

#if defined( BUILD_DLL )
    #define IMPORT_EXPORT __declspec(dllexport)
#else
    #define IMPORT_EXPORT __declspec(dllimport)
#endif
class IMPORT_EXPORT MyClass {
    ...
};

Modifier:crashmstr m'a devancé !

J'utilise quelques macros pour marquer le code à importer ou à exporter

#ifdef ISDLL
#define DLL __declspec(dllexport)
#endif

#ifdef USEDLL
#define DLL __declspec(dllimport)
#endif

Déclarez ensuite la classe dans un fichier d'en-tête :

class DLL MyClassToExport { ... }

Alors #define ISDLL à la bibliothèque, et USEDLL avant d'inclure le fichier d'en-tête à l'endroit où vous souhaitez utiliser la classe.

Je ne sais pas si vous devrez peut-être faire quelque chose différemment pour travailler avec LoadLibrary

Ajout d'un exemple de travail simple pour exporter une classe C++ à partir d'une DLL :

L'exemple ci-dessous ne vous donne qu'un bref aperçu de la façon dont les dll et les exe peuvent interagir (explicatif), mais il nécessite plus d'éléments à ajouter pour être transformé en code de production.

L'exemple complet est divisé en deux parties

UN.Création d'une bibliothèque .dll (MyDLL.dll)

B.Création d'une application qui utilise la bibliothèque .dll (Application).

UN.Fichier de projet .dll (MyDLL.dll) :

1.dllHeader.h

#ifdef  MYDLL_EXPORTS 
#define DLLCALL __declspec(dllexport)   /* Should be enabled before compiling 
                                           .dll project for creating .dll*/
#else
#define DLLCALL __declspec(dllimport)  /* Should be enabled in Application side
                                          for using already created .dll*/
#endif

// Interface Class
class ImyMath {
public:
    virtual ~ImyMath() {;}
    virtual int Add(int a, int b) = 0;
    virtual int Subtract(int a, int b) = 0;
};

// Concrete Class
class MyMath: public ImyMath {
public:
    MyMath() {}
    int Add(int a, int b);
    int Subtract(int a, int b);
    int a,b;
};

//  Factory function that will return the new object instance. (Only function
//  should be declared with DLLCALL)
extern "C" /*Important for avoiding Name decoration*/
{
    DLLCALL ImyMath* _cdecl CreateMathObject();
};

// Function Pointer Declaration of CreateMathObject() [Entry Point Function]
typedef ImyMath* (*CREATE_MATH) ();

2.dllSrc.cpp

#include "dllHeader.h"

// Create Object
DLLCALL ImyMath* _cdecl CreateMathObject() {
    return new MyMath();
}

int MyMath::Add(int a, int b) {
    return a+b;
}

int MyMath::Subtract(int a, int b) {
    return a-b;
}

B.Projet d'application qui charge et lie le fichier .dll déjà créé :

 #include <iostream>
#include <windows.h>
#include "dllHeader.h"

int main()
{
    HINSTANCE hDLL = LoadLibrary(L"MyDLL.dll"); // L".\Debug\MyDLL.dll"

    if (hDLL == NULL) {
        std::cout << "Failed to load library.\n";
    }
    else {
        CREATE_MATH pEntryFunction = (CREATE_MATH)GetProcAddress(hDLL,"CreateMathObject");
        ImyMath* pMath = pEntryFunction();
        if (pMath) {
            std::cout << "10+10=" << pMath->Add(10, 10) << std::endl;
            std::cout << "50-10=" << pMath->Subtract(50, 10) << std::endl;
        }
        FreeLibrary(hDLL);
    }
    std::cin.get();
    return 0;
}

Récemment, je me suis posé exactement la même question et j'ai résumé mes conclusions dans un article de blog.Vous pourriez le trouver utile.

Il couvre l'exportation de classes C++ à partir d'une DLL, ainsi que leur chargement dynamique avec LoadLibrary, et discute de certains des problèmes liés à cela, tels que la gestion de la mémoire, la modification des noms et les conventions d'appel.

Si vous souhaitez placer une table virtuelle dans la classe que vous exportez, vous pouvez exporter une fonction qui renvoie une interface et implémenter la classe dans le .dll, puis la placer dans le fichier .def.Vous devrez peut-être faire quelques astuces de déclaration, mais cela ne devrait pas être trop difficile.

Tout comme COM.:)

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