We help IT Professionals succeed at work.

Where's my program gone???!

narrowgate
narrowgate asked
on
Hello,
I've written a program that I want to run all the time a user is logged in. The problem comes when they log off with unsaved stuff. At this point the program (excel say) asks if they want to save the changes / lose the changes or cancel the logoff. If the user presses cancel then Windows does not close down (expected) but my program does shut down (not expected). How can I prevent this????

I'm using 2000.
Comment
Watch Question

Mohammed NasmanSoftware Developer
CERTIFIED EXPERT

Commented:
hello

  try to catch the WMQueryEndSession message
//==
unit Unit1;

interface

uses
 Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;

type
 TForm1 = class(TForm)
 private
   { Private declarations }
   procedure WMQueryEndSession(var Msg : TWMQueryEndSession); message WM_QueryEndSession;
 public
   { Public declarations }
 end;

var
 Form1: TForm1;

implementation

{$R *.DFM}
procedure TForm1.WMQueryEndSession(var Msg : TWMQueryEndSession);
begin
 if MessageDlg('Close Windows ?', mtConfirmation, [mbYes,mbNo], 0) = mrNo then
   Msg.Result := 0
 else
   Msg.Result := 1;
end;


Best regards
Mohamme nasman
Commented:
WM_QueryEndSession is sent when windows asks if it may shut down or not.  You can return 0 or 1.

However, after saying that your application CAN shut down another application may say that it cannot.  Therefore you should look for the WM_ENDSESSION message before closing your app, it works like this

1) User selects SHUT DOWN
2) WM_QUERYENDSESSION is sent
3) If the result of WM_QUERYENDSESSION from each app = 1 then ..
4) Send a WM_ENDSESSION message
5) Shut down.

I would use Application.HookMainWindow in order to hook these messages.

See this article.
http://www.howtodothings.com/showarticle.asp?article=281

Pete
====
http://www.HowToDoThings.com (Delphi articles)
http://www.Stuckindoors.com/delphi (Open source)

Author

Commented:
Hello,
To recap then.If you are closing down windoze sends a WM_QUERYENDSESSION. When all the apps say that they are happy to close down windows then sends a WM_ENDSESSION.

I have hooked WM_ENDSESSION in the manner prescribed by mnasman but my app seems to be closing down before the message handler does anything. I know this because if I Log off with unsaved stuff in excel the delphi program shuts down before the message appears in excel. Is there something I have forgotten?
Code is as below ;

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;

type
  TForm1 = class(TForm)
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
    { Private declarations }
    function HookProc(var Message: TMessage): boolean;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

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!! }
       messagebeep(MB_ICONEXCLAMATION     ) ;
      { This should execute all ExitProcs, close windows and call destructors... }
       Halt; { This works! }

      { 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!}
{ Close;} { This doesn't always work - avoid it }
    end;
  end;
end;

end .

Commented:
Listening

Commented:
What about the forms on CloseQuery?


unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs;

type
  TForm1 = class(TForm)
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
if MessageDlg('Program about to close!'+#13#10#13#10+'Sure u want to close without saving?', mtConfirmation, [mbYes,mbNo], 0) = mrYes then
  CanClose := true
else
begin
  CanClose := false
end;
end;



Dennis

Commented:
narrowgate,

A pointer for you: the Halt you have will cause the application to be terminated immediately - no further code will be executed in that block! That is why the Close method doesn't execute.

To resolve this, I'd use something like the following:

if WordBool(Message.wParam) then begin
  { Windows is closing down - clean up!! }
  messagebeep(MB_ICONEXCLAMATION);
  Release;
  Application.Terminate; // only use if this form is not the MainForm for the application
  end;


The Release method will Free & Destroy the form only AFTER all message processing has been completed, but returns immediately to the caller.

Hope that helps!

Author

Commented:
Sorry for the delay in replying. Haven't managed to solve the prob in exactly the way I wanted but I have got a result. It seems Windoze sends a Query end sess and an end sess without worrying about whether an app posts the yes/no/cancel message. I think that the app is being naughty by responding yes to the query and only worrying about unsaved data on the endsession.

Anyway got around this by doing a forced shutdown when endsession appears thus ensuring that my app is always running (in a roundabout way). Have given the points the most helpful post, but thanks everyone.

Explore More ContentExplore courses, solutions, and other research materials related to this topic.