У меня есть многопоточное приложение и в определенных потоках я создаю окна с использованием ATL CWindowImpl<>
. У меня есть статический метод, который я использую в качестве процедуры потока. Мне нужно создать окно в потоке, потому что мне нужно некоторое из моего сообщения с потоком до be synchronous, а PostThreadMessage()
явно асинхронно. Когда мое окно получает сообщение WM_DESTROY
(обработчик, определяемое MESSAGE_HANDLER
макро), он вызывает PostQuitMessage()
, как показан в этом методе:Правильное закрывающее окно, созданное в отдельном потоке с использованием ATL
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' придет? Это не обязательно, если у вас нет конкретной причины. Если ваш поток здесь предназначен только для размещения окна, то просто отслеживайте «WM_NCDESTROY» в потоке потока, и как только вы его обработали для своего окна, самое время для завершения потока. –
В соответствии с [документацией] (http://msdn.microsoft.com/en-us/library/windows/desktop/ms644945%28v=vs.85%29.aspx) для 'PostQuitMessage()', эта функция API должен отправить сообщение 'WM_QUIT' в очередь сообщений потока и должно быть доступно для каждого потока. Я неверно истолковал документацию? – JimEvans
GetMessage возвращает 0 для сообщения WM_QUIT, поэтому цикл while завершается без выполнения цикла. Поэтому вам не нужен тест для == WM_QUIT –