为何调用GetProcAddress后执行_MessageBox触发内存访问违例?
内存访问违例(0xC0000005):调用动态获取的
MessageBox时触发空指针调用 先把你提供的代码片段整理出来:
头文件内容
extern HMODULE Ws_32; extern HMODULE User32; extern HMODULE Kernel32; extern HMODULE Advapi32; typedef int (WINAPI *fnMessageBox)( _In_opt_ HWND hWnd, _In_opt_ LPCTSTR lpText, _In_opt_ LPCTSTR lpCaption, _In_ UINT uType ); struct API { HMODULE User32; fnMessageBox _MessageBox; };
CPP文件内容
API Api; VOID Tools::LoadApis(API Api) { if ((Api.User32 = GetModuleHandleW(L"USER32.DLL")) == ERROR) { Api.User32 = LoadLibraryW(L"USER32.DLL"); } if (Api.User32) { Api._MessageBox = fnMessageBox(GetProcAddress(Api.User32, "MessageBox")); } } int main() { Tools::LoadApis(Api); // 非示例核心部分 Api._MessageBox(0, 0, 0, 0); }
问题原因分析
兄弟,你这个问题其实是C++里最容易踩的值传递陷阱!
你遇到的0xC0000005访问违例,本质是调用了空指针(0x00000000)指向的函数,根源出在LoadApis函数的参数传递方式上:
- 你声明的
LoadApis函数参数是API Api,这是值传递——函数内部会创建一个传入的Api变量的副本,所有对Api的修改都是在这个副本上进行的。 - 而你在
main里传入的是全局的Api变量,函数里修改的只是它的副本,全局的Api._MessageBox从头到尾都没有被赋值,依然是默认的空指针(0x00000000)。 - 当你调用
Api._MessageBox(0,0,0,0)时,实际上是尝试跳转到0地址执行代码,这直接触发了内存访问违例。
修复方案
只需要把LoadApis的参数改成引用传递,让函数直接操作全局的Api变量即可:
VOID Tools::LoadApis(API& Api) { // 这里加&变成引用,直接操作原变量 // 注意:GetModuleHandleW失败返回NULL,不是ERROR,修正判断条件 if ((Api.User32 = GetModuleHandleW(L"USER32.DLL")) == NULL) { Api.User32 = LoadLibraryW(L"USER32.DLL"); } if (Api.User32) { // 明确指定Unicode版本的MessageBox,避免编译选项带来的问题 Api._MessageBox = reinterpret_cast<fnMessageBox>(GetProcAddress(Api.User32, "MessageBoxW")); } }
另外补充两个小细节:
GetModuleHandleW失败时返回的是NULL,不是ERROR,你原来的判断条件有问题,会导致不必要的LoadLibraryW调用。MessageBox有ANSI和Unicode两个版本,直接用"MessageBox"可能会因为项目的字符集编译选项出现问题,明确指定MessageBoxW或MessageBoxA更稳妥。
内容的提问来源于stack exchange,提问作者MinCarve
相关产品推荐
相关产品推荐

