Click here to Skip to main content
15,886,724 members
Articles / Programming Languages / C++

Animated System Tray Icon, Taskbar Icon, and Titlebar Icon

Rate me:
Please Sign up or sign in to vote.
4.65/5 (25 votes)
14 Jul 20062 min read 91.8K   4.2K   59  
An article on animating system tray, taskbar and title bar icons.
// TrayIcon.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#include "resource.h"

#define		NUM_ICON_FOR_ANIMATION	8
#define		MAX_LOADSTRING			100
#define		MYMSG_NOTIFYICON		(WM_APP + 100)

// Global Variables:
HINSTANCE		hInst;								// current instance
TCHAR			szTitle[MAX_LOADSTRING];			// The title bar text
TCHAR			szWindowClass[MAX_LOADSTRING];		// The title bar text
HWND			hWindowHandle;

// Global Vraibles
// Keep track of the last displayed icon
int				nCounter; 
// List of Icon that is created and to be animated
static int		IconResourceArray[NUM_ICON_FOR_ANIMATION] = {IDI_ICON8, IDI_ICON7, IDI_ICON6, IDI_ICON5, IDI_ICON4, IDI_ICON3, IDI_ICON2, IDI_ICON1};
// Current icon displayed index values.
static			m_nCounter = 0;


// Foward declarations of functions included in this code module:
ATOM				MyRegisterClass(HINSTANCE hInstance);
BOOL				InitInstance(HINSTANCE, int);
LRESULT CALLBACK	WndProc(HWND, UINT, WPARAM, LPARAM);


VOID AnimateIcon(HINSTANCE hInstance, HWND hWnd, DWORD dwMsgType,UINT nIndexOfIcon);
VOID TimerAnimationIcon(HINSTANCE hInst, HWND hWnd);
LONG OnTrayNotification(HINSTANCE hInstance, HWND hWnd, WPARAM wParam, LPARAM lParam);


int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
 	// TODO: Place code here.
	MSG msg;
	HACCEL hAccelTable;

	// Initialize global strings
	LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
	LoadString(hInstance, IDC_TRAYICON, szWindowClass, MAX_LOADSTRING);
	MyRegisterClass(hInstance);

	// Perform application initialization:
	if (!InitInstance (hInstance, nCmdShow)) 
	{
		return FALSE;
	}

	hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_TRAYICON);

	// Main message loop:
	while (GetMessage(&msg, NULL, 0, 0)) 
	{
		if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) 
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}

	return msg.wParam;
}



//
//  FUNCTION: MyRegisterClass()
//
//  PURPOSE: Registers the window class.
//
//  COMMENTS:
//
//    This function and its usage is only necessary if you want this code
//    to be compatible with Win32 systems prior to the 'RegisterClassEx'
//    function that was added to Windows 95. It is important to call this function
//    so that the application will get 'well formed' small icons associated
//    with it.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
	WNDCLASSEX wcex;

	wcex.cbSize = sizeof(WNDCLASSEX); 

	wcex.style			= CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc	= (WNDPROC)WndProc;
	wcex.cbClsExtra		= 0;
	wcex.cbWndExtra		= 0;
	wcex.hInstance		= hInstance;
	wcex.hIcon			= LoadIcon(hInstance, (LPCTSTR)IDI_TRAYICON);
	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
	wcex.lpszMenuName	= (LPCSTR)IDC_TRAYICON;
	wcex.lpszClassName	= szWindowClass;
	wcex.hIconSm		= LoadIcon(wcex.hInstance, (LPCTSTR)IDI_TRAYICON);

	return RegisterClassEx(&wcex);
}

//
//   FUNCTION: InitInstance(HANDLE, int)
//
//   PURPOSE: Saves instance handle and creates main window
//
//   COMMENTS:
//
//        In this function, we save the instance handle in a global variable and
//        create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   HWND hWnd;

   hInst = hInstance; // Store instance handle in our global variable

   hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

   if (!hWnd)
   {
      return FALSE;
   }

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   // Add icon on system tray during initialzation
   AnimateIcon(hInstance, hWnd, NIM_ADD, 0);
   // Set a timer functionality to animate the icon in a certain interval
   SetTimer(hWnd, 1, 500, NULL);
	  
   return TRUE;
}

