guidelines - c++ export class dll example




Exportieren einer C++-Klasse aus einer DLL (4)

Die meisten meiner C / C ++ - Entwicklungen beinhalten monolithische Moduldateien und überhaupt keine Klassen. Wenn ich also eine DLL mit barrierefreien Funktionen __declspec(dllexport) exportiere ich sie einfach mit der Standard- __declspec(dllexport) . Dann greifen Sie entweder dynamisch über LoadLibrary() oder zur Kompilierzeit mit einem Header und einer lib-Datei auf sie zu.

Wie machst du das, wenn du eine ganze Klasse (und alle ihre öffentlichen Methoden und Eigenschaften) exportieren willst?

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

Wie würdest du es mit einem Header und lib für die Kompilierzeit verknüpfen?


Was ist mit der späten Bindung? Wie beim Laden mit LoadLibrary () und GetProcAddress ()? Ich benutze es, die Bibliothek zur Laufzeit zu laden und es wäre toll, wenn Sie das hier tun könnten.

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

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

Beide Ansätze sind für C-Level-Funktionsexporte geeignet. Sie können den Linker entweder behandeln lassen oder GetProcAddress wie angegeben aufrufen.

Wenn es jedoch um exportierte Klassen geht , wird typischerweise nur der erste Ansatz verwendet, dh implizit eine Verbindung zu der DLL hergestellt. 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 dynamisch nach der Programminitialisierung geladen werden soll, haben Sie zwei Möglichkeiten:

  1. Erstellen Sie Objekte der Klasse mithilfe einer speziellen Factory-Funktion, die intern (ein kleines Stück) Assembler verwenden muss, um neu erstellte Objekte an ihre entsprechenden Offsets "anzuschließen". Dies muss zur Laufzeit NACH dem Laden der DLL offensichtlich geschehen. Eine gute Erklärung dieses Ansatzes finden Sie here .

  2. Verwenden Sie eine Delay-Load-DLL .

Alles in allem ... wahrscheinlich ist es besser, nur mit implizitem Verknüpfen zu gehen, in diesem Fall möchten Sie definitiv die oben gezeigte Präprozessor-Technik verwenden. Wenn Sie eine neue DLL in Visual Studio erstellen und die Option "Symbole exportieren" wählen, werden diese Makros tatsächlich für Sie erstellt.

Viel Glück...


Hinzufügen eines einfachen Arbeitsbeispiels zum Exportieren einer C ++ - Klasse aus einer DLL:

Das unten stehende Beispiel gibt Ihnen nur einen kurzen Überblick darüber, wie dll und exe miteinander interagieren können (selbsterklärend), aber es braucht mehr Dinge, die hinzugefügt werden müssen, um in einen Produktionscode zu wechseln.

Das vollständige Beispielbeispiel ist in zwei Teile unterteilt

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

B. Erstellen einer Anwendung, 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;
}

Vor kurzem stellte ich mir genau die gleiche Frage und fasste meine Ergebnisse in einem Blogbeitrag zusammen . Sie können es nützlich finden.

Es umfasst das Exportieren von C ++ - Klassen aus einer DLL sowie das dynamische Laden dieser Klassen mit LoadLibrary und einige der damit verbundenen Probleme, wie z. B. Speicherverwaltung, Namensfehlern und Aufrufkonventionen.


Wenn Sie die DLL und das Modul erstellen, das die DLL verwendet, haben Sie eine Art #define, die Sie verwenden können, um zwischen den beiden zu unterscheiden, dann können Sie in Ihrer Klassenheaderdatei so etwas tun:

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

Edit: crashmstr bezwinge mich dazu!





dll