4

If a system is trying to shut down, an app can block this shutdown by overriding OnQueryEndSession() and returning FALSE. Surely that means WM_ENDSESSION is the only definitive message to respond to regarding shutdown.

On the other hand, the top answer to this question quotes no less than Raymond Chen as saying that responding to WM_ENDSESSION is essentially pointless. So this is confusing.

Is there some kind of "best practice" principles to apply in deciding which of these messages (if any) one should respond to for doing what kinds of application shutdown work?

In particular, if neither message is handled, will a shutdown process cause an application to be closed as if the user had closed the application manually (e.g. click on red X close button)?

Community
  • 1
  • 1
omatai
  • 3,448
  • 5
  • 47
  • 74
  • 3
    That's a misquotation. The [original is here](http://blogs.msdn.com/b/oldnewthing/archive/2008/04/21/8413175.aspx) and it does *not* say that responding to `WM_ENDSESSION` is pointless, it says that it would be pointless for Windows to send `WM_CLOSE` after `WM_ENDSESSION`. (I think perhaps the poster was confusing it with [this similar quote](http://blogs.msdn.com/b/oldnewthing/archive/2012/01/05/10253268.aspx) about handling DLL_PROCESS_DETACH.) – Harry Johnston Jul 13 '15 at 07:56

2 Answers2

12

This article from Microsoft gives a very comprehensive discussion of end-of-session best practice both pre- and post-Vista. The article makes it quite clear that one should assume that if one receives a WM_QUERYENDSESSION then shutdown will occur at some point.

As soon as all applications have responded to the WM_ENDSESSION message, or been forced to terminate within 5 seconds of receiving the WM_ENDSESSION message, Windows may shut down at any time. This may limit what can be done in response to WM_ENDSESSION.

If an application requires more time to clean itself up:

If your application may need more than 5 seconds to complete its shutdown processing in response to WM_ENDSESSION, it should call ShutdownBlockReasonCreate() in its WM_QUERYENDSESSION handler, and promptly respond TRUE to WM_QUERYENDSESSION so as not to block shutdown. It should then perform all shutdown processing in its WM_ENDSESSION handler.

Windows will apparently not send any additional messages to your application to allow it to exit "gracefully" (e.g. WM_CLOSE). Rather, it will simply call TerminateProcess. If you want a graceful close, you have to build it yourself within the above constraints.

Harry Johnston
  • 35,639
  • 6
  • 68
  • 158
omatai
  • 3,448
  • 5
  • 47
  • 74
  • 4
    It is important to note that when you receive `WM_ENDSESSION` you must do all essential shutdown processing *before* returning from the message handler. This is apparently [a common mistake](http://blogs.msdn.com/b/oldnewthing/archive/2013/06/27/10429232.aspx). – Harry Johnston Jul 13 '15 at 08:10
  • @HarryJohnston Correct. It's even worse than what you say, though. When `WM_ENDSESSION(wParam=TRUE)` is sent, it means 1) You have 5 seconds to do cleanup, and returning from the event handler. If you don't, you get FORCIBLY terminated. 2) When you manually return from the event handler, you get FORCIBLY terminated instantly - NO more window message loop processing - **NOT EVEN OBJECT DESTRUCTORS WILL RUN**. So you shouldn't waste time `PostQuitMessage`, because IT WON'T RUN. 3) Do NOT use `DestroyWindow` inside your `WM_ENDSESSION` handler. Windows will INSTANTLY TERMINATE YOUR PROCESS. – Mitch McMabers Aug 02 '19 at 18:33
  • And to clarify point 3 (ran out of space in the other message): `DestroyWindow` will cause Windows to terminate you INSTANTLY on THAT line of code. NOTHING after your `DestroyWindow(hWnd)` call will execute. NOTHING. So NEVER destroy your window manually in `WM_ENDSESSION`. Finally, here's a summary of what to do: If you see a `WM_ENDSESSION(wParam=TRUE)`, do ALL of your cleanup (and MANUALLY delete objects so their destructors are run if vital cleanup is done in them), and do NOT `PostQuitMessage/DestroyWindow` AT ALL. Then just return from your event handler and BOOM your process is DEAD. – Mitch McMabers Aug 02 '19 at 18:35
  • Basically: Windows treats `WM_ENDSESSION` as your application's "exit point" during shutdown/restart/logoff. It does NOT run your message queue after that. It does NOT run object destructors. It does NOT let your `main()`-function run/exit cleanly. It just INSTANTLY terminates you and "tears down the building" (as Raymond Chen describes it). -- And the funniest thing is, if an application does not implement this function, then you're screwed. Your app just instantly terminates with ZERO cleanup. So yes, EVERY Windows program must MANUALLY implement `WM_QUERYENDSESSION` and `WM_ENDSESSION`. – Mitch McMabers Aug 02 '19 at 18:37
2

You do need to close down your application in WM_ENDSESSION, at least if you want to support the Restart Manager API. I think both MSDN and Raymond are wrong here. (Maybe it changed recently, or they overlooked the Restart Manager?)

The Restart Manager API is used by installers to close and restart exes which have files locked that they need to replace. To support being restarted by it, you call RegisterApplicationRestart and then need to have a window which handles WM_QUERYENDSESSION and WM_ENDSESSION.

If you don't shut down your app in the WM_ENDSESSION handler than it will simply keep running and block the Restart Manager, and in turn the installers trying to use it.

I found this out the hard way. MSDN explicitly says you don't need to call PostQuitMessage, but if I don't do that then my process keep running.

I suspect the documentation didn't realise the Restart Manager is different, and less forceful, compared to what happens when the entire OS shuts down.

(Edit: I should add, this was with a simple ATL COM EXE server, but as far as I can tell there was nothing about that complicating things, and Windows simply wasn't triggering a WM_QUIT to the message loop unless I did it myself.)

Leo Davidson
  • 6,093
  • 1
  • 27
  • 29