This site is temporarily down. Please come back. Delphi doesn't process WM_ENDSESSION
DelphiFAQ Home Search:

Delphi doesn't process WM_ENDSESSION

 

comments3 comments. Current rating: 4 stars (2 votes). Leave comments and/ or rate it.

This really is a bug or at least a very lazy 'feature':

When you have a delphi application running, and you are shutting down
windows, (don't close your app first), NONE of your destructors are
called!!!!

The problem seems to be that when you close down Windows, it will first
send a WM_QueryEndSession message to all running top-level windows. This
is handled and processed correctly by the TForm object in VCL.

Then assuming that all applications indicated that it was ok to close down,
Windows will send WM_EndSession messages to all windows. This message is
not handled by VCL. The application is simply brought down with a bang.
No windows are closed, no destructor called and no exit procedures called.

The solution is to handle the WM_EndSession message yourself. There are
several ways of handling messages in Delphi, but the only reliable way
of handling the WM_ENDSESSION is to use the HookWindow method of
Application.

In the message handler, check to see if the message is a WM_ENDSESSION.
If so, we should close down the application. We could have called the
Close method of the main window, but the Windows API documentation states
that the system might go down anytime after return from the WM_ENDSESSION,
and a posted WM_QUIT message might never arrive to the application.

The solution is to simply call Halt instead. This will call all registred
exit procedures, including the ones in Controls and DB units. These will
free the application and screen objects and take the BDE down correctly.

A simple example follows - compile it and watch the flag file being
deleted. Try it also out without the hook in .FormCreate.

// FROM: hallvard@falcon.no (Hallvard Vassbotn)
unit Tst2u;

Interface

uses
  SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics,
    Controls, Forms, Dialogs, Grids, DBGrids, Db, dbtables;

type
  TForm1 = class (TForm)
    DataSource1 : TDataSource;
    Table1      : TTable;
    DBGrid1     : TDBGrid;
    procedure FormCreate (Sender: TObject);
  private
    { private declarations }
    function HookProc (var message: TMessage) : Boolean;
  public
    { public declarations }
  end;

var
  Form1 : TForm1;

implementation

{$R *.DFM}
const
  FlagFileName = 'C:\Flag.Fil';

procedure CreateFlagFile;
var
  f : System.Text;
begin
  System.Assign (f, FlagFileName);
  System.Rewrite (f);
  WriteLn (f, 'This is a dummy flag file');
  System.Close (f)
end;


procedure KillFlagFile;
var
  f : File;
begin 
  System.Assign (f, FlagFileName); 
  System.Erase (f)
end; 


procedure MyExitProc; 
  far; 
begin 
  KillFlagFile
end; 


procedure TForm1.FormCreate (Sender: TObject); 
begin 
  Application.HookMainWindow (HookProc)
end; 


function TForm1.HookProc (var message: TMessage) : Boolean; 
begin 
  result := False; 
  if message.Msg = WM_ENDSESSION then 
  begin 
    if WordBool (message.WPARAM) then 
    begin 
      { Windows is closing down - clean up!! } 
      
      { This should execute all ExitProcs, close windows and call destructors.. }
      Halt
     
      { This should close things down properly,                                 }
      { but do we have enough time to handle any posted messages before Windows }
      { is already down??  This will result in a PostQuitMessage that might     }
      { never arrive!                                                           } 

      { This doesn't always work - avoid it } 
      {      Close;}      
    end
  end
end; 


initialization 
  CreateFlagFile; 
  AddExitProc (MyExitProc)

end.

Content-type: text/html

Comments:

2006-09-24, 23:59:44
anonymous from Australia  
Is this really a big problem? Sure, if the destructors aren't called then the memory won't be restored, but Windows is shutting down anyway so that doesn't matter.
2007-07-26, 06:37:44   (updated: 2007-07-26, 06:40:12)
anonymous from Istanbul, Turkey  
rating
Yeah it is really problem.
1. It is very common way to close files in destructors.
2. It is very common way to close database connections in destructors (In most time, by delphi VCL).

I noticed this situation when I saw missing records in database tables and unterminated log files.

Ömür Ölmez
www.ideayazilim.com
This image was also posted here:
Delphi doesn't process WM_ENDSESSION



Keywords:
2007-07-30, 00:43:19
anonymous from Turkey  
rating
Actually there is somethins strange. If we take a look at Forms.pas at Delphi 6 VCL, we see below :

procedure TCustomForm.WMQueryEndSession(var Message: TWMQueryEndSession);
begin
Message.Result := Integer(CloseQuery and CallTerminateProcs);
end;

What the code does is:
If CloseQuery returns true, it calls CallTerminateProcs and it returns true too, answers Windows that it is ok to shutdown/logoff.

Calling CallTerminateProcs is the same thing in both Application.Terminate() and Halt().

So, it seems, TCustomForm.WMQueryEndSession is never called. There may something wrong between main message loop and this message handler.

This image was also posted here:
Delphi doesn't process WM_ENDSESSION



Keywords:

 

 

NEW: Optional: Register   Login
Email address (not necessary):

Rate as
Hide my email when showing my comment.
Please notify me once a day about new comments on this topic.
Please provide a valid email address if you select this option, or post under a registered account.
 

Show city and country
Show country only
Hide my location
You can mark text as 'quoted' by putting [quote] .. [/quote] around it.
Please type in the code:

Please do not post inappropriate pictures. Inappropriate pictures include pictures of minors and nudity.
The owner of this web site reserves the right to delete such material.

photo Add a picture: