Click here to Skip to main content
Click here to Skip to main content

System Tray Icons - Minimize Your Application to the SysTray

By , 6 Nov 2000
 

Sample Image - TrayIcons.jpg

Introduction

This article illustrates the use of Shell_NotifyIcon to create and manage System Tray icons. The article explains the basics of this operation and assists you in creating your own 'Minimize To Tray' applications. The source code provided with this article is designed to work with dialog-based applications, but it can easily be modified to work with a CFrameWnd or CWnd based application.

Creating and Using Tray Icons

To create a Tray Icon, you need to call the following shell function: -

BOOL Shell_NotifyIcon( DWORD dwMessage, PNOTIFYICONDATA pnid );

The dwMessage parameter specifies the action to be taken - NIM_ADD, NIM_DELETE, NIM_MODIFY adds, deletes and modifies tray icons respectively.

The pnid parameter is used to customize, create, delete and obtain data from the Tray Icon. (See the MSDN Library for more details about this structure.)

Creating The Application

1. Create a new VC++ dialog based project. For this example, I will call this project MyTray which will contain the CMyTrayApp and CMyTrayDlg classes.

2. Download and extract the DialogTray source code to the root of the project folder

3. From the Project->Add To Project menu, select Files and then select TrayDialog.h and TrayDialog.cpp. This will add a new class to your project named CTrayDialog.

4. Replace the CMyTrayDlg base class with CTrayDialog.

class CMyTrayDlg : public CDialog

becomes

#include "TrayDialog.h"

class CMyTrayDlg : public CTrayDialog

5. Replace the other occurrences of CDialog in the MyTrayDlg.cpp file as follows :-

CMyTrayDlg::CMyTrayDlg(CWnd* pParent /*=NULL*/)
  : CDialog(CMyTrayDlg::IDD, pParent)

becomes

CMyTrayDlg::CMyTrayDlg(CWnd* pParent /*=NULL*/)	
    : CTrayDialog(CMyTrayDlg::IDD, pParent)

6. Create a menu resource and name it IDR_MENU1

7. In the InitDialog member function, enter the following:

    TraySetIcon(IDR_MAINFRAME);
    TraySetToolTip("ToolTip for tray icon");
    TraySetMenu(IDR_MENU1);

8. Modify the IDD_MYTRAY _DIALOG resource to have a minimize box.

9. Build and run the application

NB : To add tray menu item handlers use the class wizard.

Displaying the tray icon all the time

Simply add a TrayShow() statement to InitDialog() in CMyTrayDlg.cpp, and call TraySetMinimizeToTray(FALSE) to disable minimizing to the tray.

The events that occur in the tray are captured through the following functions:

    virtual void OnTrayLButtonDown(CPoint pt);
    virtual void OnTrayLButtonDblClk(CPoint pt);

	virtual void OnTrayRButtonDown(CPoint pt);
	virtual void OnTrayRButtonDblClk(CPoint pt);
  
	virtual void OnTrayMouseMove(CPoint pt);

Feel free to add more events or to improve on these ones.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Daniel Zilcsak
Software Developer
United States United States
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionTrayShow() leads the minimize button becoming invalidmemberScarlettlee16 May '13 - 0:17 
Hello.
When I add a TrayShow() statement to InitDialog() in CMyTrayDlg.cpp, The minimize button of the main dialog doesn't work. Any suggestions? Thanks!
QuestionHow to do If I want it be Tray Mode while begging?membervannes23 Dec '11 - 1:12 
Dear Author:
If I want it minimize to tray while program start, how to implement that?
Thanks!!!
AnswerRe: How to do If I want it be Tray Mode while begging?memberEsenChang5 Aug '12 - 17:38 
You can use "PostMessage(WM_SYSCOMMAND, SC_MINIMIZE)" on your OnInitDialog Smile | :)
Questionprogramatically minimizing does not work on VS 2005memberErik17 Oct '11 - 19:01 
Hi,
 
when I call
 
this->ShowWindow(SW_MINIMIZE);
 
in OnInitDialog to hide the Window to the tray, the Dialog is not minimized to the tray, actually my breakpoint in
 
void CTrayDialog::OnSysCommand(UINT nID, LPARAM lParam)
 
is never reached.
 
