You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何调用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 03:39:59