Click here to Skip to main content
11,412,516 members (70,032 online)
Click here to Skip to main content

Basic use of Shell_NotifyIcon in Win32

, 15 Aug 2003
Rate this:
Please Sign up or sign in to vote.
Starting your app minimized on the sytem tray.

Introduction

Recently I was browsing CodeProject, looking for a simple example of how to manage system tray icons. Ooops sorry, I shouldn't call them tray icons as MSDN documentation so carefully points out:

"The taskbar notification area is sometimes erroneously called the tray."

In spite of this, I will insist on calling a spade a shovel and refer to the "taskbar notification area" as the "tray" and "taskbar notification area icons" as "tray icons". Anyway back to the point, why another article about tray icons?

  • I've never written a Code Project article before and this seemed pretty easy.
  • This isn't another wrapper, but simple straight forward example of Shell_NotifyIcon with a minimum amount of code.
  • I wanted an example written in pure Win32 code.
  • I wanted to address some of the common problems and questions I've seen posted in other articles on the subject.

The basics

Adding, modifying, hiding and deleting tray icons is accomplished in two steps:

  1. Initialize a NOTIFYICONDATA structure
  2. Call Shell_NotifyIcon

Initialize a NOTIFYICONDATA structure

// zero the structure - note: Some Windows funtions
// require this but I can't be bothered to remember
// which ones do and which ones don't.


    NOTIFYICONDATA niData; 
    ZeroMemory(&niData,sizeof(NOTIFYICONDATA));


// get Shell32 version number and set the size of the
// structure note: the MSDN documentation about this is
// a little dubious(see bolow) and I'm not at all sure
// if the code bellow is correct


    ULONGLONG ullVersion =
        GetDllVersion(_T("Shell32.dll"));

    if(ullVersion >= MAKEDLLVERULL(6,0,0,0))
        niData.cbSize = sizeof(NOTIFYICONDATA);

    else if(ullVersion >= MAKEDLLVERULL(5,0,0,0))
        niData.cbSize = NOTIFYICONDATA_V2_SIZE;

    else niData.cbSize = NOTIFYICONDATA_V1_SIZE;


// the ID number can be any UINT you choose and will
// be used to identify your icon in later calls to
// Shell_NotifyIcon


    niData.uID = MY_TRAY_ICON_ID;


// state which structure members are valid
// here you can also choose the style of tooltip
// window if any - specifying a balloon window:
// NIF_INFO is a little more complicated 


    niData.uFlags = NIF_ICON|NIF_MESSAGE|NIF_TIP;


// load the icon note: you should destroy the icon
// after the call to Shell_NotifyIcon


    niData.hIcon =
        (HICON)LoadImage( hInstance,
            MAKEINTRESOURCE(IDI_MY_ICON),
            IMAGE_ICON,
            GetSystemMetrics(SM_CXSMICON),
            GetSystemMetrics(SM_CYSMICON),
            LR_DEFAULTCOLOR);


// set the window you want to recieve event messages


    niData.hWnd = hWnd;


// set the message to send
// note: the message value should be in the
// range of WM_APP through 0xBFFF


    niData.uCallbackMessage = MY_TRAY_ICON_MESSAGE;

Call Shell_NotifyIcon

// NIM_ADD adds a new tray icon
    Shell_NotifyIcon(NIM_ADD,&niData);

Stealth dialog

I've seen more than a few posts asking how to begin a dialog app minimized to the system tray, hence the name Stealth Dialog. This can be accomplished simply by first creating a modeless dialog:

    HWND hWnd = CreateDialog( hInstance,
        MAKEINTRESOURCE(MY_DIALOG),
        NULL,
        (DLGPROC)MyDlgProc );

Then use Shell_NotifyIcon as shown above to add your icon to the tray. Do not call ShowWindow.

Menus and messages

Messages from the tray will go to the window specified by the hWnd member of the NOTIFYICONDATA struct and the message ID is specified by the uCallbackMessage member (see above). The specific message is in the LPARAM.