How can I make the dialog minimize to tray programatically, without manually clicking the minimize box?
QuestionCWinAppmemberMember 806538825 Aug '11 - 23:52 
My aplication derives the base class CWinApp rather than CDialog. Is there some way to adapt this solution to suit my project? Thank You.
AnswerRe: CWinAppmemberMember 806538826 Aug '11 - 0:13 
Oh and my main window derives CMDIFrameWnd.
QuestionLicencingmemberrainer.hochdorfer27 Apr '10 - 22:06 
Hello Daniel,
 
We would like to use your code in our software. Are there are any copyright limitations using this code?
 
Specifically, are there any restrictions using your code as part of a commercial software application?
 
Kind Regards,
Rainer
AnswerRe: LicencingmemberDaniel Zilcsak28 Apr '10 - 3:29 
This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL), see http://www.codeproject.com/info/cpol10.aspx[^]
AnswerRe: Licencingmemberrainer.hochdorfer28 Apr '10 - 6:02 
Thanks a lot! Smile | :)
GeneralThanks just perfectmemberasierra0111 Jan '10 - 9:14 
I saw a sample on wxWidgets, Python win32, but my code is in MFC, this is perfect.
 
Jorge Sierra
C++ Programmer
www.geocities.com/asierra01
404-409-4540 Cell

GeneralRight Click MenumemberShup15 May '09 - 1:20 
Hi,
 
First of all, a great class and my full rating.
 
I have a strange problem, I used the following code:
 
void CTrayDialog::OnTrayRButtonDown(CPoint pt)
{
	CMenu *pcSubMenu = m_mnuTrayMenu.GetSubMenu(0);
	
	if(pcSubMenu)
	{
		pcSubMenu->SetDefaultItem(m_nDefaultMenuItem, TRUE);
 
		SetForegroundWindow();
		pcSubMenu->TrackPopupMenu(TPM_VERNEGANIMATION | TPM_BOTTOMALIGN | TPM_LEFTBUTTON | TPM_RIGHTBUTTON, pt.x, pt.y, this);
		PostMessage(WM_NULL, 0, 0);
	}
}
 
