Pergunta

A maior parte do meu desenvolvimento em C/C++ envolve arquivos de módulos monolíticos e absolutamente nenhuma classe, então geralmente quando preciso fazer um DLL com funções acessíveis, acabei de exportá-las usando o padrão __declspec(dllexport) diretiva.Em seguida, acesse-os dinamicamente via LoadLibrary() ou em tempo de compilação com um cabeçalho e um arquivo lib.

Como você faz isso quando deseja exportar uma classe inteira (e todos os seus métodos e propriedades públicas)?

É possível carregar dinamicamente essa classe em tempo de execução e, em caso afirmativo, como?

Como você faria isso com um cabeçalho e uma biblioteca para vinculação em tempo de compilação?

Foi útil?

Solução

E quanto à vinculação tardia?Como no carregamento com loadlibrary () e getProcaddress ()?Estou acostumado a carregar a biblioteca no tempo de execução e seria ótimo se você pudesse fazer isso aqui.

Portanto, existem duas maneiras de carregar a DLL.A primeira é fazer referência a um ou mais símbolos da DLL (seu nome de classe, por exemplo), fornecer um import .LIB apropriado e deixar o vinculador descobrir tudo.

A segunda é carregar explicitamente a DLL via LoadLibrary.

Qualquer abordagem funciona bem para exportações de funções de nível C.Você pode deixar o vinculador cuidar disso ou chamar GetProcAddress conforme observado.

Mas quando se trata de exportação Aulas, normalmente apenas a primeira abordagem é usada, ou seja, vincular implicitamente à DLL.Nesse caso, a DLL é carregada no momento de início do aplicativo e o aplicativo falha ao carregar se a DLL não for encontrada.

Se você deseja vincular a uma classe definida em uma DLL e deseja que essa DLL seja carregada dinamicamente, algum tempo após o início do programa, você tem duas opções:

  1. Crie objetos da classe usando uma função especial de fábrica, que internamente terá que usar (um pouquinho de) assembler para "conectar" objetos recém-criados aos seus deslocamentos apropriados.Isso deve ser feito em tempo de execução APÓS o carregamento da DLL, obviamente.Uma boa explicação desta abordagem pode ser encontrada aqui.

  2. Use um DLL de carregamento atrasado.

Considerando todas as coisas...provavelmente é melhor usar a vinculação implícita; nesse caso, você definitivamente deseja usar a técnica de pré-processador mostrada acima.Na verdade, se você criar uma nova DLL no Visual Studio e escolher a opção “exportar símbolos” essas macros serão criadas para você.

Boa sorte...

Outras dicas

Quando você construir a DLL e o módulo que usará a DLL, tenha algum tipo de #define que você possa usar para distinguir entre um e outro, então você pode fazer algo assim no arquivo de cabeçalho da sua classe:

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

Editar:crashmstr me venceu!

Utilizo algumas macros para marcar o código para importação ou exportação

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

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

Em seguida, declare a classe em um arquivo de cabeçalho:

class DLL MyClassToExport { ... }

Então #define ISDLL na biblioteca e USEDLL antes de incluir o arquivo de cabeçalho no local onde deseja usar a classe.

Não sei se você precisará fazer algo diferente para trabalhar com LoadLibrary

Adicionando um exemplo simples de trabalho para exportar uma classe C++ de uma DLL:

O exemplo abaixo fornece apenas uma breve visão geral de como dll e exe podem interagir entre si (autoexplicativo), mas precisa de mais coisas para adicionar para mudar para um código de produção.

O exemplo completo da amostra está dividido em duas partes

A.Criando uma biblioteca .dll (MyDLL.dll)

B.Criando um aplicativo que usa a biblioteca .dll (aplicativo).

A.Arquivo de projeto .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.Projeto de aplicação que carrega e vincula o arquivo .dll já criado:

 #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 me fiz exatamente a mesma pergunta e resumi minhas descobertas em uma postagem de blog.Você pode achar útil.

Abrange a exportação de classes C++ de uma DLL, bem como o carregamento delas dinamicamente com LoadLibrary, e discute algumas das questões relacionadas a isso, como gerenciamento de memória, manipulação de nomes e convenções de chamada.

Se você deseja colocar uma vtable na classe que está exportando, você pode exportar uma função que retorna uma interface e implementar a classe no .dll e, em seguida, colocá-la no arquivo .def.Talvez você precise fazer alguns truques de declaração, mas não deve ser muito difícil.

Assim como COM.:)

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top