通过PostThreadMessage发送WM_QUIT时触发访问违例求助
解决PostThreadMessage发送WM_QUIT引发访问违例的问题
看起来你遇到的访问违例问题根源其实出在线程函数里的MSG指针未分配内存,再加上对GetMessage参数的理解偏差,咱们一步步拆解解决:
1. 核心错误:未初始化MSG指针导致访问违例
你的原线程函数里写了:
LPMSG msg = { 0 }; while (GetMessage(msg, NULL, 0, 0) != 0) { ... }
LPMSG是指向MSG结构体的指针,你把它初始化为NULL后直接传给GetMessage,GetMessage会尝试往这个空指针指向的内存写消息数据,这必然触发访问违例!
正确的做法是使用栈上的MSG实例,而不是未分配内存的指针:
MSG msg = { 0 }; // 栈上分配结构体,而非空指针 while (GetMessage(&msg, NULL, 0, 0) != 0) { TranslateMessage(&msg); DispatchMessage(&msg); }
2. 为什么修改后的循环依然有问题?
你后来改成了:
while ( GetMessage(msg, hWnd, 0, 0) ) { if ( msg->message == WM_QUIT ) { break; } else { TranslateMessage(&msg); DispatchMessage(&msg); } }
这里有两个关键问题:
- 依然用了未分配内存的
msg指针,访问msg->message还是会触发内存错误; GetMessage的第二个参数指定了hWnd,但WM_QUIT是线程级消息,不属于任何窗口,指定hWnd后GetMessage只会接收该窗口的消息,根本捕获不到WM_QUIT,循环永远不会退出。
3. 正确的线程终止流程
修正后的线程函数
先把线程函数里的MSG变量和循环改正确,同时调整错误检查的顺序(先检查资源是否成功获取,避免后续无效操作):
unsigned __stdcall keyloggingmanager::RunKeyLogger(void * args) { UNREFERENCED_PARAMETER(args); wcout << "RunKeyLogger Thread Started !" << endl; HINSTANCE appInstance = GetModuleHandle(NULL); if (!appInstance) { wcout << L"UNABLE TO GET MODULE HANDLE" << endl; return 1; } HHOOK _keyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, ThisObj->KeyPressHandler, appInstance, 0); if (!_keyboardHook) { wcout << L"UNABLE TO HOOK" << endl; return 1; } MSG msg = { 0 }; // 栈上分配MSG结构体 while (GetMessage(&msg, NULL, 0, 0) != 0) { TranslateMessage(&msg); DispatchMessage(&msg); } wcout << L"Got WM_QUIT, aborting..." << endl; UnhookWindowsHookEx(_keyboardHook); return 0; }
终止线程的注意事项
调用PostThreadMessage时,要确保:
- 目标线程已经进入了
GetMessage循环(线程第一次调用GetMessage/PeekMessage时,系统会自动创建消息队列,此时才能接收线程消息); - 如果担心线程还没准备好,可以先调用一次
PeekMessage触发消息队列创建,再发送WM_QUIT; - 发送后可以检查返回值,处理发送失败的情况:
// 确保AboveThreadId是有效的线程ID if (PostThreadMessage(AboveThreadId, WM_QUIT, 0, 0) == FALSE) { wcout << L"Failed to post WM_QUIT message: " << GetLastError() << endl; }
额外提示:WH_KEYBOARD_LL钩子的特殊性
WH_KEYBOARD_LL是一种特殊的全局钩子,它不需要注入到其他进程,而是在当前线程的消息队列中处理钩子回调。所以你的线程消息循环必须持续运行,一旦退出循环,钩子就会失效,这部分你的原代码逻辑是对的,只要修正MSG的问题就能正常退出。
内容的提问来源于stack exchange,提问作者rafiki
相关产品推荐
相关产品推荐

