Win32 API调用引发访问冲突

时间:2019-08-22 03:41:12

标签: c++ winapi encoding

我有一个从DLL导出的C ++代码。

DWORD WINAPI MessageBoxThread(LPVOID lpParam)
{
    MessageBox(0, L"Test", L"Test", 0);
    return 0;
}

这就是我的称呼方式

typedef DWORD(*MessageBoxThread)(LPVOID);
int StartMessageBoxThread() {
    MessageBoxThread ShowMessageBox;
    HMODULE testModule = LoadLibrary(L"C:\\Users\\david\\COMServer.dll");
    ShowMessageBox = (MessageBoxThread)GetProcAddress(testModule, "MessageBoxThread");
    ShowMessageBox(NULL);
    FreeLibrary(testModule);
    return 0;
}

我在ShowMessageBox()行上的KernelBase.dll中引发了异常,该异常在写入内存位置时涉及访问冲突。

我不明白我在做什么错。两个Visual Studio项目都设置为Unicode,并且我知道使用L前缀表示宽字符串。

我可以调试并逐步进入DLL,可以看到函数的地址,因此调用该函数的代码看不到任何错误。

2 个答案:

答案 0 :(得分:5)

typedef DWORD(*MessageBoxThread)(LPVOID);

原型与dll中的定义不匹配。默认情况下,此处的调用约定为__cdecl,而WINAPI__stdcall

typedef DWORD(WINAPI *MessageBoxThread)(LPVOID);

具体来说,在被调用端,由于约定为__stdcall(被调用者清除堆栈),因此该函数将参数弹出堆栈。在调用者端,它看到约定为__cdecl(调用者清除了堆栈),并且还从堆栈中弹出了参数,最终破坏了堆栈。

答案 1 :(得分:3)

在您的StartMessageBoxThread()代码中,MessageBoxThread的声明不正确。具体来说,它缺少调用约定,因此它使用编译器的默认约定,通常是__cdecl而不是__stdcallWINAPI映射到的)。调用约定不匹配是崩溃,调用堆栈损坏等常见原因。

此外,该代码完全没有错误检查。

尝试以下方法:

typedef DWORD (WINAPI *MessageBoxThread)(LPVOID);

int StartMessageBoxThread()
{
    HMODULE testModule = LoadLibrary(L"C:\\Users\\david\\COMServer.dll");
    if (testModule)
    {
        MessageBoxThread ShowMessageBox = (MessageBoxThread) GetProcAddress(testModule, "MessageBoxThread");
        if (ShowMessageBox)
            ShowMessageBox(NULL);
        FreeLibrary(testModule);
    }
    return 0;
}