So that the right click menu would be dismissed if the mouse is clicked somewhere outside of there menu. But after the addition of this code, the strange thing that started to happen is that sometimes (I couldn't determine exactly when) the Windows Task Bar right click menu popes up over the application right click menu when right clicking on the application tray icon.
 
Any ideas as to how that can be resolved?
 
Regards,
 
Shup
Mind & Machines

GeneralThank you!memberDevMan7712 May '09 - 8:20 
Great article! It helps me a lot...
 
Thank you Daniel!
GeneralChanging tray icon while minimizedmembereight26 Mar '09 - 2:21 
I've added a simple timer to switch the tray icon every 5 second and it doesn't seem to work while minimized. To have the tray icon changed, I have to restore the dialog and re-minimize it back. Any idea on how I can get the tray icon to change while the dialog is minimized?
GeneralThanks!!!memberIAM...15 Feb '09 - 5:56 
that is all my friend. Cool | :cool:
 
Oscar Rangel

QuestionOnly minimizing to tray in my application?memberMember 192119231 Oct '08 - 5:03 
Hi,
 
I just downloaded the sample, followed the instructions in a new sample project, everything ok.
 
When I added TrayDialog to my current dialog based project in the same way, the only thing what happens is, that the program minimizes to the tray. There's no menu, no reaction on left double click. The only thing shown is the tooltip. I have to kill the application with the task manager...
 
There's no more CDialog reference in my source. It's nearly 99% the same code in OnInitDialog, message maps etc.
 
Any idea what to look for?
 
Alexander
QuestionBalloon Tip??memberthanasis_rassp12 Aug '08 - 3:16 
Is there a simple way to show a Windows XP Tip balloon when the program is minimized to tray? I google it and i cant understand any of the examples. Frown | :(
 
Anyway, thanks for the minimize code Wink | ;) it's neat.
AnswerRe: Balloon Tip??membervarandas7924 Sep '08 - 5:25 
Great class.
 
replace .cpp:
 
void CTrayDialog::TraySetToolTip(CString mToolTip, DWORD mIcon)
{
strcpy(m_nidIconData.szInfo, mToolTip);

CString tmp;
GetWindowText(tmp);
strcpy(m_nidIconData.szInfoTitle, tmp);
 
m_nidIconData.uFlags |= NIF_MESSAGE | NIF_ICON | NIF_TIP | NIF_INFO;
// Flag Description:
// - NIF_ICON The hIcon member is valid.
// - NIF_MESSAGE The uCallbackMessage member is valid.
// - NIF_TIP The szTip member is valid.
// - NIF_STATE The dwState and dwStateMask members are valid.
// - NIF_INFO Use a balloon ToolTip instead of a standard ToolTip. The szInfo, uTimeout, szInfoTitle, and dwInfoFlags members are valid.
// - NIF_GUID Reserved.
 
m_nidIconData.dwInfoFlags = mIcon; // add an icon to a balloon ToolTip
// Flag Description
// - NIIF_ERROR An error icon.
// - NIIF_INFO An information icon.
// - NIIF_NONE No icon.
// - NIIF_WARNING A warning icon.
// - NIIF_ICON_MASK Version 6.0. Reserved.
// - NIIF_NOSOUND Version 6.0. Do not play the associated sound. Applies only to balloon ToolTips
}
 
replace .h
 
void TraySetToolTip(CString mToolTip, DWORD mIcon=NIIF_INFO);
GeneralBug in CTrayDialog::OnSysCommand preventing sizingmemberEricGen24 Mar '08 - 23:02 
If you want your dialogue to be resizable, you need to modify CTrayDialog::OnSysCommand as follows:
 
void CTrayDialog::OnSysCommand(UINT nID, LPARAM lParam)
{
if(m_bMinimizeToTray)
{
if ((nID & 0xFFF0) == SC_MINIMIZE)
{
if( TrayShow())
{
this->ShowWindow(SW_HIDE);
return;
}
}
}
CDialog::OnSysCommand(nID, lParam);
}

GeneralSystem get slow...memberMember 385006728 Feb '08 - 21:52 
Tried this application...Its working nicely..but system gets slow..Confused | :confused:
Generalsmall but useful demomemberlilesh10 Oct '07 - 22:33 
useful source for integrating system tray functionality to application. thank
QuestionHow can I get my app on the tray at the very beginning?memberpjvv126 Sep '07 - 7:31 
Hi all!
 
I'd like to make my app on the tray when I launch it. I want it started on the sys tray so that the user doesn't have to close/minimize it.
 
I've tried to use the same code it is used when I press the minimize button but it doesn't work (actually it doesn't do anything), that is:
 
BOOL CMyTrayDlg::OnInitDialog()
{
...
if (TrayShow()) {
ShowWindow(SW_HIDE);
}
...
}
 
However, if I try "ShowWindow(SW_MINIMIZE)" it works!!! Any trace?
 

Thank you all-
Pedro
AnswerSolutionmemberlilesh10 Oct '07 - 23:01 
i looked into in but i didn't get reason why SW_HIDE doesn't work OnInit
May be the reason is that window hasn't yet created ..(i don't know the exact reason)
but, i have another solution , you can create your own message handler and postmessage to it, i have written code here just go through it.
 
#define MY_MESSAGE WM_USER+123
 
in oninit write,
BOOL CTempDlg::OnInitDialog()
{
..
...
::PostMessage(this->m_hWnd,MY_MESSAGE,0,0);

return TRUE; // return TRUE unless you set the focus to a control
}
 
in message map ON_MESSAGE(MY_MESSAGE, functohidewindow)
 
and lastly
 
void CTempDlg::functohidewindow()
{
this->ShowWindow(SW_HIDE);
}
 
may be this is not the best approch
 

 

Questionsystray without windowmemberchergui3 Apr '07 - 1:36 
hello;
is there a way to creet the systrayicon without creeing a window nor a dialogue? my application does not need any viewing just a tray icon with 2 items: go and stop. it is a great consummer of resources WTF | :WTF: and i don't want to use some resource for nothingMad | :mad:
GeneralIn VC++ 2003, there's errormembertlbf10 Jan '07 - 2:46 
In VC++ 2003, you must use "LRESULT CTrayDialog::OnTrayNotify(WPARAM wParam, LPARAM lParam)" than "void CTrayDialog::OnTrayNotify(WPARAM wParam, LPARAM lParam)", and just return 0 in this function, then your program's still best.
Thanks for your best code. Big Grin | :-D
GeneralRe: In VC++ 2003, there's errormemberchild00728 Jan '08 - 17:32 
It helped. thanks.
GeneralRe: In VC++ 2003, there's errormemberJerry Peterson14 May '09 - 3:15 
Thanks
Generaltray disappear after mouse overmembergeoPsyc4 Dec '06 - 13:05 
I got the program compiled and running, I see the icon in the tray and when I put my mouse over the icon it disappears, but the dialog and the program is still open and running, any help thanks!
GeneralRe: tray disappear after mouse overmembergeoPsyc4 Dec '06 - 13:24 
Nvm I got it, you have to replace every instance of CDialog in the MyTrayDiag.cpp file with CTrayDialog. Just do a replace run through the file.
Ugh that took me near half a day reading online and getting nowhere, hopefully this will save some anyone run into the same problem in the future.
GeneralRe: tray disappear after mouse overmemberlilesh10 Oct '07 - 23:16 
if u havn't got the solution reply..i have solution
QuestionRe: tray disappear after mouse overmemberAmbiguities23 Oct '07 - 17:53 
hey how do you even get an icon in the system tray. i have been trying to learn but i keep coming up short
 
Ambi
GeneralRe: tray disappear after mouse overmemberDau Le Trung4 Apr '12 - 17:29 
just replace all 'CDialog' to 'CTrayDialog' in your class which inherited CTrayDialog
Questioncan you help me? about tray iconmemberDavid121519 Jun '06 - 17:08 
hello, I have a different problem at trayicon, when I'm doing something, I try to R-click my trayicon, it should be pop my write menu,but it's not. it's pop windows menu(sorry, I don't know what is it name), can you help how to avoid the windows menu,thanks, have a nice day.
GeneralCompiling on VIsual C++ 7.0memberSychad19 Apr '06 - 7:34 
You have to change the prototype of OnTrayNotify
 
