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

System Tray Icons - Adding to your dialog application

By , 15 Apr 2002
 

Sample Image - systray.jpg

Introduction

I write applications for my site Settlers.net and also to make things easier for myself at home. In one of my apps, I have wanted to include a system tray icon. Only problem being, the sys tray icon samples people wrote were confusing and didn't do what I want. I'm young and not exactly pro at programming yet. This tray icon code is different simply because upon starting the program, the icon is placed into the system tray. When you click hide, the whole program is minimized to tray.

Right, now down the code.

Let's do this!

Okay, on the main dialog you must make a button for the hiding command. Name this button IDC_HIDEAPP.

Add files traynot.cpp and traynot.h to your project.

Paste this into yourDlg.cpp:

void CYourDlg::OnHide()
{
  // Load icon onto taskbar tray
  m_pTray = new CTrayNot (this,WM_TRAY_NOTIFY,
  NULL,theApp.m_pIconList);
  m_pTray->SetState(IDR_MAINFRAME);
  m_bHidden = TRUE;
}

void CYourDlg::OnUnHide()
{
  ShowWindow (SW_RESTORE) ;
  m_bHidden = FALSE ;
  /////////////////////////////////////
  // Remove icon from taskbar tray
  if (m_pTray)
  {
     delete m_pTray ;
     m_pTray = NULL ;
  }
}

LONG CYourDlg::OnTrayNotify ( WPARAM wParam, LPARAM lParam )
{
  switch (lParam)
  {
    case WM_RBUTTONDOWN:
    {
       CMenu menu ;
       // Load and Verify Menu
       VERIFY(menu.LoadMenu(IDR_TRAY));
       CMenu* pPopup = menu.GetSubMenu (0) ;
       ASSERT(pPopup != NULL);

       // Get the cursor position
       POINT pt ;
       GetCursorPos (&pt) ;

       // Fix Microsofts' BUG!!!!
       SetForegroundWindow();

       ///////////////////////////////////
       // Display The Menu
       pPopup->TrackPopupMenu(TPM_LEFTALIGN |
       TPM_RIGHTBUTTON,pt.x, pt.y, AfxGetMainWnd());
       break ;
    }
    case WM_LBUTTONDBLCLK:
       //////////////////////////////////
       // Unhide our Window
       if (m_bHidden)
          ShowWindow (SW_RESTORE);
       //OnUnHide() ;
       break ;
  }
  return (0) ;
}

void CYourDlg::OnDestroy() 
{
  CDialog::OnDestroy();

  // Remove Icon from Tray
  if (m_pTray)
  {
    delete m_pTray ;
    m_pTray = NULL ;
  } 
}

void CYourDlg::OnTrayRestore() 
{
  // UnHide Application
  if (m_bHidden)
    ShowWindow (SW_RESTORE) ;
  m_bHidden = FALSE ;
}

void CYourDlg::OnHideapp() 
{
  //This will be the onclick for the hide button
  //in order to call that the app is minimised.
  theApp.HideApplication();
}

Add these to yourDlgs message map:

ON_MESSAGE(WM_TRAY_NOTIFY, OnTrayNotify)
ON_COMMAND(ID_TRAY_RESTORE, OnTrayRestore)
ON_BN_CLICKED(IDC_HIDEAPP, OnHideapp)

Add #include "TrayNot.h" to yourDlg.h. Add:

CTrayNot* m_pTray;
BOOL m_bHidden;

to your public call in yourDlg.h before yourDlgs standard constructor.

Add the following to your dialog's afx message maps.

afx_msg LONG OnTrayNotify ( WPARAM wParam, LPARAM lParam ) ;
afx_msg void OnTrayRestore();
afx_msg void OnHideapp();
afx_msg void OnHide();
afx_msg void OnUnHide();
afx_msg void OnDestroy();

In yourapp.cpp (Not yourdlg.cpp) add this just after #endif:

// Load Icons for Tray 
m_pIconList[0] = LoadIcon (MAKEINTRESOURCE(IDR_MAINFRAME));
m_pIconList[1] = LoadIcon (MAKEINTRESOURCE(IDR_MAINFRAME));
m_pIconList[2] = LoadIcon (MAKEINTRESOURCE(IDR_MAINFRAME));