INT_PTR CALLBACK MyDlgProc(HWND hWnd, UINT message,
    WPARAM wParam, LPARAM lParam)
{
    switch(message)
    {
    case MY_TRAY_ICON_MESSAGE:
        switch(lParam)
        {
        case WM_LBUTTONDBLCLK:
            ShowWindow(hWnd, SW_RESTORE);
            break;
        case WM_RBUTTONDOWN:
        case WM_CONTEXTMENU:
            ShowContextMenu(hWnd);
        }
        break;
    case...

If you implement a context menu, messages are received through WM_COMMAND and the menu item ID is contained in the low-order word of the WPARAM.

    case WM_COMMAND:
        switch (LOWORD(wParam))
        {
        case MY_MENU_MSG1:
            ...
            break;
        case MY_MENU_MSG2:
        ...

Important: If you implement a context menu, it's vital that you set your window to the foreground before calling TrackPopupMenu to ensure the menu closes properly.

void ShowContextMenu(HWND hWnd)
{
    ...

    HMENU hMenu;

// create or load a menu

    ...

    SetForegroundWindow(hWnd);
    TrackPopupMenu(hMenu, ...

Cleaning up

Sometime before your app closes you should remove your tray icon by calling Shell_NotifyIcon with the NIM_DELETE flag.

    case WM_DESTROY:
        Shell_NotifyIcon(NIM_DELETE,&niData);

Notes:

The MSDN documentation says about the cbSize member of the NOTIFYICONDATA structure:

"You can keep your application compatible with all Shell32.dll versions while still using the current header files by setting the size of the NOTIFYICONDATA structure appropriately. Before initializing the structure, use the DllGetVersion function to determine which Shell32.dll version is installed on the system. If it is version 5.0 or greater, initialize the cbSize member with:

nid.cbSize = sizeof(NOTIFYICONDATA);

Setting cbSize to this value enables all the version 5.0 and 6.0 enhancements. For earlier versions, the size of the pre-6.0 structure is given by the NOTIFYICONDATA_V2_SIZE constant and the pre-5.0 structure is given by the NOTIFYICONDATA_V1_SIZE constant. Initialize the cbSize member with:

nid.cbSize = NOTIFYICONDATA_V2_SIZE;

Using this value for cbSize enables your application to use NOTIFYICONDATA with earlier Shell32.dll versions, although without the version 6.0 enhancements:"

Now maybe it's my neighbors Turkish tobacco or maybe I'm just not catching on here, but there seems to be an overlapping conflict between "5.0 or greater" and "pre-6.0".

Anyway, if anybody can shed any light on this or anything else they care to shed light on, please shed.

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

Share

About the Author

Abraxas23

China China
No Biography provided

Comments and Discussions

 
GeneralRe: How to avoid multiple tray icons of the same app? Pin
"Fish" (David B. Trout) at 1-Oct-08 18:08
member"Fish" (David B. Trout)1-Oct-08 18:08 
GeneralHere's how to get the DLL Version Pin
Elchay at 3-Nov-05 7:15
memberElchay3-Nov-05 7:15 
GeneralGreat job! Pin
boolman at 19-Oct-05 8:38
memberboolman19-Oct-05 8:38 
GeneralShell_NotifyIcon sometimes fails at startup Pin
LukeV at 18-May-05 10:42
memberLukeV18-May-05 10:42 
GeneralRe: Shell_NotifyIcon sometimes fails at startup Pin
Abraxas23 at 19-May-05 5:58
memberAbraxas2319-May-05 5:58 
GeneralRe: Shell_NotifyIcon sometimes fails at startup Pin
rharting at 1-Aug-05 8:32
memberrharting1-Aug-05 8:32 
General[ELP] hide the icon of another process than the mine Pin
NewMAn291185645 at 12-May-05 21:24
sussNewMAn29118564512-May-05 21:24 
GeneralRe: [ELP] hide the icon of another process than the mine Pin
Abraxas23 at 19-May-05 6:19
memberAbraxas2319-May-05 6:19 
General[ELP] hide the icon of another process than the mine Pin
NewMAn2911856456465 at 12-May-05 21:23
sussNewMAn291185645646512-May-05 21:23 
GeneralGet existing icons Pin
Anonymous at 24-Feb-05 15:08
sussAnonymous24-Feb-05 15:08 
GeneralRe: Get existing icons Pin
Anonymous at 24-Feb-05 15:11
sussAnonymous24-Feb-05 15:11 
QuestionHow to keep icon active on WinXP? Pin
dlanders at 23-Dec-04 7:38
memberdlanders23-Dec-04 7:38 
GeneralGetDllVersion() Pin
Anonymous at 18-Dec-04 8:38
sussAnonymous18-Dec-04 8:38 
GeneralRe: GetDllVersion() Pin
te_mike at 26-Dec-04 16:40
memberte_mike26-Dec-04 16:40 
GeneralRe: GetDllVersion() Pin
Abraxas23 at 19-May-05 6:40
memberAbraxas2319-May-05 6:40 
GeneralGetDllVersion Pin
folarx at 26-Nov-04 9:32
memberfolarx26-Nov-04 9:32 
I was wondering how did You manage to make this code work without actually importing the DllGetVersion function.
GeneralDialog box and system tray Pin
calpol2004 at 14-Sep-04 9:48
membercalpol200414-Sep-04 9:48 
GeneralRe: Dialog box and system tray Pin
oshah at 15-Sep-04 7:53
sussoshah15-Sep-04 7:53 
QuestionHow to create MFC single dialog that initialy hiden? Pin
Wayut at 28-Jun-04 16:52
memberWayut28-Jun-04 16:52 
AnswerRe: How to create MFC single dialog that initialy hiden? Pin
Abraxas23 at 29-Aug-04 0:58
memberAbraxas2329-Aug-04 0:58 
QuestionWill this work with VC6 ? Pin
Paddy478 at 22-Jun-04 2:20
memberPaddy47822-Jun-04 2:20 
AnswerRe: Will this work with VC6 ? Pin
Abraxas23 at 29-Aug-04 1:02
memberAbraxas2329-Aug-04 1:02 
GeneralRe: Will this work with VC6 ? Pin
jdykshorn at 9-Nov-04 10:22
memberjdykshorn9-Nov-04 10:22 
Questiontray icon without window? Pin
Anonymous at 12-Jun-04 12:35
sussAnonymous12-Jun-04 12:35 
AnswerRe: tray icon without window? Pin
Abraxas23 at 29-Aug-04 0:49
memberAbraxas2329-Aug-04 0:49 
AnswerRe: tray icon without window? Pin
dbbtvlzfpz at 10-Oct-08 5:51
memberdbbtvlzfpz10-Oct-08 5:51 
GeneralCrash Recovery Pin
Anash P Oommen at 14-Mar-04 21:50
memberAnash P Oommen14-Mar-04 21:50 
GeneralRe: Crash Recovery Pin
Abraxas23 at 3-Apr-04 8:49
memberAbraxas233-Apr-04 8:49 
GeneralRe: Crash Recovery Pin
oshah at 13-Sep-04 8:08
sussoshah13-Sep-04 8:08 
GeneralRe: Crash Recovery Pin
Abraxas23 at 17-Sep-04 1:39
memberAbraxas2317-Sep-04 1:39 
GeneralUsing GetDllVersion in Visual Basic Pin
Anonymous at 4-Mar-04 20:58
sussAnonymous4-Mar-04 20:58 
GeneralRe: Using GetDllVersion in Visual Basic Pin
Abraxas23 at 3-Apr-04 8:06
memberAbraxas233-Apr-04 8:06 
Questionhow to get points for context menu Pin
Umesh D. at 23-Feb-04 4:41
memberUmesh D.23-Feb-04 4:41 
AnswerRe: how to get points for context menu Pin
Umesh D at 23-Feb-04 5:16
memberUmesh D23-Feb-04 5:16 
GeneralRe: how to get points for context menu Pin
Abraxas23 at 3-Apr-04 9:02
memberAbraxas233-Apr-04 9:02 
Questionhow to get points for context meanu Pin
Umesh D. at 23-Feb-04 4:41
memberUmesh D.23-Feb-04 4:41 
Generaladding a reduce button to the window Pin
sbouli at 30-Dec-03 0:28
membersbouli30-Dec-03 0:28 
GeneralRe: adding a reduce button to the window Pin
Abraxas23 at 3-Apr-04 9:30
memberAbraxas233-Apr-04 9:30 
Generalonly one start Pin
sbouli at 24-Dec-03 0:15
membersbouli24-Dec-03 0:15 
GeneralRe: only one start Pin
Anonymous at 27-Dec-03 6:20
sussAnonymous27-Dec-03 6:20 
Generalsetting the priority level Pin
sbouli at 19-Dec-03 4:46
membersbouli19-Dec-03 4:46 
GeneralRe: setting the priority level Pin
Abraxas23 at 21-Dec-03 9:20
memberAbraxas2321-Dec-03 9:20 
GeneralRe: setting the priority level Pin
sbouli at 24-Dec-03 0:05
membersbouli24-Dec-03 0:05 
General255 color System Tray Icon Pin
Mishra Vikas at 20-Nov-03 19:25
memberMishra Vikas20-Nov-03 19:25 
GeneralRe: 255 color System Tray Icon Pin
Abraxas23 at 21-Nov-03 6:59
memberAbraxas2321-Nov-03 6:59 
GeneralRe: 255 color System Tray Icon Pin
Mishra Vikas at 21-Nov-03 18:12
memberMishra Vikas21-Nov-03 18:12 
GeneralRe: 255 color System Tray Icon Pin
Abraxas23 at 23-Nov-03 3:28
memberAbraxas2323-Nov-03 3:28 
GeneralRe: 255 color System Tray Icon Pin
Mishra Vikas at 23-Nov-03 18:19
memberMishra Vikas23-Nov-03 18:19 
GeneralRe: 255 color System Tray Icon Pin
ARatcliffe at 6-May-04 22:30
memberARatcliffe6-May-04 22:30 
GeneralCant make it work Pin
idonda at 3-Nov-03 0:06
memberidonda3-Nov-03 0:06 

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

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.150427.1 | Last Updated 16 Aug 2003
Article Copyright 2003 by Abraxas23
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid