【发布时间】:2013-05-22 12:09:48
【问题描述】:
我有一个多线程应用程序,并且在某些线程上,我正在使用 ATL 的CWindowImpl<> 创建窗口。我有一个用作线程过程的静态方法。我需要在线程上创建一个窗口,因为我需要与线程进行一些通信到be synchronous,而PostThreadMessage() 是明确异步的。当我的窗口收到WM_DESTROY消息(由MESSAGE_HANDLER宏定义的处理程序)时,它调用PostQuitMessage(),如下方法所示:
LRESULT MyATLWindowClass::OnDestroy(UINT uMsg,
WPARAM wParam,
LPARAM lParam,
BOOL& bHandled) {
::PostQuitMessage(0);
return 0;
}
我正在使用PostThreadMessage() 向线程发送自定义消息,以向线程指示是时候自行终止了。处理该自定义消息时,我调用了CWindowImpl::DestroyWindow() 方法,该方法似乎可以正确地破坏窗口,因为我的OnDestroy 消息处理程序正在被调用。但是,拥有线程似乎从未收到WM_QUIT 消息进行处理。下面是我的线程过程的简化版本。
unsigned int WINAPI MyATLWindowClass::ThreadProc(LPVOID lpParameter) {
// Initialize COM on the thread
::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
// Create the window using ATL
MyATLWindowClass new_window;
HWND session_window_handle = new_window.Create(
/* HWND hWndParent */ HWND_MESSAGE,
/* _U_RECT rect */ CWindow::rcDefault,
/* LPCTSTR szWindowName */ NULL,
/* DWORD dwStyle */ NULL,
/* DWORD dwExStyle */ NULL,
/* _U_MENUorID MenuOrID */ 0U,
/* LPVOID lpCreateParam */ NULL);
// Initialize the message pump on the thread.
MSG msg;
::PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
// Run the message loop
BOOL get_message_return_value;
while ((get_message_return_value = ::GetMessage(&msg, NULL, 0, 0)) != 0) {
if (get_message_return_value == -1) {
// GetMessage handling logic taken from MSDN documentation
break;
} else {
if (msg.message == WD_SIGNAL_THREAD_SHUTDOWN) {
// Requested thread shutdown, so destroy the window
new_window.DestroyWindow();
} else if (msg.message == WM_QUIT) {
// Process the quit message and exit the message loop
// to terminate the thread
break;
} else {
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
}
}
// Uninitialize COM on the thread before exiting
::CoUninitialize();
return 0;
}
请注意,我是否调用DestroyWindow() 或向窗口发送WM_CLOSE 消息似乎并不重要。在这两种情况下,线程的消息泵都没有接收到 WM_QUIT。拥有线程的消息泵应该接收这样的消息吗?我对线程的消息泵和窗口的消息泵如何交互的误解在哪里?或者关于 ATL 的窗口类如何创建和管理窗口,我缺少什么?
【问题讨论】:
-
WM_QUIT是终止整个应用程序,而你只是在破坏你的窗口......为什么你期望WM_QUIT来?除非您有特定原因,否则它不必在那里。如果您的线程仅用于托管窗口,那么只需在线程 proc 上监视WM_NCDESTROY,一旦您为窗口处理了它,就该关闭线程了。 -
根据the documentation for
PostQuitMessage(),该API 函数应该将WM_QUIT消息发布到线程的消息队列,并且应该可以在每个线程的基础上使用。我是否误解了文档? -
GetMessage 为 WM_QUIT 消息返回 0,因此您的 while 循环终止而不执行循环体。所以你不需要测试 == WM_QUIT
-
@ScottMcP-MVP 啊哈!那就是我缺少的那部分。我在
GetMessage文档中忽略了那篇文章。感谢您指出。
标签: c++ multithreading winapi com atl