简体   繁体   English

无法从C应用程序访问C ++ DLL中的变量

[英]Can't access variable in C++ DLL from a C app

I'm stuck on a fix to a legacy Visual C++ 6 app. 我坚持修复传统的Visual C ++ 6应用程序。 In the C++ DLL source I have put 在我放的C ++ DLL源代码中

extern "C" _declspec(dllexport) char* MyNewVariable = 0;

which results in MyNewVariable showing up (nicely undecorated) in the export table (as shown by dumpbin /exports blah.dll). 这导致MyNewVariable在导出表中显示(很好地未修饰)(如dumpbin / exports blah.dll所示)。 However, I can't figure out how to declare the variable so that I can access it in a C source file. 但是,我无法弄清楚如何声明变量,以便我可以在C源文件中访问它。 I have tried various things, including 我尝试过各种各样的东西,包括

_declspec(dllimport) char* MyNewVariable;

but that just gives me a linker error: 但这只是给我一个链接器错误:

unresolved external symbol "__declspec(dllimport) char * MyNewVariable" (__imp_?MyNewVariable@@3PADA) 未解析的外部符号“__declspec(dllimport)char * MyNewVariable”(__ imp_?MyNewVariable @@ 3PADA)

extern "C" _declspec(dllimport) char* MyNewVariable;

as suggested by Tony (and as I tried before) results in a different expected decoration, but still hasn't removed it: 正如Tony所建议的(以及我之前尝试过的)会产生不同的预期装饰,但仍然没有将其删除:

unresolved external symbol __imp__MyNewVariable 未解析的外部符号__imp__MyNewVariable

How do I write the declaration so that the C++ DLL variable is accessible from the C app? 如何编写声明,以便可以从C应用程序访问C ++ DLL变量?


The Answer 答案

As identified by botismarius and others (many thanks to all), I needed to link with the DLL's .lib. 由botismarius和其他人确认(非常感谢所有),我需要链接DLL的.lib。 To prevent the name being mangled I needed to declare it (in the C source) with no decorators, which means I needed to use the .lib file. 为了防止名称被破坏,我需要声明它(在C源代码中)没有装饰器,这意味着我需要使用.lib文件。

you must link against the lib generated after compiling the DLL. 你必须链接编译DLL后生成的lib。 In the linker options of the project, you must add the .lib file. 在项目的链接器选项中,必须添加.lib文件。 And yes, you should also declare the variable as: 是的,你还应该将变量声明为:

extern "C" { declspec(dllimport) char MyNewVariable; }

extern "C" is how you remove decoration - it should work to use: extern“C”是你如何删除装饰 - 它应该工作使用:

extern "C" declspec(dllimport) char MyNewVariable; extern“C”declspec(dllimport)char MyNewVariable;

or if you want a header that can be used by C++ or C (with /TC switch) 或者如果你想要一个可以被C ++或C使用的头文件(带/ TC开关)

#ifdef __cplusplus
extern "C" {
#endif
declspec(dllimport) char MyNewVariable;
#ifdef __cplusplus
}
#endif

And of course, link with the import library generated by the dll doing the export. 当然,还要与执行导出的dll生成的导入库链接。

I'm not sure who downmodded botismarius, because he's right. 我不确定是谁修改了botismarius,因为他是对的。 The reason is the .lib generated is the import library that makes it easy to simply declare the external variable/function with __declspec(dllimport) and just use it. 原因是.lib生成的是导入库,可以很容易地使用__declspec(dllimport)简单地声明外部变量/函数并使用它。 The import library simply automates the necessary LoadLibrary() and GetProcAddress() calls. 导入库只是自动执行必要的LoadLibrary()GetProcAddress()调用。 Without it, you need to call these manually. 没有它,您需要手动调用它们。

They're both right. 他们都是对的。 The fact that the error message describes __imp_?MyNewVariable@@3PADA means that it's looking for the decorated name, so the extern "C" is necessary. 错误消息描述__imp_?MyNewVariable@@3PADA意味着它正在寻找装饰名称,因此extern“C”是必要的。 However, linking with the import library is also necessary or you'll just get a different link error. 但是,链接到导入库也是必要的,否则您将获得不同的链接错误。

@Graeme: You're right on that, too. @Graeme:你也是对的。 I think the "C" compiler that the OP is using is not enforcing C99 standard, but compiling as C++, thus mangling the names. 我认为OP使用的“C”编译器不是强制执行C99标准,而是编译为C ++,因此会破坏名称。 A true C compiler wouldn't understand the "C" part of the extern "C" keyword. 真正的C编译器不会理解extern "C"关键字的“C”部分。

In the dll source code you should have this implementation so that the .lib file exports the symbol: dll源代码中,您应该具有此实现,以便.lib文件导出符号:

extern "C" _declspec(dllexport) char* MyNewVariable = 0;

The c client should use a header with this declaration so that the client code will import the symbol: c客户端应该使用带有此声明的标头 ,以便客户端代码将导入符号:

extern "C" _declspec(dllimport) char* MyNewVariable;

This header will cause a compile error if #include-ed in the dll source code, so it is usually put in an export header that is used only for exported functions and only by clients. 如果dll源代码中包含#include-ed,则此标头将导致编译错误,因此通常将其放在导出标头中,该标头仅用于导出的函数且仅由客户端使用。

If you need to, you can also create a "universal" header that can be included anywhere that looks like this: 如果需要,您还可以创建一个“通用”标题,可以包含在以下任何位置:

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

Then the dll source code looks like this: 那么dll源代码如下所示:

#define dll_source_code 
#include "universal_header.h"

EXPORTED char* MyNewVariable = 0;

And the client looks like this: 客户端看起来像这样:

#include "universal_header.h"
...
MyNewVariable = "Hello, world";

If you do this a lot, the monster #ifdef at the top can go in export_magic.h and universal_header.h becomes: 如果你这么做了,顶部的怪物#ifdef可以进入export_magic.h并且universal_header.h变成:

#include "export_magic.h"

EXPORTED char *MyNewVariable;

I've never used _declspec(dllimport) when I was programming in Windows. 我在Windows编程时从未使用_declspec(dllimport)。 You should be able to simply declare 你应该能够简单地宣布

extern "C" char* MyNewVariable;

and link to the .libb created when DLL was compiled. 并链接到编译DLL时创建的.libb。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM