Não é possível acessar variável em C++ DLL de um aplicativo C
-
09-06-2019 - |
Pergunta
Estou preso em uma correção para um aplicativo legado do Visual C++ 6.Na fonte C++ DLL eu coloquei
extern "C" _declspec(dllexport) char* MyNewVariable = 0;
o que resulta na exibição de MyNewVariable (bem sem decoração) na tabela de exportação (conforme mostrado por dumpbin /exports blah.dll).No entanto, não consigo descobrir como declarar a variável para poder acessá-la em um arquivo de origem C.Eu tentei várias coisas, incluindo
_declspec(dllimport) char* MyNewVariable;
mas isso só me dá um erro de vinculador:
símbolo externo não resolvido "__declspec(dllimport) char * MyNewVariable" (__imp_?MyNewVariable@@3PADA)
extern "C" _declspec(dllimport) char* MyNewVariable;
como sugerido por Tony (e como tentei antes) resulta em uma decoração diferente do esperado, mas ainda não a removeu:
símbolo externo não resolvido __imp__MyNewVariable
Como escrevo a declaração para que a variável DLL C++ seja acessível no aplicativo C?
A resposta
Conforme identificado por botismarius e outros (muito obrigado a todos), eu precisava vincular ao .lib da DLL.Para evitar que o nome fosse mutilado, precisei declará-lo (na fonte C) sem decoradores, o que significa que precisei usar o arquivo .lib.
Solução
você deve vincular-se à lib gerada após compilar a DLL.Nas opções do vinculador do projeto, você deve adicionar o .lib
arquivo.E sim, você também deve declarar a variável como:
extern "C" { declspec(dllimport) char MyNewVariable; }
Outras dicas
extern "C" é como você remove a decoração - deve funcionar para usar:
extern "C" declspec(dllimport) char MyNewVariable;
ou se você quiser um cabeçalho que possa ser usado por C++ ou C (com opção /TC)
#ifdef __cplusplus
extern "C" {
#endif
declspec(dllimport) char MyNewVariable;
#ifdef __cplusplus
}
#endif
E claro, linkar com a biblioteca de importação gerada pela dll que faz a exportação.
Não tenho certeza de quem reduziu o botismarius, porque ele está certo.A razão é que o .lib gerado é a biblioteca de importação que torna mais fácil simplesmente declarar a variável/função externa com __declspec(dllimport)
e apenas use-o.A biblioteca de importação simplesmente automatiza o necessário LoadLibrary()
e GetProcAddress()
chamadas.Sem ele, você precisa chamá-los manualmente.
Ambos estão certos.O fato de a mensagem de erro descrever __imp_?MyNewVariable@@3PADA
significa que está procurando o nome decorado, portanto o "C" externo é necessário.No entanto, vincular à biblioteca de importação é também necessário ou você receberá um erro de link diferente.
@Graeme:Você está certo nisso também.Acho que o compilador "C" que o OP está usando não está aplicando o padrão C99, mas compilando como C++, distorcendo assim os nomes.Um verdadeiro compilador C não entenderia a parte “C” do extern "C"
palavra-chave.
No código fonte dll você deve ter esta implementação para que o arquivo .lib exportações o símbolo:
extern "C" _declspec(dllexport) char* MyNewVariable = 0;
O cliente c deve usar um cabeçalho com esta declaração para que o código do cliente importar o símbolo:
extern "C" _declspec(dllimport) char* MyNewVariable;
Este cabeçalho causará um erro de compilação se #include-ed no código-fonte da dll, portanto, geralmente é colocado em um cabeçalho de exportação que é usado apenas para funções exportadas e apenas por clientes.
Se necessário, você também pode criar um cabeçalho "universal" que pode ser incluído em qualquer lugar parecido com este:
#ifdef __cplusplus
extern "C" {
#endif
#ifdef dll_source_file
#define EXPORTED declspec(dllexport)
#else
#define EXPORTED declspec(dllimport)
#endif dll_source_file
#ifdef __cplusplus
}
#endif
EXPORTED char* MyNewVariable;
Então o código fonte da dll fica assim:
#define dll_source_code
#include "universal_header.h"
EXPORTED char* MyNewVariable = 0;
E o cliente fica assim:
#include "universal_header.h"
...
MyNewVariable = "Hello, world";
Se você fizer muito isso, o monstro #ifdef no topo pode entrar em export_magic.h e universal_header.h se tornar:
#include "export_magic.h"
EXPORTED char *MyNewVariable;
Nunca usei _declspec(dllimport) quando estava programando no Windows.Você deve ser capaz de simplesmente declarar
extern "C" char* MyNewVariable;
e link para o .libb criado quando a DLL foi compilada.