In the yourapp.h (not yourdlg.h) add this to the public callback:

HICON m_pIconList[3];

After the last } down the bottom of this file, add this:

extern CYourApp theApp;

Open stdafx.h and add #define WM_TRAY_NOTIFY WM_APP+1000 after AfxCmn.h's include.

Now just add a menu using the resource add and name it IDR_TRAY. Add a restore command (ID_TRAY_RESTORE) and then you're done....

You may find that when you quit, the icon doesn't disappear. Use the destroy function and add delete m_pTray ; to it... Or you could just download my demo project and rip all the code from that?

Anyways, I hope this helped some of you. Vote for this, so I get a T-Shirt haha!

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Ashman
Web Developer
Australia Australia
Member
Name: Ash Rowe
From: Canberra, Australia
Qualifications: Diploma in Game Programming
Age: 19 (Getting old and feeling it)
 
Tutorials I have written in the past, I have done so in a fashion that would enable even the newest of programmers to get a grasp on what is actually happening with the code I submit. I am looking at writing even more in the near future to further assist others as well as gain a better understanding myself of the code I end up with.

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   
GeneralnicememberDonsw28 Jun '09 - 14:37 
Noce but you should now update this for c#
 
cheers,
Donsw
My Recent Article : Backup of Data files - Full and Incremental

GeneralCorrection to make the icons delete correctly from the system tray.membershazzababs19 Dec '08 - 0:53 
The current code does not delete the icon from the system tray unless you move the mouse over it.
To fix this problem, you simply need to add a default block to the OnTrayNotify function.
 
LONG MyDialog::OnTrayNotify ( WPARAM wParam, LPARAM lParam )
{
  switch (lParam)
  {
    case MyMessageID:
    {
       // Do some processing
       break ;
    }
    // Add in a default so that other messages can be processed by windows
    default:
        {
            DefWindowProc(WM_TRAY_NOTIFY, wParam, lParam);
        }
        break;
  }
  return (0) ;
}
 
By the way. Thanks for the great class, it saved me much pain.
GeneralIcons in System Tray not loaded when my application is run as servicememberJLEExtdrs16 Oct '08 - 23:25 
Hi Ash,
This is a great code that is very easy to use. However, when I run my application as service, my icon is not loaded although the application is running. I have done some searching on the web and one of the reason given is because my application is now service, it will load my application before the system tray is available. Therefore, it failed to load the icon.
 
I am wondering if you are able to monitor if the icon is successfully loaded onto the system tray? I tried using m_pTray, but that does not help. If you are able to monitor if the icon is successfully loaded or not, then I will be able to write a routine to re-load the icon until it is successfully loaded onto the system tray.
 
Please help.
GeneralSimple and Good onememberYogesh Dhongade22 Aug '07 - 4:32 
I really like this app. I had gone through many other tray icon apps, but found this one very small and good one.
 
Very simply we can add tray functionality to our existing application.
 
Thanks
Smile | :)
 
Yogesh V Dhongade
QuestionPopup menu by Right-click overlaps with Taskbar menusmemberklee77721 Nov '05 - 4:35 
Hi I've been looking for the small nuisance that my application currently has, so I posted a help to MSDN newsgroup but no one answered so far. After I saw your post, I was hoping that I could use yours, but when I tested, yours also behaved the same, i.e. when I right-click on the icon, not only your "Restore" popup menus but also the taskbar popup menu, such as, "Toolbars", "Adjust Date/Time", etc. are displayed, so "Restore" menu is displayed behind the taskbar menus and eventually it is hidden.
If I right-click one more time, then only "Restore" menu is displayed. This happens alternatively. In other words, if I click again, then both menus are displayed.
I'd REALLY appreciate it if anyone can show me how to resolve this.
 
