WM_QUIT only messages for the stream, not windows?

In the Windows API, I learn how the GetMessage function works. I have seen 3 Windows message loop implementations and would like to learn them.


one)

At the time of this writing, this MSDN article describes what I think is the right way to implement a message loop.

 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)

On the GetMessage page, I see this implementation:

 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)

Finally, Visual Studio Documentation has this implementation as part of a demonstration of Win32 applications.

 MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } 


Discussion

In short, implementation # 3 ignores errors returned from GetMessage , but otherwise works the same way as the first implementation. That is, they process all messages for the current thread. And when the GetMessage function returns 0 , the loops end.

Since I found implementation # 2 to # 1, I thought it was complete. However, I noticed that GetMessage does not return 0 when a WM_QUIT message WM_QUIT sent via PostQuitMessage

This led to some confusion until I found implementation # 1 and tested it. The difference between the first two implementations is the second GetMessage parameter. In # 2, it points to hWnd , which according to the GetMessage documentation:

handle to the window whose messages should be received. The window must belong to the current thread.

In # 1, this is NULL related to this excerpt:

If hWnd is NULL, GetMessage retrieves messages for any window belonging to the current thread, and any messages in the current thread's message queue whose hwnd is NULL (see MSG structure). Therefore, if hWnd is NULL, both window messages and stream messages are processed.

When testing using NULL , the GetMessage function returns 0 when processing the WM_QUIT message, successfully completing the loop.

Questions

  • Even if PostQuitMessage is called from a specific window callback function, does WM_QUIT belong to the window or the current thread? Based on testing these three implementations, it seems to be related to the current thread.

  • If it is thread related, when is it useful or advisable to use a valid hWnd as a parameter for GetMessage ? Such a message loop will not be able to return 0 in response to WM_QUIT , so is there any other way that the message loop should end?

References

The code

 #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; } 
+8
c ++ windows winapi message-queue
source share
2 answers

In MSDN WM_QUIT :

The WM_QUIT message is not associated with a window and therefore will never be received through a window procedure. It is retrieved only with the GetMessage or PeekMessage functions.

Since WM_QUIT not associated with the window, and passing the HWND to GetMessage() returns only those messages associated with this window, the latter will never receive WM_QUIT by design.

As for when you want to pass HWND to GetMessage() , you wouldn’t do that in the general message loop for the application. But there are times when you want to download messages until something happens in the user interface, and they concern only messages associated with a particular window.

+5
source share

WM_QUIT refers to the stream, not to a single window. Note the absence of the hwnd parameter for PostQuitMessage() . There can be nothing specific to the window, because there is no way to say in which window you want to generate a message.

WM_QUIT is not really a real message. When you call PostQuitMessage() , in the message queue state, the internal flag that WM_QUIT requested was WM_QUIT . This will be automatically generated using GetMessage() or PeekMessage() at some point in the future (often immediately, but if the queue contains other published messages, they will be processed first).

This is explained in more detail on the Raymond Chen blog , which also contains the following quote:

As another special behavior, the generated WM_QUIT message bypasses the message filters passed to the GetMessage and PeekMessage functions. If the "Pending exit" internal flag is set, you will receive a WM_QUIT message when the queue is calm, regardless of which filter you pass.

This suggests that your observations are erroneous and that GetMessage() in your example # 2 above should return 0 after calling PostQuitMessage() , even if a filter parameter is provided.

In general, you should use message filters if you have a specific need for them (for example, you specifically want to receive a message sent to a specific window). In most cases, these parameters should be set to 0 for the normal functioning of your user interface.

+4
source share

All Articles