Есть 2 проблемы с этим кодом.
::GetMessage()
не останавливается, потому что вы используете параметр hWnd
с чем-то другим, чем NULL
.Вам нужно получить сообщения thread , чтобы получить ::GetMessage()
для возврата 0
. - Следуя логике в (1), вам нужно опубликовать сообщение, используя
::PostThreadMessage()
дляпоместите его в очередь сообщений потока.
Все это довольно хорошо иллюстрируется тем фактом, что ::PostQuitMessage(status)
является сокращением для
::PostThreadMessage(::GetCurrentThreadId(), WM_QUIT, status, 0);
EDIT :
Кажется, что людей заставили думать, что ::PostThreadMessage(...,WM_QUIT,...);
не работает, потому что он не получает специальной обработки установки флага QS_QUIT
, установленного ::PostQuitMessage()
.Если бы это было так, то не было бы никакого способа отправить WM_QUIT
в очередь сообщений другого потока.Вот доказательство того, что оно работает в любом случае.
В частности, обратите внимание на константы Use_PostQuitMessage
и GetMessage_UseWindowHandle
.Не стесняйтесь изменять значения и поиграть с кодом.Он работает так же, как указано в моем ответе, за исключением того, что я по ошибке использовал ::GetCurrentThread()
вместо ::GetCurrentThreadId()
, прежде чем попробовать.
#include <Windows.h>
#include <iomanip>
#include <iostream>
namespace {
// Doesn't matter if this is 'true' or 'false'.
const bool Use_PostQuitMessage = false;
// Setting this to 'true' prevents the application from closing.
const bool GetMessage_UseWindowHandle = false;
void post_quit_message ()
{
if ( Use_PostQuitMessage ) {
::PostQuitMessage(0);
}
else {
::PostThreadMessageW(::GetCurrentThreadId(), WM_QUIT, 0, 0);
}
}
::BOOL get_message ( ::HWND window, ::MSG& message )
{
if ( GetMessage_UseWindowHandle ) {
return (::GetMessageW(&message, window, 0, 0));
}
else {
return (::GetMessageW(&message, 0, 0, 0));
}
}
::ULONG __stdcall background ( void * )
{
// Allocate window in background thread that is to be interrupted.
::HWND window = ::CreateWindowW(L"STATIC", 0, WS_OVERLAPPEDWINDOW,
0, 0, 512, 256, 0, 0, ::GetModuleHandleW(0), 0);
if ( window == 0 ) {
std::cerr << "Could not create window." << std::endl;
return (EXIT_FAILURE);
}
// Process messages for this thread's windows.
::ShowWindow(window, SW_NORMAL);
::MSG message;
::BOOL result = FALSE;
while ((result = get_message(window,message)) > 0)
{
// Handle 'CloseWindow()'.
if ( message.message == WM_CLOSE )
{
post_quit_message(); continue;
}
// Handling for 'ALT+F4'.
if ((message.message == WM_SYSCOMMAND) &&
(message.wParam == SC_CLOSE))
{
post_quit_message(); continue;
}
// Dispatch message to window procedure.
::TranslateMessage(&message);
::DispatchMessageW(&message);
}
// Check for error in 'GetMessage()'.
if ( result == -1 )
{
std::cout << "GetMessage() failed with error: "
<< ::GetLastError() << "." << std::endl;
return (EXIT_FAILURE);
}
return (EXIT_SUCCESS);
}
}
int main ( int, char ** )
{
// Launch window & message pump in background thread.
::DWORD id = 0;
::HANDLE thread = ::CreateThread(0, 0, &::background, 0, 0, &id);
if ( thread == INVALID_HANDLE_VALUE ) {
std::cerr << "Could not launch thread." << std::endl;
return (EXIT_FAILURE);
}
// "do something"...
::Sleep(1000);
// Decide to close application.
::PostThreadMessageW(id, WM_QUIT, 0, 0);
// Wait for everything to shut down.
::WaitForSingleObject(thread, INFINITE);
// Return background thread's success code.
::DWORD status = EXIT_FAILURE;
::GetExitCodeThread(thread,&status);
return (status);
}
PS :
Чтобы на самом деле протестировать однопоточное использование ::PostThreadMessage(::GetCurrentThreadId(),...);
, вызовите ::background(0);
в main вместо запуска потока.