Pregunta

La mayor parte de mi desarrollo en C/C++ implica archivos de módulos monolíticos y absolutamente ninguna clase, por lo que normalmente cuando necesito hacer un DLL con funciones accesibles simplemente las exporto usando el estándar __declspec(dllexport) directiva.Luego acceda a ellos dinámicamente a través de LoadLibrary() o en tiempo de compilación con un encabezado y un archivo lib.

¿Cómo se hace esto cuando se desea exportar una clase completa (y todos sus métodos y propiedades públicos)?

¿Es posible cargar dinámicamente esa clase en tiempo de ejecución y, de ser así, cómo?

¿Cómo lo harías con un encabezado y una biblioteca para vincular en tiempo de compilación?

¿Fue útil?

Solución

¿Qué pasa con el enlace tardío?Como en cargarlo con loadLibrary () y getProcAddress ()?Me utilizan poder cargar la biblioteca en el momento de ejecución y sería genial si pudieras hacerlo aquí.

Entonces hay dos formas de cargar la DLL.La primera es hacer referencia a uno o más símbolos de la DLL (su nombre de clase, por ejemplo), proporcionar un .LIB de importación apropiado y dejar que el vinculador se encargue de todo.

El segundo es cargar explícitamente la DLL a través de LoadLibrary.

Cualquiera de los dos enfoques funciona bien para las exportaciones de funciones de nivel C.Puede dejar que el vinculador lo maneje o llamar a GetProcAddress como anotó.

Pero cuando se trata de exportar clases, normalmente solo se utiliza el primer enfoque, es decir, vincular implícitamente a la DLL.En este caso, la DLL se carga en el momento de inicio de la aplicación y la aplicación no se carga si no se puede encontrar la DLL.

Si desea vincular una clase definida en una DLL y desea que esa DLL se cargue dinámicamente, en algún momento después del inicio del programa, tiene dos opciones:

  1. Cree objetos de la clase usando una función de fábrica especial, que internamente tendrá que usar (un poquito de) ensamblador para "conectar" los objetos recién creados a sus compensaciones apropiadas.Esto debe hacerse en tiempo de ejecución DESPUÉS de que se haya cargado la DLL, obviamente.Se puede encontrar una buena explicación de este enfoque. aquí.

  2. Usar una DLL de carga retardada.

Todas las cosas consideradas...Probablemente sea mejor optar por enlaces implícitos, en cuyo caso definitivamente querrás utilizar la técnica de preprocesador que se muestra arriba.De hecho, si crea una nueva DLL en Visual Studio y elige la opción "exportar símbolos", estas macros se crearán automáticamente.

Buena suerte...

Otros consejos

Cuando construyas la DLL y el módulo que usará la DLL, ten algún tipo de #define que puedas usar para distinguir entre uno y otro, luego puedes hacer algo como esto en el archivo de encabezado de tu clase:

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

Editar:crashmstr se me adelantó!

Utilizo algunas macros para marcar el código para importar o exportar.

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

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

Luego declara la clase en un archivo de encabezado:

class DLL MyClassToExport { ... }

Entonces #define ISDLL en la biblioteca, y USEDLL antes de incluir el archivo de encabezado en el lugar donde desea usar la clase.

No sé si es posible que necesites hacer algo diferente para trabajar con LoadLibrary

Agregar un ejemplo de trabajo simple para exportar una clase C++ desde una DLL:

El siguiente ejemplo le brinda solo una breve descripción general de cómo dll y exe pueden interactuar entre sí (se explica por sí mismo), pero necesita agregar más cosas para cambiar a un código de producción.

El ejemplo de muestra completo se divide en dos partes.

A.Creando una biblioteca .dll (MyDLL.dll)

B.Creación de una aplicación que utiliza la biblioteca .dll (Aplicación).

A.Archivo de proyecto .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.Proyecto de aplicación que carga y vincula el archivo .dll ya creado:

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

Recientemente me hice exactamente la misma pregunta y resumí mis hallazgos. en una publicación de blog.Lo podrías encontrar útil.

Cubre la exportación de clases de C++ desde una DLL, así como la carga dinámica con LoadLibrary, y analiza algunos de los problemas relacionados con esto, como la gestión de la memoria, la manipulación de nombres y las convenciones de llamada.

Si está dispuesto a colocar una vtable en la clase que está exportando, puede exportar una función que devuelva una interfaz e implementar la clase en el .dll y luego colocarla en el archivo .def.Quizás tengas que hacer algunos trucos de declaración, pero no debería ser demasiado difícil.

Como COM.:)

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top