0

What is the proper way to 'quit' an application after final clean-up tasks have been done, in response to the WM_ENDSESSION message?

Once my application, a service-like executable responding to external input, receives this message and wParam == TRUE it writes the end of the log and flushes it. After this point, I actually want my application to stop, completely. I don't want any further code to run, because clean-up will be done by Windows and any servicing done by my application after this message is likely to be rudely interrupted by process termination.

I want my application to do only the absolutely necessary amount of work and after that stop so as to not slow down Windows shutdown. Some possibilities I can think of are:

  • One option I can think of is to call ExitProcess. However, this seems to do a lot of work and maybe too much?
  • Another option is to set a flag after receiving WM_ENDSESSION and have strategically placed checks for this flag in my code so that the program does nothing. The obvious disadvantage is that this complicates the code unnecessarily.

There might be other options and I want to know: which is the proper way?


Interesting reads

The following are some interesting reads on the subject, but none of these answers this question.

Community
  • 1
  • 1
MicroVirus
  • 5,324
  • 2
  • 28
  • 53
  • You've been ignoring the WM_QUERYENDSESSION notification when it gets that far. Best thing to do then is to hang your program, Sleep(INFINITE). That will annoy the bejesus out of your user, he'll be sure to file a bug report. If you don't like getting bug reports then use `_exit(1);` – Hans Passant Oct 16 '15 at 16:04
  • 2
    @HansPassant: Except, you cannot perform your shutdown in a `WM_QUERYENDSESSION` handler, since there is no guarantee that a `WM_ENDSESSION` will follow. You can, however, flush any buffers, that need to be written out to disk, to reduce the processing time in your `WM_ENDSESSION` handler to its minimum. – IInspectable Oct 16 '15 at 16:50
  • No, that's been over and done with for the past 10 years. Good riddance. – Hans Passant Oct 16 '15 at 17:00
  • 3
    @IInspectable: If you return TRUE from `WM_QUERYENDSESSION`, you are guaranteed to receive `WM_ENDSESSION`. What is NOT guaranteed is that the session will actually end if you receive `WM_ENDSESSION`. This is stated in the documentation: "*When an application returns TRUE for this message, it receives the WM_ENDSESSION message, **regardless of how the other applications respond to the WM_QUERYENDSESSION message**. Each application should return TRUE or FALSE immediately upon receiving this message, and defer any cleanup operations until it receives the WM_ENDSESSION message.*" – Remy Lebeau Oct 16 '15 at 17:55
  • @IInspectable: So, your app can receive `WM_ENDSESSION` and clean itself up even if another app returns FALSE to `WM_QUERYENDSESSION` to prevent shutdown. However, `WM_ENDSESSION` does indicate whether the session is actually ending or not. – Remy Lebeau Oct 16 '15 at 17:56
  • @HarryJohnston: no, I meant what I said. Read the [`WM_ENDSESSION` documentation](https://msdn.microsoft.com/en-us/library/windows/desktop/aa376889.aspx): "*wParam - **If the session is being ended, this parameter is TRUE**; the session can end any time after all applications have returned from processing this message. **Otherwise, it is FALSE**.*" And [this documentation](https://msdn.microsoft.com/en-us/library/ms700677.aspx) says if you receive `WM_QUERYENDSESSION`, whether you return TRUE or FALSE, you can receive `WM_ENDSESSION` with `wParam` set to FALSE. – Remy Lebeau Oct 16 '15 at 20:33
  • @RemyLebeau: I misunderstood you; thanks for clarifying. But doesn't that mean that IInspectable is right to say that you should wait for `WM_ENDSESSION` rather than shutting down when you receive `WM_QUERYENDSESSION` ? If `wParam` is `FALSE` you presumably don't need to shut down after all. – Harry Johnston Oct 16 '15 at 20:46
  • @HansPassant I've not been ignoring `WM_QUERYENDSESSION`; @RemyLebeau explains it quite nicely: I only know that I have to exit at the point where I receive the `WM_ENDSESSION`. My question is then, what is the best way to stop my program after I'm ready (as in: my user code has done all minimally necessary clean-up). – MicroVirus Oct 17 '15 at 11:32
  • No, you should shutdown your program with you get QES. As I said, the days that programs could still block a shutdown with QES are long gone. WES will quickly follow. Just look at how class libraries do this. Like [Winforms](http://referencesource.microsoft.com/#System.Windows.Forms/winforms/Managed/System/WinForms/Form.cs,dea6fdef3f8a07b3), QES generates CloseReason.WindowsShutDown, the app is expected to terminate. Use the (limited) time you get for QES to save state. And quit, absolutely no point in waiting. – Hans Passant Oct 17 '15 at 12:09
  • @HansPassant From the Winforms example one can see from [`WmClose`](http://referencesource.microsoft.com/#System.Windows.Forms/winforms/Managed/System/WinForms/Form.cs,6892) that on a close request, such as WES, events like `OnClosing` and `OnFormClosing` are raised, but these are cancellable by the user. Furthermore, it does not continue to pass 2 on WES, so nothing actually closes. Only when in pass 2 `WM_ENDSESSION` is received with `wParam == TRUE` does any closing actually happen. – MicroVirus Oct 17 '15 at 12:25
  • 1
    Furthermore, from MSDN's doc's on WES: "When an application returns TRUE for this message, it receives the WM_ENDSESSION message, regardless of how the other applications respond to the WM_QUERYENDSESSION message. Each application should return TRUE or FALSE immediately upon receiving this message, and defer any cleanup operations until it receives the WM_ENDSESSION message.". This seems to be opposite to what you are saying. Also the [Guidelines for Applications](https://msdn.microsoft.com/en-us/library/windows/desktop/aa373651(v=vs.85).aspx) on the subject seems to tell us to wait. – MicroVirus Oct 17 '15 at 12:26

2 Answers2

2

Update:

_exit() will quickly terminate the process without the unnecessary work. (Don't confuse this with exit().)

Interestingly, the implementation of _exit() ends with a call to ExitProcess, so the DLL_PROCESS_DETACH notifications are still sent, but the runtime DLL won't run static destructors in this case because _exit() sets a flag first.

Original Answer:

ExitProcess is appropriate. It may sound like a lot of work, but much of that is going to happen anyway, even if your process crashes.

The only significant, unnecessary work might be the DLL_PROCESS_DETACH notifications to the DLLs. The best thing you can do about that is to make sure your DLLs don't do much work when they receive those notifications.

Another option would be to call abort or _exit, but I suspect these are roughly equivalent to ExitProcess.

Adrian McCarthy
  • 45,555
  • 16
  • 123
  • 175
  • I think the main potential problem is the C++ destructors, which I believe the runtime library runs when it receives DLL_PROCESS_DETACH? – Harry Johnston Oct 16 '15 at 20:21
  • @Harry Johnston: I believe the compiler arranges to run destructors for globals when the original thread "returns" from main (it doesn't matter if you've linked against the static or dynamic versions of the runtime libraries). I'm fairly certain ExitProcess avoids that, since the code will not "return" from main. The language runtime libraries probably don't do anything on a DLL_PROCESS_DETACH, except maybe in the debug versions. – Adrian McCarthy Oct 16 '15 at 20:32
  • I've looked through the Microsoft Visual C++ 2010 CRT code for `_exit` and it ends up calling `ExitProcess`. Do you happen to know if Windows will call `ExitProcess` or the equivalent on the process when the session ends, or is that another call? I am mostly curious about whether things like `DLL_PROCESS_DETACH` are also called by Windows on session end. In other words: are calling `ExitProcess` yourself and waiting for Windows to terminate your application at session ending equivalent? – MicroVirus Oct 17 '15 at 11:48
  • @MicroVirus: no, if the process is terminated (for example, because it failed to exit when it received `WM_ENDSESSION`) the DLL detach calls are not made. – Harry Johnston Oct 19 '15 at 03:57
  • I've just tested this (Visual Studio 2010) and destructors for globals *are* run when ExitProcess is called, provided you are dynamically linked to the runtime library. (If you are statically linked to the runtime library, then destructors for globals in the application are not called. Destructors for globals in DLLs are called either way.) – Harry Johnston Oct 23 '15 at 02:20
  • @Harry Johnston: Interesting. I would not have expected that. I'll edit the answer. – Adrian McCarthy Oct 23 '15 at 12:45
1

I agree with Adrian that ExitProcess() is usually the most appropriate choice.

However, if you absolutely must (for example) prevent the C++ destructors from running, you can always resort to the nuclear option:

TerminateProcess(GetCurrentProcess());
Harry Johnston
  • 35,639
  • 6
  • 68
  • 158
  • See also Adrian's note about _exit(); that's probably a better choice if your only concern is the C++ destructors. (It presumably won't affect destructors belonging to a DLL linked with the static runtime or with a different dynamic runtime, but that's an edge case.) – Harry Johnston Oct 23 '15 at 21:11