We have a Win32 application written using WTL (Windows Template Library), and I'm looking for patterns for exiting the application. The issue that I'm dealing with is that some of the views in the application contain resources which may take some time (measured in 1 to 2 seconds), to destroy (i.e. waiting for a thread to exit, etc)
Win32 seems to support two main lifecycle messages, WM_CLOSE and WM_DESTROY. WM_CLOSE seems to be the message you want to send windows to notify them that there is a request to close the application, and gives you the opportunity to decide on whether or not to continue to close. WM_DESTROY, is when take down is occurring and should just be cleaning up.
The question is, how would you handle a case where you want to keep the message loop running, while shutting down the application.
Example: Main window receives WM_CLOSE because user clicks on close. Let's say you don't need to prompt the user for exiting, but you then notify all of your views that a close is occuring. Let's also say that at this point, you don't want to exit the application because you need to clean up some resources, which may take a second or two, and you want the interaction to be asynchronous.
How would you notify the main window when all of the child views have completed their shutdown processes? To be more specific, is there any standard message for notifying parents that you are done cleaning up?
CodePudding user response:
Your assumptions about WM_CLOSE
and WM_DESTROY
are incorrect.
WM_CLOSE
is a request to close a window. It happens when the user clicks the 'X', or presses Alt F4 for example. The default handler for WM_CLOSE
initiates the destruction of the window that received the close request.
WM_DESTROY
is part of the message cascade happening when a window is actually destroyed (DestroyWindow
function). It is not the last message to be received during window destruction, that would be WM_NCDESTROY
.
Destroying the application's main window neither terminates the message loop, nor does it terminate the application.
The application terminates when all non-background threads terminate. So it requires the UI thread to terminate. Which requires its message loop to terminate.
The message loop terminates when it decides to break out of its while loop. The trick here is that GetMessage
returns false
upon receiving WM_QUIT
. WM_QUIT
is a result of calling PostQuitMessage
, which, in a well-behaved application, happens in the WM_DESTROY
handler of the application's main window. This call to PostQuitMessage
is the application programmer's responsibility, and you can do whatever you want here.
In fact, you can also simply place your cleanup work after the message loop, before the main thread terminates.
CodePudding user response:
The question is, how would you handle a case where you want to keep the message loop running, while shutting down the application.
I would have the WM_CLOSE
handler display a "Please wait" message to the user, and then asynchronously initiate whatever shutdown logic is needed. Do not call DefWindowProc()
or DestroyWindow()
yet.
Let the message loop run normally while the shutdown logic is doing its thing in the background.
When all shutdown tasks are finished, dismiss the "Please wait" message, and destroy the application window, signalling the message loop to exit, as explained by the other answers.
CodePudding user response:
All these are conventions, they have nothing to do with actual application shutdown.
WM_CLOSE
is sent to the window when the user clicks X (or Alt F4). You can ignore it, or (usually) you call DestroyWindow
, then the window receives WM_DESTROY
in which you can call PostQuitMessage to break the message loop.
Nobody forces you to actually break the message loop. There is no actual shutting down involved.What you will do after that is entirely up to the code. The application is not terminated until WinMain
returns (or ExitProcess()
called), not when the message loop is broken. You can start another message loop right away.
It's just that usually, most applications have one main window and, therefore, closing it is taken as the closing of the application.
CodePudding user response:
WM_CLOSE
is Windows telling the application code that the user wants to close a window. The default behavior, what you get if DefWindowProc
fields the message, is for WM_CLOSE
to cause the window to be destroyed. Destroying the window will lead to WM_DESTROY
being posted to the window. A typical pattern is to post WM_QUIT
from the WM_DESTROY
handler if the window in question is the application's main window.
A key thing to understand is that none of this has to happen this way. You can not destroy the window from WM_CLOSE
and you can not PostQuitMessage
from WM_DESTROY
. This is all up to you.
Example: Main window receives WM_CLOSE because user clicks on close. Let's say you don't need to prompt the user for exiting, but you then notify all of your views that a close is occuring. Let's also say that at this point, you don't want to exit the application because you need to clean up some resources
So if you don't want to exit the application maybe allow the window to be destroyed from WM_CLOSE
but don't post the quit message from that window's WM_DESTROY
handler. Post whatever custom messages (say) you need to cleanup resources from WM_CLOSE
and only when that all completes call PostQuitMessage
. Or something similar to this. There is not one right way; however, just note that it is the user who is initiating WM_CLOSE so when that happens your application better appear to close that window immediately or it will feel off.