Mega Code Archive

 
Categories / Delphi / Examples
 

Delphi doesnt process wm_endsession

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.