无法调用DLL函数:HelloWorld函数定位失败排查求助
问题
尝试调用一个仅用于显示MessageBox的DLL,但加载器无法定位其中的HelloWorld函数,程序运行后无任何反应。此前测试user32.dll的SwapMouseButton函数可正常调用。已定义导入导出,但怀疑存在错误,也不确定调用约定是否正确。相关代码如下:
原导入导出定义
#ifndef INDLL_H #define INDLL_H #ifdef EXPORTING_DLL extern __declspec(dllexport) void HelloWorld(); #else extern __declspec(dllimport) void HelloWorld(); #endif #endif
原Hello World DLL代码
/* Hello World DLL */ #include "stdafx.h" #define EXPORTING_DLL #include "sampleDLL.h" #include "pch.h" BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { return TRUE; } void HelloWorld() { MessageBox(NULL, TEXT("Hello World"), TEXT("In a DLL"), MB_OK); }
原DLL加载器代码
/* DLL Loader */ #include <windows.h> #include <iostream> typedef int(__stdcall* f_funci)(); int main() { HINSTANCE hGetProcIDDLL = LoadLibrary("PATH\\LoadME.dll"); if (!hGetProcIDDLL) { return EXIT_FAILURE; } // resolve function f_funci functon = (f_funci)GetProcAddress(hGetProcIDDLL, "HelloWorld"); if (!functon) { std::cout << "Function Could Not Be Located" << std::endl; return EXIT_FAILURE; } std::cout << "returned " << functon() << std::endl; return EXIT_SUCCESS; }
问题分析与修复
1. C++名字修饰导致函数名无法匹配
默认情况下,C编译器会对函数名进行修饰(添加参数类型、调用约定相关后缀),使得GetProcAddress无法通过原始的"HelloWorld"字符串找到函数。必须用extern "C"包裹导出函数,禁用C名字修饰。
2. 调用约定不匹配
DLL中的HelloWorld默认使用__cdecl调用约定,但加载器中定义的函数指针是__stdcall,这会导致调用栈失衡,引发崩溃或未定义行为。需要统一两者的调用约定。
3. 返回值类型不匹配
DLL中的HelloWorld是void类型,但加载器中函数指针定义为返回int,会导致调用后读取无效返回值,引发未定义行为。
4. 其他细节问题
- DLL代码中未显式包含
windows.h,虽然可能通过预编译头间接包含,但显式包含更稳妥; - 加载器中未调用
FreeLibrary释放DLL资源,可能导致资源泄漏; - 建议使用宽字符版本的
LoadLibraryW避免路径编码问题。
修正后的代码
修正后的导入导出头文件
#ifndef INDLL_H #define INDLL_H #ifdef __cplusplus extern "C" { #endif #ifdef EXPORTING_DLL #define DLL_API __declspec(dllexport) #else #define DLL_API __declspec(dllimport) #endif // 统一指定__stdcall调用约定 DLL_API void __stdcall HelloWorld(); #ifdef __cplusplus } #endif #endif
修正后的DLL代码
/* Hello World DLL */ #include "stdafx.h" #define EXPORTING_DLL #include "sampleDLL.h" #include "pch.h" #include <windows.h> BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { return TRUE; } void __stdcall HelloWorld() { MessageBox(NULL, TEXT("Hello World"), TEXT("In a DLL"), MB_OK); }
修正后的加载器代码
/* DLL Loader */ #include <windows.h> #include <iostream> // 匹配DLL中的函数签名:void返回值 + __stdcall调用约定 typedef void(__stdcall* f_HelloWorld)(); int main() { // 使用宽字符版本LoadLibraryW,替换为实际DLL路径 HINSTANCE hGetProcIDDLL = LoadLibraryW(L"PATH\\LoadME.dll"); if (!hGetProcIDDLL) { std::cout << "无法加载目标DLL" << std::endl; return EXIT_FAILURE; } f_HelloWorld HelloWorldFunc = (f_HelloWorld)GetProcAddress(hGetProcIDDLL, "HelloWorld"); if (!HelloWorldFunc) { std::cout << "无法定位HelloWorld函数" << std::endl; FreeLibrary(hGetProcIDDLL); return EXIT_FAILURE; } // 调用函数,弹出MessageBox HelloWorldFunc(); // 释放DLL资源 FreeLibrary(hGetProcIDDLL); return EXIT_SUCCESS; }
内容的提问来源于stack exchange,提问作者torrid
相关产品推荐
相关产品推荐

