Frage

Der Großteil meiner C/C++-Entwicklung umfasst monolithische Moduldateien und überhaupt keine Klassen, also normalerweise, wenn ich eine erstellen muss DLL mit zugänglichen Funktionen exportiere ich sie einfach mit dem Standard __declspec(dllexport) Richtlinie.Greifen Sie dann entweder dynamisch über darauf zu LoadLibrary() oder zur Kompilierzeit mit einer Header- und LIB-Datei.

Wie machen Sie das, wenn Sie eine ganze Klasse (und alle ihre öffentlichen Methoden und Eigenschaften) exportieren möchten?

Ist es möglich, diese Klasse zur Laufzeit dynamisch zu laden und wenn ja, wie?

Wie würden Sie es mit einem Header und einer Bibliothek für die Verknüpfung zur Kompilierzeit machen?

War es hilfreich?

Lösung

Was ist mit der Spätbindung?Wie beim Laden mit loadlibrary () und getProcaddress ()?Ich kann die Bibliothek zur Laufzeit laden und es wäre großartig, wenn Sie das hier tun könnten.

Es gibt also zwei Möglichkeiten, die DLL zu laden.Die erste besteht darin, auf ein oder mehrere Symbole aus der DLL zu verweisen (z. B. Ihren Klassennamen), eine entsprechende Import-LIB bereitzustellen und den Linker alles herausfinden zu lassen.

Die zweite besteht darin, die DLL explizit über LoadLibrary zu laden.

Beide Ansätze funktionieren gut für Funktionsexporte auf C-Ebene.Sie können dies entweder dem Linker überlassen oder GetProcAddress aufrufen, wie Sie notiert haben.

Aber wenn es um den Export geht Klassen, Normalerweise wird nur der erste Ansatz verwendet, d. h. eine implizite Verknüpfung mit der DLL.In diesem Fall wird die DLL zum Startzeitpunkt der Anwendung geladen und die Anwendung kann nicht geladen werden, wenn die DLL nicht gefunden werden kann.

Wenn Sie eine Verknüpfung zu einer in einer DLL definierten Klasse herstellen möchten und diese DLL irgendwann nach der Programminitiierung dynamisch geladen werden soll, haben Sie zwei Möglichkeiten:

  1. Erstellen Sie Objekte der Klasse mithilfe einer speziellen Factory-Funktion, die intern (ein kleines bisschen) Assembler verwenden muss, um neu erstellte Objekte mit ihren entsprechenden Offsets zu „verknüpfen“.Dies muss natürlich zur Laufzeit erfolgen, NACHDEM die DLL geladen wurde.Eine gute Erklärung für diesen Ansatz finden Sie hier Hier.

  2. Benutze einen Verzögerungslade-DLL.

Alles in Betracht gezogen...Wahrscheinlich ist es besser, einfach die implizite Verknüpfung zu verwenden. In diesem Fall möchten Sie auf jeden Fall die oben gezeigte Präprozessortechnik verwenden.Wenn Sie in Visual Studio eine neue DLL erstellen und die Option „Symbole exportieren“ auswählen, werden diese Makros tatsächlich für Sie erstellt.

Viel Glück...

Andere Tipps

Wenn Sie die DLL und das Modul erstellen, das die DLL verwenden wird, verfügen Sie über eine Art #define, mit dem Sie zwischen den beiden unterscheiden können. Anschließend können Sie in Ihrer Klassenheaderdatei Folgendes tun:

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

Bearbeiten:crashmstr ist mir zuvorgekommen!

Ich verwende einige Makros, um den Code für den Import oder Export zu markieren

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

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

Dann deklarieren Sie die Klasse in einer Header-Datei:

class DLL MyClassToExport { ... }

Dann #define ISDLL in der Bibliothek und USEDLL bevor Sie die Header-Datei an der Stelle einfügen, an der Sie die Klasse verwenden möchten.

Ich weiß nicht, ob Sie für die Arbeit mit etwas anderes tun müssen LoadLibrary

Hinzufügen eines einfachen Arbeitsbeispiels für den Export einer C++-Klasse aus einer DLL:

Das folgende Beispiel gibt Ihnen nur einen kurzen Überblick darüber, wie DLL und Exe miteinander interagieren können (selbsterklärend), aber für die Umwandlung in einen Produktionscode müssen noch weitere Dinge hinzugefügt werden.

Das vollständige Beispielbeispiel ist in zwei Teile unterteilt

A.Erstellen einer DLL-Bibliothek (MyDLL.dll)

B.Erstellen einer Anwendung, die die DLL-Bibliothek (Anwendung) verwendet.

A..dll-Projektdatei (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.Anwendungsprojekt, das die bereits erstellte DLL-Datei lädt und verknüpft:

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

Kürzlich habe ich mir genau die gleiche Frage gestellt und meine Ergebnisse zusammengefasst in einem Blogbeitrag.Möglicherweise finden Sie es nützlich.

Es umfasst den Export von C++-Klassen aus einer DLL sowie deren dynamisches Laden mit LoadLibrary, und erörtert einige der damit verbundenen Probleme, wie Speicherverwaltung, Namensverfälschung und Aufrufkonventionen.

Wenn Sie bereit sind, eine Vtable in die zu exportierende Klasse einzufügen, können Sie eine Funktion exportieren, die eine Schnittstelle zurückgibt, die Klasse in der DLL implementieren und diese dann in die DEF-Datei einfügen.Möglicherweise müssen Sie einige Tricks bei der Deklaration anwenden, aber es sollte nicht zu schwierig sein.

Genau wie COM.:) :)

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top