Animating System Tray Icons


Desktop-as-a-Service Designed for Any Cloud ? Nutanix Frame


This article explains how to animate an icon in the Shell tray and assign dynamically changing tooltips for each icon phase. So the end result will be that your icon can now visually indicate what your application is currently doing along with corresponding tooltip descriptions. User notifications like left click and right click on the icon are also handled. The Windows NT  resource usage indicator on the Shell Tray is a wonderful example of animating icons on the Shell Tray. Let's animate now !.

Step 1: (Setting up the data for the animation)

The first step involves setting up well organized arrays that kind of keep track of the icons lined up for animation along with their tooltip description strings. Also define a user defined notification that will let you know if the user clicked on the animating icon. Swing by at your resource editor and create all the icons that you need and give them the same ids specified in the array.


static int iconResourceArray[NUM_ICONS_IN_ANIMATION] =

static CString strToolTipArray[NUM_ICONS_IN_ANIMATION] = 
 CString("Resource Usage = 20%") ,
 CString("Resource Usage = 40%") ,
 CString("Resource Usage = 60%") ,
 CString("Resource Usage = 80%"),
 CString("Resource Usage = 100%") }; 


Step 2:(Adding an useful helper function)

Take a look at this useful helper function below that wraps up the Shell_NotifyIcon call. The first  parameter indicates to the helper whether you need to add,delete, or modify an icon in the Shell Tray by specifying NIM_ADD, NIM_DELETE, or NIM_MODIFY. The second parameter indicates the index of the icon in the array that you set up in Step 1. The third parameter indicates the tooltip string for the currently displayed icon.

void CShellAnimDlg::InstallAnimatedIcon(DWORD dwMsgType,UINT nIndexOfIcon, CString strToolTip)

	//Load the specified icon from the array
	HICON hIconAtIndex = AfxGetApp()->LoadIcon(iconResourceArray[nIndexOfIcon]);

	///Fill up the NOTIFYICONDATA Structure
	iconData.cbSize		= sizeof(NOTIFYICONDATA);
	iconData.hWnd		= GetSafeHwnd();  //window's handle
	iconData.uID			= 100 ;  //identifier
	iconData.uFlags		= NIF_MESSAGE|NIF_ICON|NIF_TIP; //flags
	iconData.uCallbackMessage	= MYMSG_NOTIFYICON; //notification handler
	iconData.hIcon		= hIconAtIndex;    //icon handle   
	//Fill up tool tip
	LPCTSTR lpszToolTip = strToolTip.GetBuffer(strToolTip.GetLength());
	//Tell the shell what we intend doing
	//Add,Delete,Modify ---> NIM_ADD,NIM_DELETE, NIM_MODIFY in dwMsgType
	Shell_NotifyIcon(dwMsgType, &iconData); 

	//Resources are precious !
	if (hIconAtIndex)


Step 3: (Animating the icon)

Whenever you need to start the animation, begin by adding an icon first on the tray by calling the helper function with NIM_ADD. Subsequently, cycle through the animation by calling NIM_MODIFY. The following code which is a dialog based application adds the first icon in OnInitDialog() and then sets up a timer that cycles through the animation.

BOOL CShellAnimDlg::OnInitDialog()
    ///usual initialization goes here   	
    int nIndexFirstIcon = 0;
    return TRUE; // return TRUE unless you set the focus to a control
void CShellAnimDlg::OnTimer(UINT nIDEvent) 
	// TODO: Add your message handler code here and/or call default
	static int nCounter = 0;
	m_nCounter = nCounter; //Store it here to keep track of the last displayed icon
	nCounter = nCounter%(NUM_ICONS_IN_ANIMATION);


Please Note: You may need to get the last icon off the tray when the application closes. So make sure you get the icon off the tray when your application closes by calling:



Step 4: (Handling notifications)

We now  need to keep track of  user actions on our icon.. Remember the user defined message id MYMSG_NOTIFYICON that we passed for callback notification to the NOTIFYICONDATA structure in the helper function. Well, the icon posts a message whenever the user performs an action on the icon. We are interested only on mouse clicks and so let's handle them. Firstly, go ahead and define a user defined message as shown in step 1. Once you're done with that , map the message handler to a function as shown below.

afx_msg void OnHandleIconNotify(UINT wParam, LONG lParam);                //function to handle notifications

ON_MESSAGE(MYMSG_NOTIFYICON,OnHandleIconNotify)      //message mapped to function

void CShellAnimDlg::OnHandleIconNotify(UINT wParam, LONG lParam)
    CString strTest;
    CString strCurrPosition(strToolTipArray[m_nCounter]);
    switch (lParam)
        case WM_LBUTTONDOWN:
        case WM_RBUTTONDOWN:
        case WM_LBUTTONDBLCLK:
            ///Do whatever you need to do when the click occured
            //Current icon animation position is at m_nCounter


You now have your animated icon cycling through it's phases on the Shell Tray with different tool tips depending on the icon position in the cycle order.

Last updated: 17 June 1998

This article was originally published on August 8th, 1998

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date