Recently I had a very hard to find bug-problem with closing my application (made in Delphi).
It just refused to respond to Windows shutdown messages and prevented Windows to shutdown and restart..
I spent a lot of hours investigating this problem.
Initially the first part of the problem, because I was showing a dialog for "Really close?" and preventing closing if some files are not saved, this was done in FormCloseQuery and it was stupid approach, because FormCloseQuery doesn’t know if windows is shutting down and thus preventing shutdown.
Then, I made a Message listeners for windows asking applications query for shutdown : WM_QueryEndSession and WM_EndSession:
// Shutdown messages
procedure WMEndSession(var Msg: TWMEndSession); message WM_ENDSESSION;
// Query to Shutdown
procedure WMQueryEndSession(var Msg: TMessage); message WM_QUERYENDSESSION;
The problem remained: the messages were received only second time. The first time when Windows was shutting down the application was still preventing shutdown, and only for the second Shutdown call, the messages were received and Application quit.
So something else was corrupting even the messages queue.
After some time, I accidentally came under another Form in same application, which also had FormCloseQuery, this time it was really needed because this Form was closing with fading effect and Query was preventing close until fader finished. So that was the second part of the problem.
Again I needed to listen for Shutdown messages in this Form.
So to conclude: you need to listen for Windows shut down Messages and Queries in every form that has FormCloseQuery or better yet avoid it, if you want to let windows shutdown normally.
Also to note: Delphi made applications (on Windows shutdown) exit instantly without freeing objects, so be careful and it is a good practice to listen to Shutdown procedure and to call your own Closing and Freeing procedure manually:
//Windows' Query for Shutdown
procedure TMainForm.WMQueryEndSession(var Msg: TMessage);
begin
//Windows is about to shut down - Alow or not
bForceClose := True;
Msg.Result := 1; // 1 for Signal that it is OK to shut down
inherited; // let the inherited message handler respond
end;
//Windows is shutting down
procedure TMainForm.WMEndSession(var Msg: TWMEndSession);
begin
// shutdowning
if Msg.EndSession = True then
begin
//Windows is shutting down -- Closing'
bForceClose := True;
//Be CAREFULLL - MIGTH BE DOUBLE OR NO FREEING AT ALL
CleanUp; // My Closing procedure
FinalDestroy; // Destructor sometimes never called on shutdown !!!!!!
inherited; // let the inherited message handler respond
end
else
inherited;
// Msg.Result:=0; //Signal that we got the message - not needed
end;
bForceClose here is a global boolean variable, signaling that we should force our application closing, and if you still need FormCloseQuery check for bForceClose there (of course you need to set it false on application start):
procedure TMainForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
CanClose := True;
if not bForceClose then begin
//no close
CanClose := False;
//Do what you need here;
end
else CanClose := TRUE; //Forced close
end;
And you need this done in every form with FormCloseQuery.
February 24th, 2010 at 11:50 am
Have you checked here? Detecting and preventing Windows shut down http://delphi.about.com/cs/adptips2000/a/bltip0500_4.htm
my favorite delphi database components http://www.components4developers.com
February 25th, 2010 at 9:25 am
Yes, but is’s more related to detecting Shutdown sequence, and it is not a good way to prevent shutdown of your application.
Of course Zarko’s tips is always great.