WM_QUERYENDSESSION is the correct message to handle. This is sent before WM_ENDSESSION
and as per the following VCL code, you can see that WMQueryEndSession immediately calls CloseQuery
.
procedure TCustomForm.WMQueryEndSession(var Message: TWMQueryEndSession);
begin
Message.Result := Integer(CloseQuery);
end;
One could consider the above implementation to be a small bug in the VCL code, because as the WM_QUERYENDSESSION
documentation states (emphasis mine):
Each application should return TRUE or FALSE immediately upon receiving this message, and defer any cleanup operations until it receives the WM_ENDSESSION message.
Applications can display a user interface prompting the user for information at shutdown, however it is not recommended. After five seconds, the system displays information about the applications that are preventing shutdown and allows the user to terminate them. For example, Windows XP displays a dialog box, while Windows Vista displays a full screen with additional information about the applications blocking shutdown. If your application must block or postpone system shutdown, use the ShutdownBlockReasonCreate
function. For more information, see Shutdown Changes for Windows Vista.
If the user fails to respond to a dialog that happens to pop-up within 5 seconds, they would have to terminate the app or cancel shutdown. Unfortunately, since CloseQuery
is typically used to prompt the user so it's not a good idea to do so.
NOTE: This was perfectly acceptable pre-Vista, and the above code is probably more of a legacy issue. However, it would be good if CloseQuery
were at least adjusted to indicate the source of the close request, making it easy to deal with the specific case of Query End Session.
So given that I do not want any prompts popping up in reponse to WM_QUERYENDSESSION, I actually do the following:
procedure TxxxForm.WMQueryEndSession(var Message: TWMQueryEndSession);
begin
Message.Result := 1;
{ Do not call inherited bc VCL may prevent/delay shutdown via
calls to: CloseQuery and CallTerminateProcs (in older
versions of Delphi).
As per Vista requirements, this should not be done. Use
ShutdownBlockReasonCreate and ShutdownBlockReasonDestroy to
control when shutdown is allowed. }
end;
Moving on to the second part of your question.
The reason the above doesn't work for End Task via Task Manager is that Task Manager doesn't use the same mechanism as shutdown. It simply sends a WM_CLOSE
message to your application.
So it's perfectly acceptable for your application to behave in exactly the same way as it would when closed "normally". In fact, you can give this a try with Notepad:
- Open Notepad
- Type some text
- Go to Task Manager and click End Task for Notepad.
- You'll observe that Notepad will prompt for confirmation, and Task Manager will show a dialog that Notepad is waiting for a response from the user. (At least in Win7.)
However, if you do want/need to prevent the prompt when closing from Task Manager, you can do so. But the code will have to deal a number of special cases, and may not behave in exactly the same way on all versions of Windows. (So you'll have to ask yourself if it's really worth the effort.)
You have to cater for at least 3 situations:
- Close from a custom menu or button within your application.
- Close from standard Windows commands: X on top right, Sys Menu or double-click top left corner, Alt+F4 key combination.
- And finally closing from Task Manager.
Getting all 3 to behave the way you want gets a little tricky.
- Option 3 sends a
WM_CLOSE
. So you'd have to let "default" behaviour close without prompt. And use a Flag
to enable prompting. In this way option 3 can close "silently".
- Option 2 first sends
WM_SYSCOMMAND
with SC_CLOSE
followed by WM_CLOSE
. So you can set your Flag
in response to the first message. Therefore your user will get a prompt.
- Option 1 will most likely be implemented by calling
Close
. But to ensure you get a prompt, you'll have to set your Flag
first.
- Don't forget to clear your
Flag
if your user chooses not to close the application.
A Final Thought
I personally find "close confirmation" quite annoying. Of course, I am in the habit of saving often, so don't risk losing data.
Basically, the only justifiable reason to prompt on close is to prevent accidental data loss of unsaved data. And you can create a more pleasant user experience if you follow this rule:
When an app opens, always restore it to exactly the same state it was in when it closed.
I.e. if there was unsaved data for a document, store it in temporary files. When the app reopens, the document is automatically placed in the same "edit" state it was in at shutdown.
(Yes. Perhaps this is an oversimplification, but the idea works quite nicely on mobile devices.)