LRESULT CTrayDialog::OnTrayNotify(WPARAM wParam, LPARAM lParam)

GeneralRe: Compiling on VIsual C++ 7.0memberchild00728 Jan '08 - 17:31 
It helped. thanks.
GeneralDisplaying the menu in the icon tray problemmemberchris17514 Mar '06 - 8:01 
1. Bring up the menu in the system tray and don't click on any of the selections.
2. Then click away and notice the menu doesn't disappear?
 
Chris
GeneralRe: Displaying the menu in the icon tray problemmemberDean Michaud24 Mar '06 - 4:30 
Look below in the comments for the source to a solution Chris.
 
It seems to work great with the implemented solution.
 
: Dean Michaud
QuestionItem1=ShowWindow?memberAm0k30 Jan '06 - 4:12 
I want "Item 1" on systray menu to work just like "OnTrayLButtonDblClk(CPoint pt)" but can't do this Confused | :confused:
10x
GeneralIssue With CEmemberoilos16 Aug '05 - 1:23 
hi i have a small issue with this class
actually, i managed to make it work on a Windows CE
 
the only pb i got is that i dont get the icon on the system tray ?
 
do you have an idea why he is behaving like this
 
thanks

GeneralProblemmemberharpreetsbamrah23 Jun '05 - 20:24 
If i stop the explorer.exe from taskManager and then restart the explorer.My application icon disappears.Though for my project i can get away with it but am curious that Windows Messanger icon reappears in the tray when the explorer is restarted.How can i do the same for my application.Though my application is running in the background i am not able to put the icon back in the tray when the explorer restarts.Anybody any ideas on this.
GeneralRe: Problemmemberharpreetsbamrah23 Jun '05 - 20:44 
looked around found the answer on http://www.microsoft.com/msj/0299/c/c0299.aspx.
and this is how i implimented it .
declare a new message with RegisterWindowMessage in CTrayDialog.h
like this
const UINT WM_TASKBARCREATED = ::RegisterWindowsMessage(_T("TaskBarCreated"))
And in CTrayDialog.cpp make a message map entry
ON_REGISTERED_MESSAGE(WM_TASKBARCREATED,OnTaskBarCreated)
In the OnTaskBarCreated function i tried calling TrayShow() function but the bool variable is still set to true so the function fails . Had to write another private function where i am putting the icon on the tray unconditionally.
LRESULT CTrayDialog::OnTaskBarCreated(WPARAM wp, LPARAM lp)
{
VERIFY(OnExplorerTrayShow());
return 0;
}
OnExplorerTrayShow() looks like this.
 
