我在导入C ++函数时遇到问题。如果我将它们声明为C函数,我可以成功导入它们。当显式加载时,如果任何函数缺少extern作为C装饰,我会得到以下异常:
First-chance exception at 0x00000000 in cpp.exe: 0xC0000005: Access violation.
DLL.h:
extern "C" __declspec(dllimport) int addC(int a, int b);
__declspec(dllimport) int addCpp(int a, int b);
DLL.cpp:
#include "DLL.h"
int addC(int a, int b) {
return a + b;
}
int addCpp(int a, int b) {
return a + b;
}
main.cpp中:
#include "..DLL/DLL.h"
#include <stdio.h>
#include <windows.h>
int main() {
int a = 2;
int b = 1;
typedef int (*PFNaddC)(int,int);
typedef int (*PFNaddCpp)(int,int);
HMODULE hDLL = LoadLibrary(TEXT("../Debug/DLL.dll"));
if (hDLL != NULL)
{
PFNaddC pfnAddC = (PFNaddC)GetProcAddress(hDLL, "addC");
PFNaddCpp pfnAddCpp = (PFNaddCpp)GetProcAddress(hDLL, "addCpp");
printf("a=%d, b=%d\n", a,b);
printf("pfnAddC: %d\n", pfnAddC(a,b));
printf("pfnAddCpp: %d\n", pfnAddCpp(a,b)); //EXCEPTION ON THIS LINE
}
getchar();
return 0;
}
如何导入动态加载的c ++函数?我发现以下代码通过引用* .lib来隐式加载,但我想了解动态加载。
提前谢谢大家。
更新 bindump / exports
1 00011109 ?addCpp@@YAHHH@Z = @ILT+260(?addCpp@@YAHHH@Z)
2 00011136 addC = @ILT+305(_addC)
解决方案:
看一下 文件导出和显式复制 c ++ mangle命名约定。
PFNaddCpp pfnAddCpp =(PFNaddCpp)GetProcAddress(hDLL,“?addCpp @@ YAHHH @ Z”);
答案 0 :(得分:1)
不可避免地,空指针上的访问冲突是因为GetProcAddress()
在出错时返回null。
问题是编译器的C ++名称是mangled,以适应各种C ++特性(名称空间,类和重载等)。因此,您的函数addCpp()
在结果库中并未真正命名为addCpp()
。当您使用extern "C"
声明函数时,您放弃了重载以及将函数放在命名空间中的选项,但作为回报,您将得到一个名称不受损坏的函数,您可以从C代码调用该函数(对名称损坏一无所知。)
解决此问题的一个方法是export the functions using a .def file重命名导出的函数。有一篇文章Explicitly Linking to Classes in DLLs描述了执行此操作所必需的内容。
答案 1 :(得分:0)
可以将整个头文件包装在extern "C"
中,如下所示。然后,您无需担心忘记其中一个声明的extern "C"
。
#ifdef __cplusplus
extern "C" {
#endif
__declspec(dllimport) int addC(int a, int b);
__declspec(dllimport) int addCpp(int a, int b);
#ifdef __cplusplus
} /* extern "C" */
#endif
你仍然可以使用你在函数体中习惯的所有C ++特性 - 这些函数仍然是C ++函数 - 它们只是对原型有限制,使它们与C代码兼容。