在Windows API中,我正在研究GetMessage
函数的实际工作方式。我已经看过Windows消息循环的3种实现,并希望对其进行探讨。
1)
在撰写本文时,this MSDN article描述了我认为是实现消息循环的正确方法。
MSG msg;
BOOL bRet;
while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
{
if (bRet == -1)
{
// handle the error and possibly exit
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
2)
在
GetMessage
function page上,我看到了以下实现:MSG msg;
BOOL bRet;
while( (bRet = GetMessage( &msg, hWnd, 0, 0 )) != 0)
{
if (bRet == -1)
{
// handle the error and possibly exit
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
3)
最后,Visual Studio documentation将此实现作为其Win32 Application演示的一部分。
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
讨论
简而言之,实现方案3忽略了从
GetMessage
返回的错误,但其他方面与第一个实现方案相同。也就是说,它们都处理当前线程的所有消息。当GetMessage
函数返回0
时,循环终止。由于我在#1之前找到了实现#2,因此我认为它已经完成。但是,我注意到通过
GetMessage
发布0
消息时WM_QUIT
不会返回PostQuitMessage
这导致了一些困惑,直到我找到实现#1并对其进行了测试。前两个实现之间的区别是
GetMessage
的第二个参数。在#2中,它指定hWnd
,根据GetMessage
文档,它是:在#1中,是
NULL
,它与以下摘录有关:当使用
NULL
进行测试时,GetMessage
函数在处理0
消息时会返回WM_QUIT
,从而成功终止循环。问题
PostQuitMessage
,但WM_QUIT
实际上是否属于该窗口或当前线程?根据对这三个实现的测试,它似乎与当前线程相关联。 hWnd
作为GetMessage
的参数有用或合适?这样的消息循环将无法返回0
作为对WM_QUIT
的响应,那么消息循环是否应该终止? 引用
GetMessage
PostQuitMessage
WM_QUIT
Message 代码
#include <Windows.h>
#include <tchar.h>
#include <strsafe.h>
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch(msg)
{
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, msg, wParam, lParam);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR cmdLine, int nCmdShow) {
LPCTSTR wndClassName =_T("Class_SHTEST");
LPCTSTR wndName = _T("SHTest");
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW|CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
wcex.hCursor = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW));
wcex.hbrBackground = (HBRUSH) COLOR_WINDOW+1;
wcex.lpszMenuName = NULL;
wcex.lpszClassName = wndClassName;
wcex.hIconSm = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
if (!RegisterClassEx(&wcex))
{
MessageBox(NULL, _T("Call to RegisterClassEx failed!"), wndName, MB_OK|MB_ICONERROR);
}
HWND window = CreateWindow(wndClassName, wndName,
WS_OVERLAPPEDWINDOW | WS_MAXIMIZE,
0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL);
if (!window) {
MessageBox(NULL, _T("Call to CreateWindow failed!"), wndName, MB_OK|MB_ICONERROR);
}
ShowWindow(window, SW_SHOW);
UpdateWindow(window);
//Message loop (using implementation #1)
MSG msg;
BOOL bRet;
while((bRet = GetMessage(&msg, NULL, 0, 0)) != 0) {
if (bRet == -1) {
//Handle error and possibly exit.
}
else {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
//Return the exit code in the WM_QUIT message.
return (int) msg.wParam;
}
最佳答案
根据WM_QUIT
的MSDN documention:
由于WM_QUIT
与窗口不相关,并且将HWND
传递给GetMessage()
仅检索与该窗口相关联的那些消息,因此后者在设计上将永远不会收到WM_QUIT
。
至于何时要将HWND
传递给GetMessage()
,则不需要在应用程序的常规消息循环中传递。但是有时候,您希望在UI中发生某些事情时泵送消息,而只关心与特定窗口关联的消息。
关于c++ - WM_QUIT只为线程而不是窗口发帖吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/32768924/