System Tray Icons



Click here for a larger image.



Click here for a larger image.

Environment: VC++ .NET, Windows 2000/XP, Windows Platform SDK

1. Introduction

Note: THIS CODE WILL WORK ONLY UNDER WINDOWS 2000/XP AND ABOVE

The System Tray is a familiar place for every reasonably experienced Windows OS user. Many applications use this area to place small icons here, which give information about their status. They give the user addition flexibility to directly interact with the application. Almost all applications provide a context menu over the system tray icons for interaction with the application. With the advent of Windows 2000/XP popup balloons can also be shown over the system tray icons, to notify the user of any relevant event. This article explains the process of creating and showing icons in the system tray for any application. This also caters to multiple icons to be shown for the same application. You can also show popup balloons over the specified icons.

2. Using the Code

  • Include the files SYSTRAYICON.H and SYSTRAYICON.CPP in your project.
  • Create an object (a class) from CSysTrayIcon. In case you wish to process mouse messages over the icons, derive a class from CSysTrayIcon and override any or all of the mouse messages mentioned in Section 2.2.
  • Create the object of the class CSysTrayIcon or a class derived from CSysTrayIcon(preferably in the MainFrame class).
  • Create and manipulate icons in the system tray using the functions given in Section 2.1.
  • Mouse messages are trapped, and overridable functions are provided for custom processing. See Section 2.2 for the list of overridable functions that are triggered by mouse messages.

