Solved

how to minimize the application into the sytem tray?

Posted on 2001-06-28
7
374 Views
Last Modified: 2010-04-06
i'm going to write an application that could minimize himself into the system tray (MS Windows). and if the icon clicked, it would activate a popup menu....
what should i do?
0
Comment
Question by:eddie_kho
7 Comments
 
LVL 1

Accepted Solution

by:
Kaspars earned 50 total points
ID: 6234516
Well, man, there is a lot of solutions, but there is, how to do it manually. Although there are some side effects - at first, your main form acts like child form, but some little workaround and it can be fixed (i did).
Hiding an Application from Windows and Applying that Technique with Creating a System Tray Application

By Brendan Delumpa

How do I keep an application from displaying a button on the Windows task bar and prevent users from using [Alt-Tab] to switch to it once it executes?

By convention, any application's window that has its extended window style bit set as a tool window (WS_EX_TOOLWINDOW) will be hidden from the task bar and users will not be able to switch to it. In Delphi, every form has a BorderStyle property of bsToolWindow, so you might think that all you have to do is set the borderstyle of the main form of the application to bsToolWindow and you'll be able to hide the application from the task bar. Not really. The reason for this is because the main form of the application really isn't the main form of the application.

The application object that encapsulates all Delphi programs (TApplication) actually has a form of its own. It's totally transparent, so you can't really see it. This is the window we need to interact with in order to hide the application. So how do we do it? Well, if you remember what I said at the top of this tip, the Windows convention for "hiding" an application is to set its extended window style bit to WS_EX_TOOLWIN. You can easily do this with a little Windows API trickery. Yes, that's right, trickery. We trick the application into displaying as a tool window instead of an application window.

Specifically, in order to accomplish this task you have to edit the project's source code. Here's a complete listing:


program Project1;

uses
  Forms,
 Unit1 in 'Unit1.pas' {Form1},
  Windows;

{$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.

Notice that I've treated the application object like a window. It's legal to do that because the application object has its own window?it's just hidden. So by using a couple of functions to retrieve and then set the window display properties, we can achieve the desired effect. The first function, GetWindowLong, is a Windows API function that takes an application handle and a constant representing a bit offset stored in Windows that describes a particular window. For our purposes, we pass the GWL_EXSTYLE offset value to retrieve the extended window style information. Once we've got that, it's a simple matter of making a call to SetWindowLong to make the change to the application. SetWindowLong takes the application's handle, the information offset, and what you want to change at that offset. Once called, it changes the window appropriately. The net effect is that no button is displayed for the application on the task bar and you won't be able to [Alt-Tab] to the application. It's really hidden. You should probably study the online documentation regarding the Get- and SetWindowLong Windows API functions to better familiarize yourself with the functions. You'll see that you can do a lot more with these functions than what I've just brushed over here.

Getting Some Use Out of All This...

When I originally started writing this article, I was going to leave it at hiding an application from Windows. But then I thought to myself, "What use is it?" The most obvious use of the technique is for creating system tray applications; that is, applications that add an icon to the system tray and are invoked from there as opposed to the task bar. For example, the Audio Control (the little loudspeaker at the bottom right of your screen) is a system tray application. So how do you create a system tray application? Easy. Just 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;


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.

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 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.
0
 
LVL 8

Expert Comment

by:Cesario
ID: 6234521
Hello eddie,

download this component
http://www.torry.net/vcl/system/tasks/tytsystray.zip

Best Regards

Cesario
0
 
LVL 22

Expert Comment

by:mnasman
ID: 6234545
This question answered before, you can see the question and the comments in this link

http://www.experts-exchange.com/jsp/qShow.jsp?qid=11453899
0
Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

 
LVL 3

Expert Comment

by:MarcG
ID: 6234565
first you need to add a new message to your form ...
const WM_TASKBAREVENT = WM_USER + 1;
add a new procedure for this event to the form
procedure WMTASKBAREVENT(var message: TMessage); message WM_TASKBAREVENT;

you need shellAPI unit for that.

//Minimize it to system tray
procedure Button1click(Sender: TObject);
begin
  ShowWindow(GetWindow(handle, GW_OWNER), SW_HIDE);
self.hide;
  TaskBarAddIcon; //My Procedure to add an icon to System Tray
end;

//show Icon in ST
procedure TaskBarAddIcon;
var tnid : TNOTIFYICONDATA;
begin
  tnid.cbSize := SizeOf(TNOTIFYICONDATA);
  tnid.Wnd := Form1.handle;
  tnid.uID := 1; //any ID you want
  tnid.uFlags := NIF_MESSAGE or NIF_ICON or NIF_TIP; //Icon-handle, Message and Tooltip are given
  tnid.uCallbackMessage := WM_TASKBAREVENT;
  tnid.hIcon := form1.image1.picture.icon.handle;
  strcopy(tnid.szTip, 'MyTooltip');
  Shell_NotifyIcon(NIM_ADD, @tnid); //Register ...
end;

//react upon systemtray clicks
procedure TForm1.WNTASKBAREVENT(var message: TMessage);
vat Point : TPoint;
begin
  case message.LParamLo of
    WM_LBUTTONDBLCLK :
    begin
      Form1.show;
      TaskBarRemoveIcon;
    end;
    WM_RBUTTONDOWM :
    begin
      GetCursorPos(Point);
      popupmenu1.popup(point.x, point.y);
    end;
  end;
end;

//Clean up TNA
procedure TaskBarRemoveIcon;
var tnid: TNOTIFYICONDATA;
begin
  tnid.cbSize := sizeof(TNOTIFYICONDATA);
  tnid.Wnd := Form1.handle;
  tnid.uID := 1;
  Shell_NotifyIcon(NIM_DELETE, @tnid);
end;

0
 
LVL 3

Expert Comment

by:MarcG
ID: 6234567
again too slow :( when I started writing it was still no comments ... had to make a short break and then ...
0
 

Author Comment

by:eddie_kho
ID: 6236518
thanks guys, give me a little time to try your suggestions... i'll tell you the result in soon...
0
 

Author Comment

by:eddie_kho
ID: 6329354
sorry.. sorry, it has been a month since the last comment... i've had something else to do that didn't left many time for me to try your suggestions, i'm not busy recently so i tried your code and it's work very well...
i want to say thank you very much to all of you, but after all there could be only one who gain the point and i think i'll give it to kaspars...
0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
Introduction Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGrid…
Here's a very brief overview of the methods PRTG Network Monitor (https://www.paessler.com/prtg) offers for monitoring bandwidth, to help you decide which methods you´d like to investigate in more detail.  The methods are covered in more detail in o…
This video gives you a great overview about bandwidth monitoring with SNMP and WMI with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're looking for how to monitor bandwidth using netflow or packet s…

760 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

Need Help in Real-Time?

Connect with top rated Experts

21 Experts available now in Live!

Get 1:1 Help Now