Domanda

La maggior parte del mio sviluppo in C/C++ coinvolge file di moduli monolitici e assolutamente nessuna classe, quindi di solito quando ho bisogno di creare un file DLL con le funzioni accessibili le esporto semplicemente utilizzando lo standard __declspec(dllexport) direttiva.Quindi accedervi dinamicamente tramite LoadLibrary() o in fase di compilazione con un header e un file lib.

Come si fa quando si desidera esportare un'intera classe (e tutti i suoi metodi e proprietà pubblici)?

È possibile caricare dinamicamente quella classe in fase di esecuzione e, in caso affermativo, come?

Come lo faresti con un'intestazione e una lib per il collegamento in fase di compilazione?

È stato utile?

Soluzione

E la rilegatura tardiva?Come nel caricarlo con loadLibrary () e GetPrCAddress ()?Sono usato per caricare la biblioteca in fase di esecuzione e sarebbe bello se potessi farlo qui.

Quindi ci sono due modi per caricare la DLL.Il primo è fare riferimento a uno o più simboli dalla DLL (il nome della tua classe, ad esempio), fornire un file import .LIB appropriato e lasciare che il linker capisca tutto.

Il secondo consiste nel caricare esplicitamente la DLL tramite LoadLibrary.

Entrambi gli approcci funzionano bene per le esportazioni di funzioni di livello C.Puoi lasciare che sia il linker a gestirlo o chiamare GetProcAddress come hai notato.

Ma quando si tratta di esportato classi, in genere viene utilizzato solo il primo approccio, ovvero il collegamento implicito alla DLL.In questo caso la DLL viene caricata all'avvio dell'applicazione e l'applicazione non viene caricata se non è possibile trovare la DLL.

Se desideri collegarti a una classe definita in una DLL e desideri che la DLL venga caricata dinamicamente, qualche tempo dopo l'avvio del programma, hai due opzioni:

  1. Crea oggetti della classe utilizzando una speciale funzione factory, che internamente dovrà utilizzare (un po' di) assembler per "agganciare" gli oggetti appena creati ai loro offset appropriati.Questo deve essere fatto in fase di esecuzione DOPO che la DLL è stata caricata, ovviamente.È possibile trovare una buona spiegazione di questo approccio Qui.

  2. Usare un DLL con caricamento ritardato.

Tutte le cose considerate...probabilmente è meglio utilizzare semplicemente il collegamento implicito, nel qual caso vorrai sicuramente utilizzare la tecnica del preprocessore mostrata sopra.Infatti, se crei una nuova DLL in Visual Studio e scegli l'opzione "esporta simboli" queste macro verranno create per te.

Buona fortuna...

Altri suggerimenti

Quando crei la DLL e il modulo che utilizzerà la DLL, disponi di una sorta di #define che puoi utilizzare per distinguere tra l'uno e l'altro, quindi puoi fare qualcosa di simile nel file di intestazione della classe:

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

Modificare:crashmstr mi ha preceduto!

Utilizzo alcune macro per contrassegnare il codice per l'importazione o l'esportazione

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

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

Quindi dichiara la classe in un file di intestazione:

class DLL MyClassToExport { ... }

Poi #define ISDLL nella biblioteca, e USEDLL prima di includere il file di intestazione nel punto in cui desideri utilizzare la classe.

Non so se potresti aver bisogno di fare qualcosa di diverso per lavorare con LoadLibrary

Aggiunta di un semplice esempio funzionante per esportare una classe C++ da una DLL:

L'esempio riportato di seguito fornisce solo una breve panoramica di come DLL ed exe possono interagire tra loro (autoesplicativo) ma richiede più cose da aggiungere per trasformarlo in un codice di produzione.

L'esempio completo del campione è diviso in due parti

UN.Creazione di una libreria .dll (MyDLL.dll)

B.Creazione di un'applicazione che utilizza la libreria .dll (Applicazione).

UN.File di progetto .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.Progetto applicativo che carica e collega il file .dll già creato:

 #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;
}

Recentemente mi sono posto esattamente la stessa domanda e ho riassunto le mie scoperte in un post sul blog.Potresti trovarlo utile.

Riguarda l'esportazione di classi C++ da una DLL, nonché il loro caricamento dinamico con LoadLibrary, e discute alcuni dei problemi al riguardo, come la gestione della memoria, la modifica dei nomi e le convenzioni di chiamata.

Se desideri inserire un vtable nella classe che stai esportando, puoi esportare una funzione che restituisce un'interfaccia e implementare la classe nel file .dll, quindi inserirla nel file .def.Potrebbe essere necessario fare qualche trucco con la dichiarazione, ma non dovrebbe essere troppo difficile.

Proprio come COM.:)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top