//
//  FUNCTION: WndProc(HWND, unsigned, WORD, LONG)
//
//  PURPOSE:  Processes messages for the main window.
//
//  WM_COMMAND	- process the application menu
//  WM_PAINT	- Paint the main window
//  WM_DESTROY	- post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	int wmId, wmEvent;
	PAINTSTRUCT ps;
	HDC hdc;
	TCHAR szHello[MAX_LOADSTRING];
	LoadString(hInst, IDS_HELLO, szHello, MAX_LOADSTRING);

	switch (message) 
	{
		case WM_COMMAND:
			wmId    = LOWORD(wParam); 
			wmEvent = HIWORD(wParam); 
			// Parse the menu selections:
			switch (wmId)
			{
				case IDM_EXIT:
				case ID_FILE_KILLPROCESS:
				   DestroyWindow(hWnd);
				   break;
				case ID_TRAYICON_MINIMISE:
					ShowWindow(hWnd, SW_MINIMIZE);
					break;
				case ID_TRAYICON_HIDEWINDOW:
					ShowWindow(hWnd, SW_HIDE);
					break;
				case ID_TRAYICON_MAXIMIZEWINDOW:
					ShowWindow(hWnd, SW_MAXIMIZE);
					break;
				default:
				   return DefWindowProc(hWnd, message, wParam, lParam);
			}
			break;
		case WM_PAINT:
			hdc = BeginPaint(hWnd, &ps);
			// TODO: Add any drawing code here...
			RECT rt;
			GetClientRect(hWnd, &rt);
			DrawText(hdc, szHello, strlen(szHello), &rt, DT_CENTER);
			EndPaint(hWnd, &ps);
			break;
		case WM_CLOSE:
		case WM_DESTROY:
		case WM_QUIT:
			KillTimer(hWnd, 1);
			AnimateIcon(hInst, hWnd, NIM_DELETE, m_nCounter);
			PostQuitMessage(0);
			break;
		case WM_TIMER:
			TimerAnimationIcon(hInst, hWnd);
		case MYMSG_NOTIFYICON:
			// System Tray Icon notification will be executed..
			OnTrayNotification(hInst, hWnd, wParam, lParam);
			break;
		default:
			return DefWindowProc(hWnd, message, wParam, lParam);
   }
   return 0;
}

/*	Function Name   : TimerAnimationIcon
	Description		: Function which will keep track of the current displayed icons, based on that
					  this will select the next icon to be displayed by sending a modify message type
					  to the system tray icon.
	Function Called	: AnimateIcon
	Global Variable	: m_nCounter - Keep track of the icon which is currently dispalyed
					  nCounter   - Incremented one by one to select the next icon from the icon list.
*/
VOID TimerAnimationIcon(HINSTANCE hInst, HWND hWnd)
{
	AnimateIcon(hInst, hWnd, NIM_MODIFY, nCounter);
	m_nCounter = nCounter; //Store it here to keep track of the last displayed icon
	nCounter++;
	nCounter = nCounter%(NUM_ICON_FOR_ANIMATION);
}

/*	Function Name   : AnimateIcon
	Description		: Function which will act based on the message type that is received as parameter
					  like ADD, MODIFY, DELETE icon in the system tray. Also send a message to display
					  the icon in title bar as well as in the task bar application.
	Function Called	: Shell_NotifyIcon	-	API which will Add, Modify, Delete icon in tray.
					  SendMessage - Send a message to windows
	Variable		: NOTIFYICONDATA - Structure which will have the details of the tray icons
*/
void AnimateIcon(HINSTANCE hInstance, HWND hWnd, DWORD dwMsgType,UINT nIndexOfIcon)
{
	HICON hIconAtIndex = LoadIcon(hInstance, (LPCTSTR) MAKEINTRESOURCE(IconResourceArray[nIndexOfIcon]));

	NOTIFYICONDATA IconData;

	IconData.cbSize = sizeof(NOTIFYICONDATA);
	IconData.hIcon  = hIconAtIndex;
	IconData.hWnd   = hWnd;
	lstrcpyn(IconData.szTip,"Animated System Tray Icons", (int) strlen("Animated System Tray Icons")+1);
	IconData.uCallbackMessage = MYMSG_NOTIFYICON;
	IconData.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
	
	Shell_NotifyIcon(dwMsgType, &IconData);
	SendMessage(hWnd, WM_SETICON, NULL, (long) hIconAtIndex);

	if(hIconAtIndex)
		DestroyIcon(hIconAtIndex);
}

/*	Function Name   : OnTrayNotification
	Description		: CALLBACK routine which will be get executed when a notification is identified on the
					  system tray. 
	Function Called	: LoadMenu	-	Load the menu into the application
*/
LONG OnTrayNotification(HINSTANCE hInstance, HWND hWnd, WPARAM wParam, LPARAM lParam)
{
	HMENU hMenu;

	switch(lParam)
	{
		case WM_RBUTTONDOWN:
		{
			/** Load and verify the menu**/
			if(hMenu = LoadMenu(hInstance, (LPCTSTR) MAKEINTRESOURCE(IDC_TRAYICON)))
			{
				hMenu = GetSubMenu(hMenu, 0);
				if(hMenu != NULL)
				{
					POINT pt;
					GetCursorPos(&pt);
					SetForegroundWindow(hWnd);
					TrackPopupMenu(hMenu, TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, 0, hWnd, NULL);
				}
			}
			break ;
		}
	}
	return 0;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

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


Written By
Architect Luxoft
Germany Germany
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions