Hi, I hope to find the solution here....

I want my app to minimize to tray and to use tooltip icon (in systray) for some info for the user. I've tried to find some source code for this but it seams that no one wants to share "the secret". I hope that in this place I'll find the answer...

Thanks in advance for any hint or suggestions ;)

Dani AI

Generated

Short summary: the two approaches already posted are the right ones — call Shell_NotifyIcon with a properly filled TNotifyIconData (as in ’s quick example) or use a small wrapper/class (see ’s TTrayIcon) or a ready component such as CoolTray. The notes below add practical, implementation‑level advice and common gotchas that are not obvious from the snippets.

  • Initialize/clean up reliably: always FillChar/ZeroMemory the TNotifyIconData before use and set cbSize. Register once with NIM_ADD, change text or icon with NIM_MODIFY, and remove with NIM_DELETE on shutdown (or in the component destructor). Keep the same uID and a live window handle for the lifetime of the icon.
  • Flags and text: include NIF_TIP to show the tooltip and NIF_ICON if supplying an icon. Copy the tip into the structure’s szTip with the correct PChar/StrPCopy semantics for the Delphi version being used (watch Unicode vs ANSI differences in Delphi 2009+). If an update does not appear, use NIM_MODIFY rather than re-adding.
  • Message handling: use AllocateHWnd/DeallocateHWnd (or a windowed component) to receive the callback message (WM_USER + n). Handle WM_LBUTTONDBLCLK, WM_RBUTTONDOWN, etc., and show a popup menu from the cursor position. Ensure the callback message value is unique enough not to collide with other WM_USER uses.
  • Troubleshooting: check Shell_NotifyIcon return values and GetLastError when things fail. If the tooltip is truncated or missing, verify OS limitations and the structure size; balloon hints require NIF_INFO and additional NOTIFYICONDATA fields, and behavior can differ across Windows versions and shell restarts (Explorer crash will remove icons).
  • Design tip: encapsulate tray logic in a small class (register/unregister, update tip, show menu). That mirrors ’s approach and avoids leaks or orphan icons if the form is closed unexpectedly.

This guidance complements the posted examples and helps avoid the common runtime and cross‑version pitfalls when adding and updating tray tooltips in Delphi.

Recommended Answers

All 2 Replies

this what i've play a time ago

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls,shellapi;
const

WM_CAllBack = WM_USER;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
   procedure go_to_tray(var msg:TMessage);message wm_syscommand;
   procedure WM_CALLBACKPRO(var msg : TMessage); message wm_callBack;
    { Public declarations }
  end;

var
  Form1: TForm1;
  tricon:HICON;
  TrayIcon : TNotifyIconData;

implementation

{$R *.DFM}

{ TForm1 }

procedure TForm1.WM_CALLBACKPRO(var msg : TMessage);
var
p : TPoint;
begin

case msg.LParam of
 WM_LBUTTONDOWN :
  begin
    Shell_NotifyIcon(NIM_DELETE,@TrayIcon);
    Form1.Visible := True;
  end;
 end;
end;

procedure TForm1.go_to_tray(var msg: TMessage);
var tray:boolean;
begin
//
tray:=false;
 if msg.WParam=sc_minimize then
//  MessageDlg('ssss', mtWarning, [mbOK], 0);
  begin
         Form1.Visible := False;
         tricon:= application.Icon.Handle;
         Trayicon.cbSize := SizeOf(TNotifyIconData);
         Trayicon.Wnd := handle;
         Trayicon.szTip := 'acing';
         Trayicon.uID := 1;
         TrayIcon.hIcon := tricon;
         TrayIcon.uCallbackMessage := WM_CAllBack;
         Trayicon.uFlags := NIF_MESSAGE or NIF_ICON or NIF_TIP;
         Shell_NotifyIcon(NIM_ADD,@trayicon);
//         formshow:=false;
//         form1.Hide;
         tray:=true;
         ShowWindow(Form1.Handle,SW_HIDE);
         ShowWindow(Application.Handle,SW_HIDE);
  end;

 inherited;
 if tray then
  begin
   ShowWindow(Form1.Handle,SW_HIDE);
   ShowWindow(Application.Handle,SW_HIDE);
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
MessageDlg('aa', mtWarning, [mbOK], 0);
end;

end.

another suggestion is to use cooltray component. is very usefull

if you want i think you'll find some good docs about this here:

http://delphi.about.com/od/kbwinshell/l/aa121801a.htm

and here

best regards,

To create a tray application you need three main things: (1) a (hidden?) window to receive messages from Windows about your tray icon (2) a Windows procedure for the window where you handle those messages and (3) calls to the Shell_NotifyIcon() API to add, modify and remove your icon.

Here's a sample class (extracted from a program I've just been working on, that does all those things. It also provides a menu when you right click the icon and activates the default menu item when double-clicked. You can tweak it to do other things.

unit UTrayIcon;

interface

uses
  Messages, Windows, Graphics, ShellAPI, Menus;

type

  TTrayIcon = class(TObject)
  private
    fWnd: HWND;
    fIcon: TIcon;
    fTip: string;
    fMenu: TPopupMenu;
    procedure DoDefaultMenuAction;
    procedure DisplayPopupMenu;
    procedure WndProc(var Msg: TMessage);
    procedure InitIconData(const Icon: TIcon; const Tip: string;
      out IconData: TNotifyIconData);
    procedure RegisterTrayIcon;
    procedure UnRegisterTrayIcon;
  public
    constructor Create(const Icon: TIcon; const Tip: string;
      const Menu: TPopupMenu);
    destructor Destroy; override;
    procedure SetTip(const Tip: string);
  end;

implementation

uses
  SysUtils, Classes;

const
  // message we receive from Windows when somethings happens to our icon
  CM_TRAY = WM_USER + 1; 

constructor TTrayIcon.Create(const Icon: TIcon; const Tip: string;
  const Menu: TPopupMenu);
begin
  Assert(Assigned(Icon)); // icon to display
  Assert(Assigned(Menu)); // popup menu for right clicks
  inherited Create;
  fWnd := AllocateHWnd(WndProc); // hidden window - see Delphi help
  fIcon := TIcon.Create;
  fIcon.Assign(Icon);
  fTip := Tip;
  fMenu := Menu;
  RegisterTrayIcon;
end;

destructor TTrayIcon.Destroy;
begin
  UnRegisterTrayIcon;
  FreeAndNil(fIcon);
  if fWnd <> 0 then
    DeallocateHWnd(fWnd);
  inherited;
end;

procedure TTrayIcon.DisplayPopupMenu;
var
  Pos: TPoint;
begin
  GetCursorPos(Pos);
  if Assigned(fMenu) then
    fMenu.Popup(Pos.X, Pos.Y);
end;

procedure TTrayIcon.DoDefaultMenuAction;
var
  Idx: Integer;
  MI: TMenuItem;
begin
  if not Assigned(fMenu) then
    Exit;
  // find default menu item if any and "click" it if found
  for Idx := 0 to Pred(fMenu.Items.Count) do
  begin
    MI := fMenu.Items[Idx];
    if MI.Default then
    begin
      MI.Click;
      Break;
    end;
  end;
end;

procedure TTrayIcon.InitIconData(const Icon: TIcon; const Tip: string;
  out IconData: TNotifyIconData);
begin
  // helper method to ease setting up TNotifyIconData structure
  // see Windows API help for NOTIFYICONDATA for details
  with IconData do
  begin
    cbSize := SizeOf(IconData);
    Wnd := fWnd;
    uID := 0;
    uFlags := NIF_MESSAGE; // says to use our callback message
    if Assigned(Icon) then
      uFlags := uFlags or NIF_ICON;  // says to use icon we provide
    if Tip <> '' then
      uFlags := uFlags or NIF_TIP; // says to use tooltip we provide
    uCallbackMessage := CM_TRAY;
    if Assigned(Icon) then
      hIcon := Icon.Handle // handle to our icon
    else
      hIcon := 0;
    StrPCopy(szTip, Tip); // info tip
  end;
end;

procedure TTrayIcon.RegisterTrayIcon;
var
  IconData: TNotifyIconData;
begin
  // adds tray icon
  InitIconData(fIcon, fTip, IconData);
  Shell_NotifyIcon(NIM_ADD, @IconData);
end;

procedure TTrayIcon.SetTip(const Tip: string);
var
  IconData: TNotifyIconData;
begin
  // sets info tip for tray icon
  InitIconData(nil, Tip, IconData);
  Shell_NotifyIcon(NIM_MODIFY, @IconData);
end;

procedure TTrayIcon.UnRegisterTrayIcon;
var
  IconData: TNotifyIconData;
begin
  // removes tray icon
  InitIconData(fIcon, '', IconData);
  Shell_NotifyIcon(NIM_DELETE, @IconData);
end;

procedure TTrayIcon.WndProc(var Msg: TMessage);
begin
  // check for our custom message
  if Msg.Msg = CM_TRAY then
  begin
    // we handle double click and right mouse click 
    case Msg.LParam of
      WM_LBUTTONDBLCLK: DoDefaultMenuAction;
      WM_RBUTTONDOWN: DisplayPopupMenu;
    end;
  end
  else
    // default processing for other messages
    Msg.Result := DefWindowProc(fWnd, Msg.Msg, Msg.WParam, Msg.LParam);
end;

end.

I hope that's clear from comments in code

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.