Board index » delphi » How to get my Application into the Systray?

How to get my Application into the Systray?

Hi!
I won't ot write an application that get's into the systray (where the
clock, etc is). Can anybody help me?
Examples are welcome!
 

Re:How to get my Application into the Systray?


July 1998

Creating a System Tray Application: A 10-Minute Solution

By Brendan Delumpa

Isn't it funny how coding certain things in Windows that appear as if they
should be easy to implement, ultimately become exercises in "hair pulling"?
It's not so much that the task of coding is that difficult; the information you
need to accomplish it is either hidden behind layers of related, hyperlinked
material (for example, Windows help) or does not exist in the first place
(certain "omissions" in the Delphi technical documentation. Have I been here
before?). Well, such is the case with creating System Tray applications.
Implementation is actually a snap, but getting to the point where you know
enough to implement it is not so straightforward. And when you see the code for
creating a System Tray application, like me, you'll probably smirk. But don't
worry, it's not something that'll make you say, "Duh!" Let's take a look...

There are two distinct things that you need to take care of to successfully
create a System Tray application. The first thing is to "hide" your application
from Windows. While System Tray applications look and act the same as any
Windows program, they can't be switched to using Alt-Tab, nor do they have a
button on the task bar. So we'll take care of that first.

By convention, any window that has a style of WS_EX_TOOLWINDOW is not available
to the task bar, nor are users able to switch to it. At first, you might think
that you would set this style using the CreateParams procedure. Unfortunately,
that procedure will only work on a form. Now let's make a distinction here. The
main form of the application is not the application's window. An application
object has its own window--you can't see it, but it's there just the same. This
is the window to which you apply the WS_EX_TOOLWINDOW style. So where do you
put the code? In the project source, of course. So, open up an new project,
then select View|Project Source from the main menu in the IDE. Once there, copy
and paste the following code into the editor window.

program Project1;

uses
  Forms,
  Unit1 in 'Unit1.pas' {Form1},
  Windows; //THIS IS REQUIRED TO SET THE WINDOW STYLE!

{$R *.RES}

//Declare a var to retrieve current window information
var
  ExtendedStyle : Integer;

begin
  Application.Initialize;

  //Get the Extended Styles of the Application, by passing its
  //handle to GetWindowLong
  ExtendedStyle := GetWindowLong(Application.Handle, GWL_EXSTYLE);

  //Now, set the Extended Style by doing a bit masking operation.
  //OR in the WS_EX_TOOLWINDOW bit, and AND out the WS_EXAPPWINDOW bit
  //This effectively converts the application from an App Windows to a
  //Tool Window.
  SetWindowLong(Application.Handle, GWL_EXSTYLE, ExtendedStyle OR
WS_EX_TOOLWINDOW
                                                 AND NOT WS_EX_APPWINDOW);
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.

Now, to actually create the effect of a System Tray application (put our
application into the System Tray itself) is a bit more involved than hiding the
application, but by no means is it a difficult proposition. So what will you
need? First of all you'll need the main form of the application. Once there,
drop a TPopupMenu component on the form. The popup menu will act as the main
interface for performing various actions you'd like to take with your System
Tray application. Take a look at the code below:

{This sets up the application to be a system tray application.
 This is the main form for the application. It has a popup menu
 that will be used to display the main form, or close the application.

 And using the ShellAPI unit, we can then use a couple of calls to display
 the application's icon on the system tray, and make it respond to a
 right mouse click}

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  ShellAPI, ExtCtrls, Menus;

type
  TForm1 = class(TForm)
    PopupMenu1: TPopupMenu;
    ShowMainForm1: TMenuItem;
    N1: TMenuItem;
    ExitApplication1: TMenuItem;
    procedure FormCreate(Sender: TObject);
    procedure ShowMainForm1Click(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure ExitApplication1Click(Sender: TObject);
  private
    procedure WndProc(var Msg : TMessage); override;
  public
    IconNotifyData : TNotifyIconData;
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);
begin
  //Set the border icons to have only a system menu. This will
  //leave just the close button.
  BorderIcons := [biSystemMenu];
  //Now set up the IconNotifyData structure so that it receives
  //the window messages sent to the application and displays
  //the application's tips
  with IconNotifyData do begin
    hIcon := Application.Icon.Handle;
    uCallbackMessage := WM_USER + 1;
    cbSize := sizeof(IconNotifyData);
    Wnd := Handle;
    uID := 100;
    uFlags := NIF_MESSAGE + NIF_ICON + NIF_TIP;
  end;
  //Copy the Application's Title into the tip for the icon
  StrPCopy(IconNotifyData.szTip, Application.Title);
  //Add the Icon to the system tray and use the
  //the structure and its values
  Shell_NotifyIcon(NIM_ADD, @IconNotifyData);
end;

procedure TForm1.WndProc(var Msg : TMessage);
var
  p : TPoint;
begin
  case Msg.Msg of
    WM_USER + 1:
    case Msg.lParam of
      WM_RBUTTONDOWN: begin
                        GetCursorPos(p);
                        PopupMenu1.Popup(p.x, p.y);
                      end;
    end;
  end;
  inherited;
end;

{This is one of the popup menu item's OnClick handler}
procedure TForm1.ShowMainForm1Click(Sender: TObject);
begin
  Form1.Show;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caNone;
  Form1.Hide;
end;

procedure TForm1.ExitApplication1Click(Sender: TObject);
begin
  Shell_NotifyIcon(NIM_DELETE, @IconNotifyData);
  Application.ProcessMessages;
  Application.Terminate;
end;

end.

As you can see, there's really not much to this. Just study the code to see
what's going on. But the important thing you should concentrate on is the
Create method of the form and what is done to the IconNotifyData structure.
This is a record structure declared in the ShellAPI unit that stores
information for a tray icon. Notice the flags that were used: NIF_MESSAGE +
NIF_ICON + NIF_TIP. These flags tell the icon to process application messages,
use the application's icon and its tip, respectively. Once we've set up all
that, then it's a simple matter of creating the window interaction stuff, like
we'd normally do at design time. The tray icon doesn't come into play until run
time.

The other thing to look at is the override of the WndProc procedure. WndProc is
short for Window Procedure. It intercepts all the messages sent to the window,
and acts as the central message dispatcher. In that procedure, you can trap
specific Windows messages by overriding the inherited procedure. In our case,
we trap two things: the Msg field of the message sent to the application. If it
was our custom message (WM_USER + 1) defined for the IconNotifyData variable,
then we want to handle a right-click. All other messages sent to the
application are handled in their normal fashion.

I realize that this 10-Minute Solution was pretty quick and dirty, so I
encourage you to play around with the code. Just keep in mind that you have to
do two things, if you're going to create system tray application:

1.You need to first create the "hiding" mechanism for the application. 2.Then,
you need to create the interface so that you can interact with the application
when its main form isn't being displayed.

Notice that I didn't really do too much with the form. I wanted to keep the
presentation as simple as possible. However, there is nothing to stop you from
making a more complex menu with more complicated actions. Remember: a System
Tray application is pretty much like any other Windows program.

?

Other Threads