Since Windows Vista, if you register a shutdown reason string with the OS or if your application has a top level window, the OS will wait indefinitely for your program to return from WM_QUERYENDSESSION
while displaying the blocking applications screen - or until the user chooses to forcefully end the program of course.
The below sample code simulates a 45 seconds wait with Sleep
. In the first five seconds of the wait the OS waits patiently, only then it displays the full screen UI. The only way to show the screen immediately is to immediately return false from WM_QUERYENDSESSION
. But in this case you won't be able to resume shutdown.
For details on shutdown behavior of the OS for Vista and later, see documentation.
type
TForm1 = class(TForm)
..
protected
procedure WMQueryEndSession(var Message: TWMQueryEndSession);
message WM_QUERYENDSESSION;
..
...
function ShutdownBlockReasonCreate(hWnd: HWND; Reason: LPCWSTR): Bool;
stdcall; external user32;
function ShutdownBlockReasonDestroy(hWnd: HWND): Bool; stdcall; external user32;
procedure TForm1.WMQueryEndSession(var Message: TWMQueryEndSession);
const
ENDSESSION_CRITICAL = $40000000;
begin
Message.Result := LRESULT(True);
if ((Message.Unused and ENDSESSION_CRITICAL) = 0) then begin
ShutdownBlockReasonCreate(Handle, 'please wait while muting...');
Sleep(45000); // do your work here
ShutdownBlockReasonDestroy(Handle);
end;
end;
WM_QUERYENDSESSION
or some similar message and do the muting process there. – Mme