无法从C应用程序访问C ++ DLL中的变量
我被困在对旧版Visual C ++ 6应用程序的修复中。在C ++ DLL源代码中,我已经输入了
extern "C" _declspec(dllexport) char* MyNewVariable = 0;
这将导致MyNewVariable在导出表中显示(几乎未修饰)(如dumpbin / exports blah.dll所示)。但是,我不知道如何声明该变量,以便可以在C源文件中访问它。我尝试过各种方法,包括
_declspec(dllimport) char* MyNewVariable;
但这只是给我一个链接器错误:
无法解析的外部符号" declspec(dllimport)char * MyNewVariable"(imp_?MyNewVariable @@ 3PADA)
extern "C" _declspec(dllimport) char* MyNewVariable;
按照Tony的建议(以及我之前尝试过的结果)产生了不同的预期装饰,但仍然没有将其删除:
未解析的外部符号__imp__MyNewVariable
如何编写声明,以便可以从C应用程序访问C ++ DLL变量?
答案
正如botismarius和其他人(非常感谢所有)所指出的,我需要链接DLL的.lib。为防止名称被篡改,我需要在C语言中声明没有修饰符的名称,这意味着我需要使用.lib文件。
解决方案
回答
extern" C"是我们移除装饰使用方式的方法:
extern" C" declspec(dllimport)char MyNewVariable;
或者如果我们想要可以由C ++或者C使用的标头(通过/ TC开关)
#ifdef __cplusplus extern "C" { #endif declspec(dllimport) char MyNewVariable; #ifdef __cplusplus } #endif
当然,请链接到由dll生成的导入库,以进行导出。
回答
我们必须链接编译DLL之后生成的lib。在项目的链接器选项中,我们必须添加.lib
文件。是的,我们还应该将变量声明为:
extern "C" { declspec(dllimport) char MyNewVariable; }
回答
我不确定是谁贬低了Botismarius,因为他是对的。原因是生成的.lib是导入库,可轻松使用__declspec(dllimport)声明外部变量/函数并使用它。导入库只是自动执行必要的LoadLibrary()
和GetProcAddress()
调用。没有它,我们需要手动调用它们。
回答
他们都是对的。错误消息描述__imp_?MyNewVariable @@ 3PADA
的事实意味着它正在寻找修饰的名称,因此必须加上" C"。但是,也有必要与导入库链接,否则我们将得到另一个链接错误。
回答
@Graeme:你也是对的。我认为OP使用的" C"编译器不是强制执行C99标准,而是作为C ++进行编译,从而破坏了名称。一个真正的C编译器将无法理解extern" C"
关键字的" C"部分。
回答
在Windows中进行编程时,我从未使用过_declspec(dllimport)。我们应该可以简单地声明
extern "C" char* MyNewVariable;
并链接到编译DLL时创建的.libb。
回答
在dll源代码中,我们应该具有此实现,以便.lib文件导出符号:
extern "C" _declspec(dllexport) char* MyNewVariable = 0;
c客户端应在此声明中使用标头,以便客户端代码将导入符号:
extern "C" _declspec(dllimport) char* MyNewVariable;
如果在dll源代码中#include-ed,此头文件将导致编译错误,因此通常将其放在仅用于导出函数且仅由客户端使用的导出头文件中。
如果需要,我们还可以创建一个"通用"标头,该标头可以包含在以下任何位置:
#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;
然后,dll源代码如下所示:
#define dll_source_code #include "universal_header.h" EXPORTED char* MyNewVariable = 0;
客户看起来像这样:
#include "universal_header.h" ... MyNewVariable = "Hello, world";
如果我们经常这样做,则顶部的#ifdef怪物可以进入export_magic.h,而Universal_header.h变为:
#include "export_magic.h" EXPORTED char *MyNewVariable;