C++程序调用DLL函数失败问题排查及正确实现方案
问题描述
我正尝试使用C++17编写程序调用共享库DLL中的函数。
待调用的DLL由名为test.cpp的C++文件编译而来,该文件仅包含一个test函数:
#include <iostream> int test() { std::cout << "test\n"; return 0; }
通过Visual Studio 2022原生命令提示符执行以下命令编译:
cl.exe /LD test.cpp
生成名为test.dll的DLL文件。
我参考相关技术文档编写了加载DLL函数的程序:
#include <iostream> #include <string> #include <windows.h> #include <locale> #include <codecvt> std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> StringConverter; typedef int(__stdcall* DLLFx)(); std::string GetWorkingDir() { TCHAR buffer[MAX_PATH] = { 0 }; GetModuleFileName(NULL, buffer, MAX_PATH); std::wstring::size_type pos = std::wstring(buffer).find_last_of(L"\\/"); return StringConverter.to_bytes(std::wstring(buffer).substr(0, pos).c_str()) + "\\"; } bool LoadDLLFunction(std::string libPath, std::string fxName) { HINSTANCE hGetProcIDDLL = LoadLibrary((WCHAR*)StringConverter.from_bytes(libPath.c_str()).data()); if (!hGetProcIDDLL) { std::cout << "ERROR: Could not locate DLL file\"" + libPath + "\"!\n"; return false; } DLLFx fx = (DLLFx)GetProcAddress(hGetProcIDDLL, (CHAR*)StringConverter.from_bytes(fxName.c_str()).data()); if (!fx) { std::cout << "ERROR: Could not locate function \"" + fxName + "\" in DLL file \"" + libPath + "\"!\n"; return false; } return true; } int main() { std::string workDir = GetWorkingDir(); bool result = LoadDLLFunction(workDir + "test.dll", "test"); if (result) { std::cout << "Result of loaded DLL function call: " << DLLFx() << "\n"; } std::cout << "\n"; system("pause"); return 0; }
程序中的关键部分说明:
- 全局变量
StringConverter用于将常规std::string转换为Windows API所需的std::wstring类型(C++17及以后已废弃)。 - 全局类型定义
DLLFx是指向DLL中加载函数的指针类型。 GetWorkingDir函数用于获取程序当前工作目录。LoadDLLFunction函数用于加载DLL中的函数。
我尝试调用加载的函数并显示返回结果(预期返回0,同时控制台打印test字符串),但程序能找到并加载DLL,却无法定位其中的test函数,始终输出错误信息:ERROR: Could not locate function "test" in DLL file "test.dll"!。
我猜测可能是DLL路径或函数名的字符串转换问题,但不确定是否遗漏了底层字符串机制。
尝试修改记录
根据相关建议,我对test.cpp进行了修改,添加extern "C"和__declspec(dllexport)标记,同时添加DllMain函数:
#include <iostream> #include <windows.h> 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; } extern "C" { int __declspec(dllexport) test() { std::cout << "test\n"; return 0; } }
重新编译为test.dll后,执行dumpbin /exports test.dll命令,输出显示test已被导出:
Dump of file test.dll File Type: DLL Section contains the following exports for test.dll 00000000 characteristics FFFFFFFF time date stamp 0.00 version 1 ordinal base 1 number of functions 1 number of names ordinal hint RVA name 1 0 00001180 test Summary 3000 .data 3000 .pdata 12000 .rdata 1000 .reloc 23000 .text 1000 _RDATA
但程序仍无法定位test函数。我还尝试简化GetProcAddress的函数名参数为fxName.c_str(),以及修改函数名为test_fx,均未解决问题。
我想知道究竟遗漏了什么?从C++程序加载并调用DLL函数的正确方法是什么?
内容的提问来源于stack exchange,提问作者Runsva
相关产品推荐
相关产品推荐

