【发布时间】:2011-10-13 20:10:51
【问题描述】:
所以在我的 Window 类中获取 WM_KEYDOWN 消息时出现了一个奇怪的错误。
我有一个全局 WndProc 函数,它确定它是哪个窗口实例并将消息发送到它自己的本地 WndProc 函数。
//Every Windows Message will hit this function.
LRESULT CALLBACK GlobalWndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
//Get the Window Instance from the userdata
Window* targetWindow = (Window*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
//If no window exists, then it must be the first time so we should set it
if (!targetWindow) {
//First let's try and extract the Window instance pointer from the lparam
CREATESTRUCT* createStruct = (CREATESTRUCT*)lparam;
if (createStruct) {
targetWindow = (Window*)createStruct->lpCreateParams;
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)targetWindow);
}
else {
//It was some other message which we just can't deal with right now
return DefWindowProc(hwnd, msg, wparam, lparam);
}
}
//Now we can pipe it to the Window's local wnd proc function
return targetWindow->LocalWndProc(hwnd, msg, wparam, lparam);
}
而我的本地 wndproc 看起来像这样:
LRESULT CALLBACK Window::LocalWndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
switch (msg) {
case WM_KEYDOWN:
ToggleFullScreen(!m_fullScreen);
return 0;
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
break;
case WM_CLOSE:
PostQuitMessage(0);
return 0;
break;
default:
return DefWindowProc(hwnd, msg, wparam, lparam);
}
}
所以现在很简单。如果按下任何键,窗口应调用其成员函数 ToggleFullScreen。
现在由于某种原因,当我运行此程序并按键盘上的任意键时,出现异常错误:
Athena_Debug.exe 中 0x77c015ee 处的未处理异常:0xC0000005:访问冲突读取位置 0x0000012d。
使用调用堆栈:
ntdll.dll!77c015ee()
ntdll.dll!77bf015e()
user32.dll!7588788a()
Athena_Debug.exe!Athena::Window::HandleWindowsMessage() 第 195 行 + 0xc 字节 C++ Athena_Debug.exe!Athena::AthenaCore::StartEngine() 第 96 行 + 0x12 字节 C++ Athena_Debug.exe!WinMain(HINSTANCE__ * hInstance, HINSTANCE__ * hPrevInstance, char * lpCmdLine, int nCmdShow) 第 44 行 C++ Athena_Debug.exe!__tmainCRTStartup() 第 547 行 + 0x2c 字节 C Athena_Debug.exe!WinMainCRTStartup() 第 371 行 C kernel32.dll!7702339a()
它实际中断的行是位于此处的 DispatchMessage(&msg) 行:
MSG Window::HandleWindowsMessage() {
MSG msg;
ZeroMemory(&msg, sizeof(MSG));
if (m_realTime) {
PeekMessage(&msg, m_hwnd, 0, 0, PM_REMOVE);
}
else {
GetMessage(&msg, m_hwnd, 0, 0);
}
if (msg.message != WM_NULL) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg;
}
所以有趣的是,如果我注释掉 ToggleFullScreen 而是在其中放置一个 OutputDebugTrace,它就可以正常工作并输出调试跟踪。似乎无法解析实例的功能?如果我在 ToggleFullScreen 中注释掉所有内容,它仍然会崩溃。如果我创建一个什么都不做的全新函数并调用它以响应 WM_KEYDOWN 它仍然会出错。
有人知道为什么会发生这种情况,或者对我可以如何解决它有一些想法吗?
谢谢!
【问题讨论】:
-
你确定 this 指针指向的东西在 Window::LocalWndProc 中有效吗?
-
不是问题,但您应该在 WM_CLOSE 中使用 DestroyWindow() 而不是 PostQuitMessage()
-
你不应该使用 SetWindowLong,因为它现在是空的 - 你应该测试 WM_CREATE 消息。
-
@Anders 谢谢,很高兴知道!