Link to home
Start Free TrialLog in
Avatar of the_modder
the_modderFlag for United States of America

asked on

Program won't accept TMessage without Show, then Hide

Hi. I'm making a system tray application that is not supposed to be visible, ever. It needs to detect when the user is about to log off, and pop up a message. However, I'm having issues getting a clean solution to intercepting the windows messages, as I have to show the form and then hide it. If I don't do this, then the messages never get received.
unit Unit2;
 
interface
 
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;
 
type
  TForm2 = class(TForm)
    Button1: TButton;
  procedure EndSMsg(var T : TMessage);message  WM_QUERYENDSESSION;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
 
var
  Form2: TForm2;
 
 
implementation
 
{$R *.dfm}
 
 
procedure TForm2.Button1Click(Sender: TObject);
begin
  hide;
end;
 
procedure TForm2.EndSMsg(var T : TMessage);
begin
  T.result := 1;
  if T.lparam = 0 then
    begin
    ShowMessage('System is shutting down');
    end
  else if (DWORD(T.lparam) and ENDSESSION_LOGOFF) =
                                 ENDSESSION_LOGOFF then
    begin
    ShowMessage('User is logging off');
    end;
end;
 
procedure TForm2.FormCreate(Sender: TObject);
begin
  show;
  hide;
end;
 
end.

Open in new window

Avatar of ThievingSix
ThievingSix
Flag of United States of America image

For something like this you wouldn't use a form at all.

Like so:



program Project1;
 
uses
  Windows, Messages, Dialogs;
 
var
  Msg : TMsg;
begin
  While GetMessage(Msg,0,0,0) Do
    begin
    If Msg.message = WM_QUERYENDSESSION Then
      begin
      If Msg.lParam = 0 Then
        begin
        ShowMessage('System is shutting down');
        Break;
      end
      Else If (Msg.lParam And ENDSESSION_LOGOFF) = ENDSESSION_LOGOFF Then
        begin
        ShowMessage('User is logging off');
        Break;
      end;
    end;
  end;
end.

Open in new window

use Application.OnMessage event handler, the way you do this message wil lbe intercepted only if TFOrm2 exists

ziolko.
Avatar of the_modder

ASKER

ThievingSix:
The attached code doesn't seem to work. Nothing gets triggered.

ziolko: I think that the message never gets sent to my window because the application never registers itself since its invisible (application.showmainform = false)
program Project1;
 
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ShellAPI, INIFiles,
  Unit1 in 'Unit1.pas' {Form1};
 
{$R *.res}
 
var
  Msg : TMsg;
begin
  Application.Initialize;
  Application.CreateForm(TForm1, Form1);
  application.showmainform := false;
  Application.Run;
  While GetMessage(Msg,0,0,0) Do
    begin
    If Msg.message = WM_QUERYENDSESSION Then
      begin
      If Msg.lParam = 0 Then
        begin
        ShowMessage('System is shutting down');
        Break;
      end
      Else If (Msg.lParam And ENDSESSION_LOGOFF) = ENDSESSION_LOGOFF Then
        begin
        ShowMessage('User is logging off');
        Break;
      end;
    end;
  end;
end.

Open in new window

SOLUTION
Avatar of ThievingSix
ThievingSix
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Even this code doesn't work. It does not detect a user logoff :(
    program Project1;
 
uses
  Windows,
  Messages,
  SysUtils,
  Variants,
  Classes,
  Graphics,
  Controls,
  Forms,
  Dialogs,
  StdCtrls,
  ShellAPI,
  INIFiles;
 
{$R *.res}
 
var
  Msg : TMsg;
begin
  While GetMessage(Msg,0,0,0) Do
    begin
    TranslateMessage(Msg);
    DispatchMessage(Msg);
    If Msg.message = WM_QUERYENDSESSION Then
      begin
      If Msg.lParam = 0 Then
        begin
        ShowMessage('System is shutting down');
        Break;
      end
      Else If (Msg.lParam And ENDSESSION_LOGOFF) = ENDSESSION_LOGOFF Then
        begin
        ShowMessage('User is logging off');
        Break;
      end;
    end;
  end;
end.

Open in new window

ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
ziolko: I have followed your advice and added a TApplicationEvents component. However, it still does not detect a user log off. If I don't comment out the Msg.lparam and the following sections, when I right click on the desktop, it seems that the application just keeps on opening up message boxes.
procedure TForm1.ApplicationEvents1Message(var Msg: tagMSG;
  var Handled: Boolean);
begin
  //if Msg.lparam = 0 then
  //  begin
  //  ShowMessage('System is shutting down');
  //  end
  //else
  if (DWORD(Msg.lparam) and ENDSESSION_LOGOFF) =
                                 ENDSESSION_LOGOFF then
    begin
    ShowMessage('User is logging off');
    end;
 
end;

Open in new window

Thanks guys. After hours of bashing my head into the wall, I figured out that another one of my procedures was grabbing the messages. However, ziolko's solution was better, as I learned something new from it, which I will use later in my projects.