Solved

Program won't accept TMessage without Show, then Hide

Posted on 2008-10-20
8
250 Views
Last Modified: 2012-05-05
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

0
Comment
Question by:the_modder
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 4
  • 2
  • 2
8 Comments
 
LVL 13

Expert Comment

by:ThievingSix
ID: 22755764
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

0
 
LVL 21

Expert Comment

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

ziolko.
0
 
LVL 1

Author Comment

by:the_modder
ID: 22760129
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

0
[Live Webinar] The Cloud Skills Gap

As Cloud technologies come of age, business leaders grapple with the impact it has on their team's skills and the gap associated with the use of a cloud platform.

Join experts from 451 Research and Concerto Cloud Services on July 27th where we will examine fact and fiction.

 
LVL 13

Assisted Solution

by:ThievingSix
ThievingSix earned 20 total points
ID: 22763417
Comment out line 16: "Application.Run". If you need to use a form in the application do something like below.
program Project1;
 
uses
  Windows,
  Messages,
  SysUtils,
  Variants,
  Classes,
  Graphics,
  Controls,
  Forms,
  Dialogs,
  StdCtrls,
  ShellAPI,
  INIFiles,
  Unit2 in 'Unit2.pas' {Form2};
 
{$R *.res}
 
var
  Msg : TMsg;
begin
  Application.Initialize;
  Application.CreateForm(TForm2, Form2);
  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

0
 
LVL 1

Author Comment

by:the_modder
ID: 22764552
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

0
 
LVL 21

Accepted Solution

by:
ziolko earned 80 total points
ID: 22764979
>>I think that the message never gets sent to my window because the application never registers itself since its invisible (application.showmainform = false)

showing main form doesn't matter once aplication object is created it's ready to process windows messages, WM_QUERYENDSESSION is sent to all top level windows so it must reach Appplication object.

your code snippets with while GetMessage() do ... are not a good idea because once GetMessage() returns false (no messages in queue) loop is exited and never again checks for incoming messages.

Like I wrote before write OnMessage event handler and assign it to Application.OnMessage or use TApplicationEvents component and it's OnMessage event.

ziolko.
0
 
LVL 1

Author Comment

by:the_modder
ID: 22774331
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

0
 
LVL 1

Author Closing Comment

by:the_modder
ID: 31507735
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.
0

Featured Post

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

This article explains how to create forms/units independent of other forms/units object names in a delphi project. Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi proj…
Objective: - This article will help user in how to convert their numeric value become words. How to use 1. You can copy this code in your Unit as function 2. than you can perform your function by type this code The Code   (CODE) The Im…
Monitoring a network: why having a policy is the best policy? Michael Kulchisky, MCSE, MCSA, MCP, VTSP, VSP, CCSP outlines the enormous benefits of having a policy-based approach when monitoring medium and large networks. Software utilized in this v…
This tutorial will teach you the special effect of super speed similar to the fictional character Wally West aka "The Flash" After Shake : http://www.videocopilot.net/presets/after_shake/ All lightning effects with instructions : http://www.mediaf…
Suggested Courses
Course of the Month5 days, 5 hours left to enroll

635 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question