void OnExplorerTrayShow()
{
return bSuccess = Shell_NotifyIcon(NIM_ADD,&m_nidIconData);

}
Voila it worked!!
Points to note
dont declare the OnTaskBarCreated function as virtual it has to be afx_msg because you are handling a registered windows message. This was the place where i got cought after reading the article at the indicated url. I hope CTrayIcon is complete now.
Generalsorrymembersicks18 Jun '05 - 6:42 
I solve my problem, my apologies for double posting but I can't delete my precedent message because I put a bad "email".
 
Thanks Daniel for this class.
 

Generalproblemmembersicks18 Jun '05 - 6:29 
Hi
 
I have a problem.
When I reduce my application in the systray it's ok but when I passe my mouse over the systray icon, immediatly it disappear but the application is still running because I see it on task manager.
 
Can someone could help me ?
Thanks.
GeneralRe: problemmemberAleJ15 Jun '06 - 5:36 
Hi, in your own Dlg class, you have to replace each call to CDialog class with CTrayDialog class.
 
For example:
BEGIN_MESSAGE_MAP(yourClassDlg, CDialog)
must became:
BEGIN_MESSAGE_MAP(yourClassDlg, CTrayDialog)
 
and so each other call to CDialog class, because now your Dlg class is inerithed from CTrayDialog
 
Bye,
Alessandro.

GeneralThankYou !! Modification !!memberharpreetsbamrah9 Jun '05 - 22:58 
Thanks Daniel for such an easy to use class and that too bug free.Only thing was that menu was not disappearing ,but somebody posted that too. For my specific requirement i needed the pointer to the CMenu for the icon for that i added the following and my requirement was met .
CMenu* CTrayDialog::TrayGetMenu()
{

return m_mnuTrayMenu.GetSubMenu(0);
}
I am using your class in my application and its working seamlessly .Smile | :)
thanx once more
GeneralMenu will not disappermember_bko22 May '05 - 23:43 
I had the problem that the popup menu did not disappear once I clicked outside of the menu.Frown | :(
So I searched for some informations and that´s what I found:
http://www.codeproject.com/shell/systemtray.asp[^]
 
To fix this bug just change the OnTrayRButtonDown handler to look like this:
void CTrayDialog::OnTrayRButtonDown(CPoint pt)
{
  CMenu *pcSubMenu = m_mnuTrayMenu.GetSubMenu(0);
  if (pcSubMenu) {
    pcSubMenu->SetDefaultItem(m_nDefaultMenuItem, TRUE);
    
    SetForegroundWindow();
    pcSubMenu->TrackPopupMenu(TPM_BOTTOMALIGN|TPM_LEFTBUTTON|TPM_RIGHTBUTTON, pt.x, pt.y, this);
    PostMessage(WM_NULL, 0, 0);
  }
}
... and hopefully everything is working fine.Smile | :)

 
cu _bko
JokeRe: Menu will not disappermemberHarry Lau6 Apr '06 - 4:33 
This works great. I also added this code for OnTrayLButtonDown as I have no special function for a left click. Poke tongue | ;-P
GeneralRe: Menu will not disappermemberfherlan2 Dec '06 - 5:42 
Superb!
GeneralThanks Daniel !memberganesh_nv@yahoo.com18 Apr '05 - 19:53 
Thanks Daniel for this Nice Article. You got my full Rating for this article.. Smile | :)
GeneralSome bugsmemberrrrado7 Mar '05 - 0:43 
It seems that when I've started to use this class, 2 bugs occured in my application:
1. the menu is shown by gray color when app starts (it does not look like disabled menu, text does not have disabled shadow effect), but when I move the window or force it to redraw the menu by other way it's drawn properly
(the bug fix posted below didn't help).
 
2. main dialog contains tab control which contains child dialog with edit control. When the cursor is placed in the text, I switch to another application and then back to my application, but edit box lose the focus and cursor position is not remebered.
How to solve this ?
 
thanks
 

rrrado
GeneralRe: Some bugsmemberrrrado7 Mar '05 - 2:26 
Sorry, I'm using this with custom caption button
 
http://www.codeproject.com/buttonctrl/CustomBitmapButtonDemo.asp[^]
 
the bug must be there
 

rrrado

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130516.1 | Last Updated 7 Nov 2000
Article Copyright 2000 by Daniel Zilcsak
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid