Tag Archives: FormCloseQuery WM_QueryEndSession

Be careful with FormCloseQuery

help 64 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);


  //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



//Windows is shutting down

procedure TMainForm.WMEndSession(var Msg: TWMEndSession);


  // shutdowning

  if Msg.EndSession = True then


    //Windows is shutting down -- Closing'

    bForceClose := True;


    CleanUp;   // My Closing procedure

    FinalDestroy; // Destructor sometimes never called on shutdown !!!!!!


    inherited; // let the inherited message handler respond




    // Msg.Result:=0;  //Signal that we got the message - not needed


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);


  CanClose := True;

  if not bForceClose then begin

        //no close 

        CanClose := False;

        //Do what you need here;


  else CanClose := TRUE; //Forced close


And you need this done in every form with FormCloseQuery.