为何C++编写的DLL函数无法调用,而C编写的DLL可正常调用?
C++ DLL函数调用失败,C DLL正常
能调用C语言(.c文件)编写的DLL中的printword()函数,但调用C++语言(.cpp文件)编写的同名DLL函数时,GetProcAddress返回ERROR_PROC_NOT_FOUND错误。
C++版DLL代码
// FILE: dllmain.cpp BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; } __declspec(dllexport) void printword() { std::cout << "word" << std::endl; // 用printf()也无法解决 }
调用代码
int main() { HMODULE dll; if ((dll = LoadLibrary(L"D:\\Visual Studio projects\\Dll1\\x64\\Debug\\Dll1.dll")) == NULL) { return GetLastError(); } FARPROC func; if ((func = GetProcAddress(dll, "printword")) == NULL) { return GetLastError(); } func(); return 0; }
C版DLL代码(可正常调用)
// FILE: dllmain.c BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; } __declspec(dllexport) void printword() { printf("word\n"); }
原因分析
问题核心是C++的名称修饰(Name Mangling)机制:
- C语言编译时,会直接以函数原名导出,比如
printword就是导出的名称; - C++为了支持函数重载、命名空间等特性,编译时会对函数名进行编码修饰,比如无参数的
printword()会被修饰成类似?printword@@YAXXZ的名称(具体格式取决于编译器)。
调用代码中用"printword"去查找,自然找不到实际导出的修饰名称,导致ERROR_PROC_NOT_FOUND。
解决方案
方法1:用extern "C"强制C语言链接规则
修改C++ DLL的函数声明,用extern "C"包裹,让编译器按C语言的规则导出函数,保留原名:
extern "C" __declspec(dllexport) void printword() { std::cout << "word" << std::endl; }
如果需要导出多个函数,可以把它们放在extern "C"块中:
extern "C" { __declspec(dllexport) void printword(); __declspec(dllexport) int add(int a, int b); }
方法2:使用模块定义文件(.def)指定导出名称
创建一个.def文件(比如Dll1.def),内容如下:
LIBRARY Dll1 EXPORTS printword @1
将该文件添加到Visual Studio项目中,编译后DLL会按照指定的原名导出函数,无需修改代码中的函数声明。
验证方式
可以使用Visual Studio自带的dumpbin工具查看DLL的导出表,命令如下:
dumpbin /exports Dll1.dll
对比C和未处理的C++ DLL的输出,就能直观看到名称修饰的差异。
内容的提问来源于stack exchange,提问作者FocalCoscade
相关产品推荐
相关产品推荐