2.1 Functions for Creating and Manipulation Icons In the System Tray

  • BOOL CreateIcon(HICON hIcon, UINT nIconID, PCSTR szTip)

    Input parameters:
    HICON hIcon ->
    Handle to an icon to be shown in the system tray.
    UINT nIconID ->
    A user-defined icon ID. It can be any unsigned integer.
    PCSTR szTip ->
    A tooltip that is shown when the user moves the mouse over the icon.

    Return Value:
    TRUE if an new tray icon with the ID nIconID could be created, else FALSE.

  • BOOL ShowIcon(UINT nIconID)

    Input parameters:
    UINT nIconID ->
    The icon with this ID is to be shown.

    Return value:
    TRUE if the icon with this ID exists and could be shown, else FALSE.

  • BOOL HideIcon(UINT nIconID)

    Hides the icon. It does not delete the icon from memory.

    Input parameters:
    UINT nIconID ->
    The icon with this ID is to be hidden. It is not deleted from memory.

    Return value:
    TRUE if the icon with this ID exists and could be hidden; else, FALSE.

  • BOOL DeleteIcon(UINT nIconID)
    Hides and deletes the icon from memory.

    Input parameters:
    UINT nIconID ->
    The icon with this ID is to be hidden and deleted from memory.

    Return value:
    TRUE if the icon with the ID exists and could be removed and deleted from the system tray and memory; else, FALSE.

  • BOOL ChangeIconTip(UINT nIconID, CString strTip)
    This changes the tooltip associated with the system tray icon.

    Input parameters:
    UINT nIconID ->
    The icon with this ID whose tooltip has to be changed.

    CString strTip ->
    The new tooltip to be associated with this icon.

    Return Values:
    TRUE if the icon with this ID exists and its tooltip cold be changed; else, FALSE.

  • BOOL ShowBalloon(UINT nIconID, PTSTR szBalloonTitle, PTSTR szBalloonMsg, DWORD dwIcon = NIIF_NONE, UINT nTimeOut = 10)
    Shows a popup balloon over the icon with the ID, nIconID.

    Input parameters:
    UINT nIconID ->
    The icon ID over which the balloon will be shown.

    PTSTR szBalloonTitle ->
    A string for the heading of the balloon message

    PTSTR szBalloonMsg ->
    A string for the balloon message.

    DWORD dwIcon ->
    An additional symbol in the left corner of the balloon that will emphasize the meaning of the balloon. There are four possibilities, NIIF_NONE, NIIF_ERROR, NIIF_INFO, and NIIF_WARNING. The default is NIIF_NONE. These are standard constants defined in Windows Platform SDK in shellapi.h.

    UINT nTimeOut ->
    Time in seconds for the balloon to be visible. In Windows 2000/XP, the minimum is 10 seconds. Even if you specify a time less than 10 seconds, it will be visible for a minimum of 10 seconds. This will probably change with the future versions of Windows.

    Return Value:
    TRUE if the balloon with given ID exists and the requested balloon could be shown; else, FALSE.

    2.2 Overridable Functions

    There are ten overridable virtual functions, all of which deal with mouse messages.

    virtual void OnLButtonDown(UINT nIconID, CPoint ptMouse)
    Gets called when the left mouse button has been pressed

    virtual void OnRButtonDown(UINT nIconID, CPoint ptMouse)
    Gets called when the right mouse button has been pressed

    virtual void OnMButtonDown(UINT nIconID, CPoint ptMouse)
    Gets called when the middle mouse button has been pressed

    virtual void OnLButtonUp(UINT nIconID, CPoint ptMouse)
    Gets called when the left mouse button is released

    virtual void OnRButtonUp(UINT nIconID, CPoint ptMouse)
    Gets called when the right mouse button is released

    virtual void OnMButtonUp(UINT nIconID, CPoint ptMouse)
    Gets called when the middle mouse button is released

    virtual void OnLButtonDblClk(UINT nIconID, CPoint ptMouse)
    Gets called when the left mouse button is double-clicked

    virtual void OnRButtonDblClk(UINT nIconID, CPoint ptMouse)
    Gets called when the right mouse button is double-clicked

    virtual void OnMButtonDblClk(UINT nIconID, CPoint ptMouse)
    Gets called when the middle mouse button is double-clicked

    virtual void OnMouseMove(UINT nIconID, CPoint ptMouse)
    Gets called when the mouse moves over the icon

    Input parameters for all overridables:
    UINT nIconID ->
    The icon ID over which the mouse message has been generated

    CPoint ptMouse -> The mouse position in screen co-ordinates

    2.3 Helper Function for Handling a Context Menu

  • BOOL OnContextMenu(CMenu* pContextMenu, CPoint ptMouse, CWnd* pWndMessageHandler)

    This function should be called by the programmer, as it will help him to do the requisite processing to show a context menu. This sets the window mentioned in the third parameter in the foreground, so that commands can be routed to it for processing.
    This function should generally be called in response to a right button down message, typically in the overridden method OnRButtonDown of the class derived from CSysTrayIcon.

    Input parameters:
    CMenu* pContextMenu ->
    Pointer to the menu to be shown, it is mostly on a right button press.

    CPoint ptMouse ->
    Mouse position in screen co-ordinates.

    CWnd* pWndMessageHandler ->
    A pointer to the window that will process the command handlers of the menu pContextMenu. This function on sets this window in the foreground so that it is capable of processing the command handlers. This function was written specifically for bringing the menu command handler receiver window to the foreground. In case you don't bring the window that will receive the menu commands in the foreground, the commands won't be routed properly. This window is generally the MainFrame window in a typical Windows application.

    3. The Implementation of the Class CSysTrayIcon

    The CSysTrayIcon class is a wrapper around the Windows API, Shell_NotifyIcon, and the Windows Platform SDK structure NOTIFYICONDATA, which is declared in the header file shellapi.h. Details about the above mentioned API and structure are well documented in the MSDN documentation.

    The class CSysTrayIcon contains a linked list of NOTIFYICONDATA structures (CSystrayIcon::NOTIFYICONDATAList), which maintains information about each icon in the system tray related to that application. Every application can have more than one icon in the system tray. There is no restriction on an application to have only one system tray icon. It is only restricted by the maximum value of an unsigned integer!

    Because this class CSysTrayIcon can't directly receive mouse messages, there has to be a way to route these messages to this class. This is done by creating a hidden window as a private member variable m_wndTrayMsgReceiver (of type CSysTrayWnd) in the class CSysTrayIcon, which is registered to receive the WM_SYSTRAYMSG. When a message WM_SYSTRAYMSG is received by the window object CSysTrayIcon::m_wndTrayMsgReceiver, it is mapped to CSysTrayWnd::OnSysTrayMsg(WPARAM wParam, LPARAM lParam). The lParam gives the type of mouse message and the wParam gives the icon ID on which the mouse message was generated. If you look at the implementation of CSysTrayIcon::CreateIcon(), the NOTIFYICONDATA structure members hWnd and uCallBackMessage are initialised as shown below. This is where the operating system comes to know which window is to be sent the WM_SYSTRAYMSG.

    pnidIconInfo->hWnd             = m_wndTrayMsgReceiver.
                                       GetSafeHwnd();
    pnidIconInfo->uCallbackMessage = WM_SYSTRAYMSG;
    



    Click here for a larger image.

    An object of the CSysTrayWnd window is created in the constructor of CSysTrayIcon itself. The CSystTrayWnd also has a pointer to the CSysTrayIcon class that helps in calling the virtual overridable functions as mentioned in Section 2.2.

    There are few other functions that are used internally in the class to get the icons from the linked list, if given the icon ID as the parameter. These are summarized below.

    GetNotifyIconDataFromID() ->
    Retrieves the NOTIFYCOINDATA structure from the linked list CSysTrayIcon::NOTIFYICONDATAList for the given icon ID.

    CheckIfIconIDExists() ->
    This is called to check whether the icon with the given ID already exists, when creating a new system tray icon.

    DeleteNotifyIconDataFromID() ->
    This is called from the DeleteIcon() function and the destructor of the CSystTrayIcon class for deleting the icon and proper cleanup. This function removes the icon by removing and deleting it from the linked list CSysTrayIcon::NOTIFYICONDATAList.

    4. Demo Project

    A class is derived from CSysTrayIcon with the name CMyAppTrayIcon. This class overrides only two virtual functions OnLButtonDownDBlClk() to show a message box and OnRButtonDown to show a context menu. These two functions get triggered for the Window messages of WM_LBUTTONDBLCLK and WM_RBUTTONDOWN respectively, by the routing through a CSysTrayWnd object.

    An object of CMyAppTrayIcon is kept as an member variable of the CMainFrame class. Four icons are created in CMainFrame::OnCreate(). The CMainFrame class handles all the command handlers for the context menu for the system tray icons.

    For context menu processing, the overridden OnRButtonDown method passes the main window's pointer to CSysTrayIcon::OnContextMenu as the third parameter. The main window has the command handlers for the required processing.

    void CMyAppTrayIcon::OnRButtonDown(UINT nIconID, CPoint ptMouse)
    {
        CMenu t_Menu;
                    
        t_Menu.LoadMenu(IDR_MAINFRAME);
        OnContextMenu(t_Menu.GetSubMenu(0), ptMouse,
                      ::AfxGetMainWnd());
    }
    

    Use the Icon menu to manipulate the system tray icons as shown the top figure.

    5. Downloads

    Download demo project - 76 Kb
    Download source - 6 Kb


    Comments

    • good example

      Posted by yuban on 09/24/2007 03:33pm

      I am trying to write a "toaster" style notification for notification area, and this was just about the only example code that I could find. Thanks.

      Reply
    • What about a atl-com server

      Posted by nicgendron on 08/01/2005 10:42am

      I made an atl-com server (service more exactly) and want to use the code. But, it seem my project doesn't like the inheritance from CWin. Any ideas ? Thanks

      Reply
    • How to handle the cases of Terminal Server

      Posted by Legacy on 10/07/2003 12:00am

      Originally posted by: Santhi

      Hello,
      My application runs in a Windows 2000 Terminal Server machine.
      On certain condition, I want to show an icon in the task bar (system tray) of all the remote desktops which are connected to this Terminal Server.

      How this can be handled.
      Is there any terminal Server API by which I can get a handle to the desktop of that user and call Shell_NotifyIcon with that handle or is there any other easy way out for this ?

      Reply
    • Balloon Message Written in VB

      Posted by Legacy on 04/08/2003 12:00am

      Originally posted by: Reybucs

      Do you have a program like this written in VB? Can you send me one?

      Thanks in advance.

      Reply
    • Where do I get the latest Platform SDK from?

      Posted by Legacy on 02/14/2003 12:00am

      Originally posted by: Sonyc

      Hello :)
      Newbie here...

      Great work you have done, but where can I get the
      latest Platform SDK for Visual C++ 6.0 from??????

      Could somebody mail me a URL?

      Thanks a lot
      Sonyc

      Reply
    • Where do I get the latest Platform SDK from?

      Posted by Legacy on 02/14/2003 12:00am

      Originally posted by: Sonyc

      Hello :)
      Newbie here...

      Great work you have done, but where can I get the
      latest Platform SDK for Visual C++ 6.0 from??????

      Could somebody mail me a URL? (sonyc@gmx.li)


      Thanks a lot
      Sonyc

      Reply
    Leave a Comment
    • Your email address will not be published. All fields are required.

    Top White Papers and Webcasts

    • On-demand Event Event Date: September 10, 2014 Modern mobile applications connect systems-of-engagement (mobile apps) with systems-of-record (traditional IT) to deliver new and innovative business value. But the lifecycle for development of mobile apps is also new and different. Emerging trends in mobile development call for faster delivery of incremental features, coupled with feedback from the users of the app "in the wild." This loop of continuous delivery and continuous feedback is how the best mobile …

    • Webinar on September 23, 2014, 2 p.m. ET / 11 a.m. PT Mobile commerce presents an array of opportunities for any business -- from connecting with your customers through mobile apps to enriching operations with mobile enterprise solutions. Join guest speaker, Michael Facemire, Forrester Research, Inc. Principal Analyst, as he discusses the new demands of mobile engagement and how application program interfaces (APIs) play a crucial role. Check out this upcoming webinar to learn about the new set of …

    Most Popular Programming Stories

    More for Developers

    Latest Developer Headlines

    RSS Feeds