A comment above suggested I summarize the answer I found (link). Basically, it says to provide your own handler for WM_QUERYENDSESSION. This is the recommended code:
procedure TForm1.WMQueryEndSession(var Message: TWMQueryEndSession);
begin
inherited; { let the inherited message handler respond first }
{--------------------------------------------------------------------}
{ at this point, you can either prevent windows from closing... }
{ Message.Result:=0; }
{---------------------------or---------------------------------------}
{ just call the same cleanup procedure that you call in FormClose... }
MyCleanUpProcedure;
{--------------------------------------------------------------------}
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
MyCleanUpProcedure;
end;
I am not sure that calling Inherited before calling MyCleanUpProcedure is completely correct. If the Inherited procedure responds back to Windows first, Windows could still shut down the application before MyCleanUpProcedure had completed. I am not sure what Inherited does for the WM_QUERYENDSESSION
message - I assume it defaults to allowing the shutdown immediately. In my application, the MyCleanUpProcedure runs very fast, so it would not cause Windows to display the "Not Responding" dialog due to no response to the WM_QUERYENDSESSION
message.
To be sure my procedure runs to completion, maybe the procedure should look like this:
procedure TForm1.WMQueryEndSession(var Message: TWMQueryEndSession);
begin
MyCleanUpProcedure;
inherited;
end;
Or possibly this?
procedure TForm1.WMQueryEndSession(var Message: TWMQueryEndSession);
begin
MyCleanUpProcedure;
Message.Result:=1; // tell Windows it is OK to shut down
end;