I am trying to prevent my application from being shutdown by windows. The application is running on windows 8 and written in XE6. I tried following code but it seems to be completely ignored. To test it I simply send "end task" to it through the task manager. What I need is a way to let my application finish what its doing when the application is closed by the user, by the task manager of by a windows shutdown. Normal closing is not a problem, this is handled by the FormCloseQuery event. But the other 2 methods I can't get to work. Until windows XP this was easy by catching the wm_endsession and the wm_queryendsession, starting from vista you need the use ShutDownBlockReasonCreate, which returns true but does not seems to work anyway.
procedure WMQueryEndSession(var Msg : TWMQueryEndSession); message WM_QUERYENDSESSION;
procedure WMEndSession(var Msg: TWMEndSession); message WM_ENDSESSION;
function ShutdownBlockReasonCreate(hWnd: HWND; Reason: LPCWSTR): Bool; stdcall; external user32;
function ShutdownBlockReasonDestroy(hWnd: HWND): Bool; stdcall; external user32;
procedure TForm1.WMEndSession(var Msg: TWMEndSession);
begin
inherited;
Msg.Result := lresult(False);
ShutdownBlockReasonCreate(Handle, 'please wait while muting...');
Sleep(45000); // do your work here
ShutdownBlockReasonDestroy(Handle);
end;
procedure TForm1.WMQueryEndSession(var Msg: TWMQueryEndSession);
begin
inherited;
Msg.Result := lresult(False);
ShutdownBlockReasonCreate(Handle, 'please wait while muting...');
Sleep(45000); // do your work here
ShutdownBlockReasonDestroy(Handle);
end;
Update
Changing the message result to true and removing the sleep changes nothing.
procedure TForm1.WMEndSession(var Msg: TWMEndSession);
begin
inherited;
Msg.Result := lresult(True);
ShutdownBlockReasonDestroy(Application.MainForm.Handle);
ShutdownBlockReasonCreate(Application.MainForm.Handle, 'please wait while muting...');
end;
procedure TForm1.WMQueryEndSession(var Msg: TWMQueryEndSession);
begin
inherited;
Msg.Result := lresult(True);
ShutdownBlockReasonDestroy(Application.MainForm.Handle);
ShutdownBlockReasonCreate(Application.MainForm.Handle, 'please wait while muting...');
end;
If possible it's better to save data in other place and next time you app is running again ask the user if he want to keep this data. Or even better, if you can, restore the app state exactly how it was at shutdown and you don't need to ask anything.
"Applications should respect the user's intentions and return TRUE " If possible it's better to save data in other place and next time you app is running again ask the user if he want to keep this data. Or even better, if you can, restore the app state exactly how it was at shutdown and you don't need to ask anything.
What you need to be able to do is block shutdown until you have finished saving any data. The way that is handled changed in Vista. The documentation you need starts here:
According to the documentation to block shutdown you need to return FALSE
in response to WM_QUERYENDSESSION
.
What's more, you must not do work in this message handler. The work must happen elsewhere. If you don't respond to this message in a timely fashion the system won't wait for you.
ShutdownBlockReasonCreate
before you start working. FALSE
from WM_QUERYENDSESSION
. Don't work whilst handling this message. Return immediately. ShutdownBlockReasonDestroy
. The handler for WM_QUERYENDSESSION
can look like this:
procedure TMainForm.WMQueryEndSession(var Msg: TWMQueryEndSession);
begin
if Working then
Msg.Result := 0
else
inherited;
end;
And then the code that performs the work needs to call ShutdownBlockReasonCreate
before the work starts, ShutdownBlockReasonDestroy
when the work ends, and make sure that the Working
property used above evaluates to True
during work.
If your work blocks the main thread then you are in trouble. The main thread must be responsive, otherwise the system won't wait for you. Putting the work in a thread is often the way forward. If your main window is not visible then you don't get a chance to block shutdown. The details are explained here: http://msdn.microsoft.com/en-us/library/ms700677.aspx
If you get as far as being sent WM_ENDSESSION
then it's too late. The system is going down come what may.
To test it I simply send "end task" to it through the task manager.
That has nothing to do with shutdown blocking. The way you test shutdown blocking is to logoff. If the user insists on killing your process there is little that you can do about it. Sertac's answer covers this in detail.
Finally, ignoring the return values of API calls is also very poor form. Don't do that.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With