Here is my post to MSDN:
++++++++++++++++++++++++++++++++++++++++++++
I wrote an MFC program whose icon, tooltip and menus are available in systray.
When I right-click on the icon, not only my popup menus but also the taskbar popup menu, such as, "Toolbars", "Adjust Date/Time", etc. are displayed.
If I right-click one more time, then only my menus are displayed. This happens alternatively. In other words, if I click again, then both menus are displayed.
I followed the exact steps that were posted on MSDN, such as,
afx_msg LONG CAutoUpdatesDlg::OnSysTrayIconClick( WPARAM wParam, LPARAM lParam )
{
switch (lParam){
case WM_LBUTTONDOWN:
OnSysTrayInstallupdates();
break;
case WM_RBUTTONDOWN:
ShowTrayPopupMenu();
break ;
}
// PostMessage( WM_NULL, 0, 0 );
return 0;
}
 
void CAutoUpdatesDlg::ShowTrayPopupMenu()
{
CMenu mnTrayPopup;
mnTrayPopup.LoadMenu(IDR_TRAY_POPUP);
 
POINT CurPos;
GetCursorPos (&CurPos);
CMenu *mnItem1 = mnTrayPopup.GetSubMenu(0);
SetForegroundWindow();
mnItem1->TrackPopupMenu( TPM_RIGHTBUTTON | TPM_RIGHTALIGN,
CurPos.x, CurPos.y, this );
PostMessage( WM_NULL, 0, 0 );
}
 
Is this a VC7 bug? Or am I missing anything?
 
TIA.
AnswerRe: Popup menu by Right-click overlaps with Taskbar menusmemberklee77721 Nov '05 - 5:07 
I owe you an apology. For some reason, that behavior occurs only my development machine. When I tested yours and my app on the different XP, the popup menus were displayed correctly without any problem that I described earlier.
So now I am wondering what caused it on my machine.
 
Thanks.
AnswerSame problem herememberBruno Scopinho3 Nov '06 - 2:18 
I'm having the same problem here.
AnswerRe: Popup menu by Right-click overlaps with Taskbar menusmemberChrisHarlow19 Dec '06 - 1:34 
I managed to avoid this problem by handling the WM_RBUTTONUP message instead of the WM_RBUTTONDOWN
GeneralGREAT code - two minor improvementsmemberDouglas R. Keesler13 May '05 - 15:19 

1) There is erroneous behavior in the code in that if you right-click on the tray icon then click on another application window (making it active), then left-mouse click or right-click and RESTORE... it will restore the window, but it will be behind the previously active window, thus not visible.

To correct this behavior modify the OnTrayRestore() function as follows:

  // UnHide Application
  if (m_bHidden)
  {
    ShowWindow (SW_RESTORE) ;
 
    CRect rectWindow;
    GetWindowRect(&rectWindow);
    SetWindowPos(&wndTopMost, rectWindow.left, rectWindow.top,
      rectWindow.Width(), rectWindow.Height(), SWP_SHOWWINDOW); 
 
    m_bHidden = FALSE ;
  }

This will always restore your window to the top of the z-order (other topmost windows excepted of course).

2) If you're running a true tray app, it's probably not a good idea for users to be able to terminate an application with the ESC key, or the close button on the window. Valuable data may be accidentally lost in this way, not to mention it defeats the purpose of running it in the tray.

To correct this, I added an EXIT item on the popup menu, giving the handling function this code:

m_ExitCode=1; //don't forget to declare this in your header file
exit(1);
I then simply overrode the OnClose() function, where I deleted the call to base class and inserted the following code:
	if(m_ExitCode != 1)
		OnHide();

This way the application can only be terminated from the tray menu. Much tidier I think.

GREAT CODE. Thanks for sharing. I will definitely use it. I hope these suggestions were helpful.


 

In business, if two people always agree, one of them is unnecessary.

 


Generaltwo problems...susssmarty907116 Feb '05 - 20:51 
Hi ashman,
 
First like to say it was really a nice piece of code.
 
Two problems observed....
 
(1) if you kill the process of trayicon the icon does not get removed from system tray till you bring mouse over it.. can by some means... taskbar icons can be refreshed.
 
(2) On win 98/me double click activity doesnot work.. perhaps wm_lbtndblclk have some limitation.. how to overcome..
 
bye
 
smarty

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

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130523.1 | Last Updated 16 Apr 2002
Article Copyright 2001 by Ashman
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid