About PostQuitMessage Function
-
Someone said that PostQuitMessage function does not really send a WM_QUIT message to the message queue of the calling thread. I wonder what does this function exactly do. //Here is a simple test code /*If PostQuitMessage function sends a WM_QUIT message to the message queue of the calling thread, GetMessage(..., hwnd, ..., ...) can't get the WM_QUIT message, the application won't leave the message loop. But in this example: 1.compile the source ; 2.Ctrl+F5 to run it; 3.D&D to move the window; 4.press the corss to close window; 5.found that the application process disappear from the "task manager " It seems that GetMessage(..., hwnd, ..., ...) got the WM_QUIT message. Someone said it's because of that PostQuitMessage is called before DestroyWindow. But I can't get the same result when debugging by F5. Sorry for my poor English......thanks for your attention. */ #include #include LRESULT CALLBACK WinSunProc( HWND hwnd, // handle to window UINT uMsg, // message identifier WPARAM wParam, // first message parameter LPARAM lParam // second message parameter ); int WINAPI WinMain( HINSTANCE hInstance, // handle to current instance HINSTANCE hPrevInstance, // handle to previous instance LPSTR lpCmdLine, // command line int nCmdShow // show state ) { BOOL bRet = FALSE; WNDCLASS wndcls; wndcls.cbClsExtra=0; wndcls.cbWndExtra=0; wndcls.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH); wndcls.hCursor=LoadCursor(NULL,IDC_CROSS); wndcls.hIcon=LoadIcon(NULL,IDI_APPLICATION); wndcls.hInstance=hInstance; wndcls.lpfnWndProc=WinSunProc; wndcls.lpszClassName="Weixin2003"; wndcls.lpszMenuName=NULL; wndcls.style=CS_HREDRAW | CS_VREDRAW; RegisterClass(&wndcls); HWND hwnd; hwnd=CreateWindow("Weixin2003","CreateWindow",WS_OVERLAPPEDWINDOW, 0,0,600,400,NULL,NULL,hInstance,NULL); ShowWindow(hwnd,SW_SHOWNORMAL); UpdateWindow(hwnd); MSG msg; while((bRet = GetMessage(&msg,hwnd,0,0)) != FALSE) { /*if(bRet == -1) { break; }*/ TranslateMessage(&msg); DispatchMessage(&msg); } return 0; } LRESULT CALLBACK WinSunProc( HWND hwnd, // handle to window UINT uMsg, // message identifier WPARAM wParam, // first message parameter LPARAM lParam // second message parameter ) { DWORD dwCurThreadID = GetCurrentThre
-
Someone said that PostQuitMessage function does not really send a WM_QUIT message to the message queue of the calling thread. I wonder what does this function exactly do. //Here is a simple test code /*If PostQuitMessage function sends a WM_QUIT message to the message queue of the calling thread, GetMessage(..., hwnd, ..., ...) can't get the WM_QUIT message, the application won't leave the message loop. But in this example: 1.compile the source ; 2.Ctrl+F5 to run it; 3.D&D to move the window; 4.press the corss to close window; 5.found that the application process disappear from the "task manager " It seems that GetMessage(..., hwnd, ..., ...) got the WM_QUIT message. Someone said it's because of that PostQuitMessage is called before DestroyWindow. But I can't get the same result when debugging by F5. Sorry for my poor English......thanks for your attention. */ #include #include LRESULT CALLBACK WinSunProc( HWND hwnd, // handle to window UINT uMsg, // message identifier WPARAM wParam, // first message parameter LPARAM lParam // second message parameter ); int WINAPI WinMain( HINSTANCE hInstance, // handle to current instance HINSTANCE hPrevInstance, // handle to previous instance LPSTR lpCmdLine, // command line int nCmdShow // show state ) { BOOL bRet = FALSE; WNDCLASS wndcls; wndcls.cbClsExtra=0; wndcls.cbWndExtra=0; wndcls.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH); wndcls.hCursor=LoadCursor(NULL,IDC_CROSS); wndcls.hIcon=LoadIcon(NULL,IDI_APPLICATION); wndcls.hInstance=hInstance; wndcls.lpfnWndProc=WinSunProc; wndcls.lpszClassName="Weixin2003"; wndcls.lpszMenuName=NULL; wndcls.style=CS_HREDRAW | CS_VREDRAW; RegisterClass(&wndcls); HWND hwnd; hwnd=CreateWindow("Weixin2003","CreateWindow",WS_OVERLAPPEDWINDOW, 0,0,600,400,NULL,NULL,hInstance,NULL); ShowWindow(hwnd,SW_SHOWNORMAL); UpdateWindow(hwnd); MSG msg; while((bRet = GetMessage(&msg,hwnd,0,0)) != FALSE) { /*if(bRet == -1) { break; }*/ TranslateMessage(&msg); DispatchMessage(&msg); } return 0; } LRESULT CALLBACK WinSunProc( HWND hwnd, // handle to window UINT uMsg, // message identifier WPARAM wParam, // first message parameter LPARAM lParam // second message parameter ) { DWORD dwCurThreadID = GetCurrentThre
-
Steve, thanks a lot for your answer. More questions: 1.Where can I get more information about how the PostQuitMessage virtually sends a message? 2.Why Microsoft made such a difference between PostQuitMessage and PostThreadMessage(..., WM_QUIT, ..., ...)? How can we take advantage of this difference?
-
Steve, thanks a lot for your answer. More questions: 1.Where can I get more information about how the PostQuitMessage virtually sends a message? 2.Why Microsoft made such a difference between PostQuitMessage and PostThreadMessage(..., WM_QUIT, ..., ...)? How can we take advantage of this difference?
There is a queue status flag assigned per queue. When the thread is running it can request (GetQueueStatus) the status of its queue and observe its value (QS_PAINT, QS_QUIT, ...). This request happens when the thread calls GetMessage or PeekMessage APIs. Based in the status returned, this APIs process the appropriete message from the queue and return the control. Now PostQuitMessage doesn't post a WM_QUIT message into the queue but only set QS_QUIT flag on queue status. Then if GetMessage [or PeekMessage] meet QS_QUIT flag, they return WM_QUIT message as if it were in the queue itself. In contrast, PostThreadMessage posts the WM_QUIT message into the queue without settiong the QS_QUIT flag. So the GetMessage [or PeekMessage] gets the WM_QUIT message from the queue really. Why so? Actually there are two reasons. *) Security. It might be possible that the system will fail to reserve memory for another queue entry and thus the WM_QUIT message will not enter the queue. The point is that if the app wants to quit, it should quit surely. *) Low level priority. WM_QUIT should be processed after all the messages from the queue are processed. This is important because it will allow the application finish its job and then [when no posted messages waiting] to exit. The idea is that when GetMessage detects QS_QUIT flag, it returns WM_QUIT [this is virtual message] only when the queue becomes empty and thus ensuring that the WM_QUIT is processed the last.
-- ===== Arman
-
There is a queue status flag assigned per queue. When the thread is running it can request (GetQueueStatus) the status of its queue and observe its value (QS_PAINT, QS_QUIT, ...). This request happens when the thread calls GetMessage or PeekMessage APIs. Based in the status returned, this APIs process the appropriete message from the queue and return the control. Now PostQuitMessage doesn't post a WM_QUIT message into the queue but only set QS_QUIT flag on queue status. Then if GetMessage [or PeekMessage] meet QS_QUIT flag, they return WM_QUIT message as if it were in the queue itself. In contrast, PostThreadMessage posts the WM_QUIT message into the queue without settiong the QS_QUIT flag. So the GetMessage [or PeekMessage] gets the WM_QUIT message from the queue really. Why so? Actually there are two reasons. *) Security. It might be possible that the system will fail to reserve memory for another queue entry and thus the WM_QUIT message will not enter the queue. The point is that if the app wants to quit, it should quit surely. *) Low level priority. WM_QUIT should be processed after all the messages from the queue are processed. This is important because it will allow the application finish its job and then [when no posted messages waiting] to exit. The idea is that when GetMessage detects QS_QUIT flag, it returns WM_QUIT [this is virtual message] only when the queue becomes empty and thus ensuring that the WM_QUIT is processed the last.
-- ===== Arman
Arman Z. Sahakyan wrote:
Low level priority. WM_QUIT should be processed after all the messages from the queue are processed. This is important because it will allow the application finish its job and then [when no posted messages waiting] to exit. The idea is that when GetMessage detects QS_QUIT flag, it returns WM_QUIT [this is virtual message] only when the queue becomes empty and thus ensuring that the WM_QUIT is processed the last.
I have a question to that, this means that you violate event order? When someone posts a quit message, why would you want to move up later messages (in the queue) and process them before the WM_QUIT?
-
Arman Z. Sahakyan wrote:
Low level priority. WM_QUIT should be processed after all the messages from the queue are processed. This is important because it will allow the application finish its job and then [when no posted messages waiting] to exit. The idea is that when GetMessage detects QS_QUIT flag, it returns WM_QUIT [this is virtual message] only when the queue becomes empty and thus ensuring that the WM_QUIT is processed the last.
I have a question to that, this means that you violate event order? When someone posts a quit message, why would you want to move up later messages (in the queue) and process them before the WM_QUIT?
... this means that you violate event order? Actually not me. :) Ok, the rule violates, though partially. From the following code, it is guarranted that the application will exit after it's been processed the user defined message [generally, any posted [not sent] messages].
PostQuitMessage(0);
PostMessage(hwnd, WM_SOME_USER_DEFINED, 0, 0); // this one will be processed firstIt is partial violation because the queue, as it is, bares no vialoation. Why? Simply because the WM_QUIT has not been there. When someone posts a quit message, why would you want to move up later messages (in the queue) and process them before the WM_QUIT? To keep the integrity of the messages posted. It is possible that the application may be in a job whose integrity is defined by multiple posted messages [IOW a group of messages may be doing a single job]. Rephrased, This is a guard against possible harm inside the application logic.
-- ===== Arman
-
... this means that you violate event order? Actually not me. :) Ok, the rule violates, though partially. From the following code, it is guarranted that the application will exit after it's been processed the user defined message [generally, any posted [not sent] messages].
PostQuitMessage(0);
PostMessage(hwnd, WM_SOME_USER_DEFINED, 0, 0); // this one will be processed firstIt is partial violation because the queue, as it is, bares no vialoation. Why? Simply because the WM_QUIT has not been there. When someone posts a quit message, why would you want to move up later messages (in the queue) and process them before the WM_QUIT? To keep the integrity of the messages posted. It is possible that the application may be in a job whose integrity is defined by multiple posted messages [IOW a group of messages may be doing a single job]. Rephrased, This is a guard against possible harm inside the application logic.
-- ===== Arman
-
... this means that you violate event order? Actually not me. :) Ok, the rule violates, though partially. From the following code, it is guarranted that the application will exit after it's been processed the user defined message [generally, any posted [not sent] messages].
PostQuitMessage(0);
PostMessage(hwnd, WM_SOME_USER_DEFINED, 0, 0); // this one will be processed firstIt is partial violation because the queue, as it is, bares no vialoation. Why? Simply because the WM_QUIT has not been there. When someone posts a quit message, why would you want to move up later messages (in the queue) and process them before the WM_QUIT? To keep the integrity of the messages posted. It is possible that the application may be in a job whose integrity is defined by multiple posted messages [IOW a group of messages may be doing a single job]. Rephrased, This is a guard against possible harm inside the application logic.
-- ===== Arman
Thanks for the feedback. Good to learn something new about Window's event handling! :) I can understand that paint and mouse messages have a special handling (low priority generation) as MS has a GUI centric design... however I am surprised that MS hasn't stopped the special cases here. For example asynchronous network events (FD_ACCEPT, FD_READ) are posted to the queue and recurring is enabled by calling the matching network function, but on the other hand recurring timer events have again a special handling... kinda inconsistent. WM_QUIT came really as a surprise for me, I see your point, just not sure if it really is necessary to guard application logic at this late shut-down stage. /Moak (Event violator le Grande)