Display a System Tray Icon in VC++

shabbir's Avatar author of Display a System Tray Icon in VC++
This is an article on Display a System Tray Icon in VC++ in MFC.
Create a Dialog based application and add a menu.

First you need to declare some variables in the the header file of your Dialog.
Code: CPP
#define MYWM_NOTIFYICON (WM_USER+1)
  //User defined messages.
 
  CMenu m_TrayMenu;
  //Displaying menu when right clicked on the system tray. Should be inside the class definition
 
  NOTIFYICONDATA tnd;
  //Icon Data
 
  afx_msg LRESULT onTrayNotify(WPARAM, LPARAM);
  //Function to handle the user messages
 
Now put the following code in the OnInitDialog function
Code: CPP
CString sTip(_T("Hello System Tray"));
 
  tnd.cbSize = sizeof(NOTIFYICONDATA);
  tnd.hWnd = this->GetSafeHwnd();;
  tnd.uID = IDR_MAINFRAME;
  //ICON RESOURCE ID
  tnd.uFlags = NIF_MESSAGE|NIF_ICON;
  tnd.uCallbackMessage = MYWM_NOTIFYICON;
  tnd.uFlags = NIF_MESSAGE|NIF_ICON|NIF_TIP;
  tnd.hIcon = LoadIcon(AfxGetInstanceHandle(), MAKEINTRESOURCE (IDR_MAINFRAME));
  //ICON RESOURCE ID
  lstrcpyn(tnd.szTip, (LPCTSTR)sTip, sizeof(tnd.szTip));
 
  DWORD dwMessage = NIM_ADD;
  Shell_NotifyIcon(dwMessage, &tnd);   
 
  m_TrayMenu.LoadMenu(IDR_MENU);
  //MENU RESOURCE ID.
 
Add user-defined message handler
Code: CPP
ON_MESSAGE(MYWM_NOTIFYICON,onTrayNotify)
Now define the body of onTrayNotify as follows
Code: CPP
LRESULT CWallpaperDlg::onTrayNotify(WPARAM wParam,LPARAM lParam)
  {
    UINT uMsg = (UINT) lParam;
    switch (uMsg )
    {
    case WM_LBUTTONDBLCLK:
    this->ShowWindow(SW_SHOW);
    break;
    case WM_RBUTTONUP:
    CPoint pt;   
    GetCursorPos(&pt);
    m_TrayMenu.GetSubMenu(0)->TrackPopupMenu(TPM_RIGHTALIGN|TPM_LEFTBUTTON|TPM_RIGHTBUTTON,pt.x,pt.y,this);
    break;
    }
    return TRUE;
  }
Now if you want to add the functionality that whenever someone hits the cross it should be minimized to the system tray then add the WM_CLOSE event handler and remove the call to the CDialog::OnClose(); and add the following code.
Code: CPP
ShowWindow(SW_HIDE);
Now in the WM_DESTROY message of the dialog add the following lines to delete the icon from the system tray and clean up the tray.
Code: CPP
Shell_NotifyIcon(NIM_DELETE,&tnd);
The sample application has been done in VC++ 7.1 compiler and if you wish to transfer that and view them in older version 7.0 then you need to do the following
Quote:
1. In SLN files, the 8.0 must be replaced with 7.0.
2. In vcproj files (and only vcproj), the 7.10 part must be replaced by 7.0.
Attached Files
File Type: zip SysTray.zip (63.7 KB, 4086 views)
AhmedHan's Avatar, Join Date: Oct 2005
Go4Expert Member
One more thing...

Don't forget to define
#define _WIN32_WINNT 0x0501
before including "windows.h" file.
sanjoy.saha@hcl.in's Avatar, Join Date: Feb 2007
Newbie Member
Quote:
Originally Posted by AhmedHan
One more thing...

Don't forget to define
#define _WIN32_WINNT 0x0501
before including "windows.h" file.
can u tell me why is this done as i am new to VC++
AhmedHan's Avatar, Join Date: Oct 2005
Go4Expert Member
Quote:
Originally Posted by sanjoy.saha@hcl.in
can u tell me why is this done as i am new to VC++
Because some of the features of API functions and structures are defined for specific Windows versions or highers.

For example :
Code:
	//shellapi.h
    	typedef struct _NOTIFYICONDATAA {
    	DWORD cbSize;
    	HWND hWnd;
    	UINT uID;
    	UINT uFlags;
    	UINT uCallbackMessage;
    	HICON hIcon;
    #if _WIN32_IE >= 0x0500
    	CHAR szTip[128];
    	DWORD dwState;
    	DWORD dwStateMask;
    	CHAR szInfo[256];
    	_ANONYMOUS_UNION union {
    		UINT uTimeout;
    		UINT uVersion;
    	} DUMMYUNIONNAME;
    	CHAR szInfoTitle[64];
    	DWORD dwInfoFlags;
    #else
    	CHAR szTip[64];
    #endif
    #if _WIN32_IE >= 0x600
    	GUID guidItem;
    #endif
    } NOTIFYICONDATAA,*PNOTIFYICONDATAA;
As you see, as the constant _WIN32_IE has higher values, higher features are enabled.
[img]file:///C:/Temp/moz-screenshot-13.jpg[/img] [img]file:///C:/Temp/moz-screenshot-14.jpg[/img] [img]file:///C:/Temp/moz-screenshot-15.jpg[/img]

From MSDN :
Code:
Windows Server 2003 family            _WIN32_WINNT>=0x0502
  Windows XP                            _WIN32_WINNT>=0x0501
  Windows 2000                        _WIN32_WINNT>=0x0500
  Windows NT 4.0                        _WIN32_WINNT>=0x0400
  Windows Me                            _WIN32_WINDOWS=0x0490
  Windows 98                            _WIN32_WINDOWS>=0x0410
  Internet Explorer 6.0                _WIN32_IE>=0x0600
  Internet Explorer 5.01, 5.5            _WIN32_IE>=0x0501
  Internet Explorer 5.0, 5.0a, 5.0b    _WIN32_IE>=0x0500
  Internet Explorer 4.01                _WIN32_IE>=0x0401
  Internet Explorer 4.0                _WIN32_IE>=0x0400
  Internet Explorer 3.0, 3.01, 3.02    _WIN32_IE>=0x0300
Gopinath's Avatar, Join Date: Jun 2006
Newbie Member
Hi,

i did this application in VC++6.0, but i want to display the balloon tool tips for my system tray icon, i know how to do this. when i'm working in version 6.0 its giving errors as

error C2039: 'uTimeout' : is not a member of '_NOTIFYICONDATAA'
error C2039: 'dwInfoFlags' : is not a member of '_NOTIFYICONDATAA'
erro C2039: 'szInfo' : is not a member of '_NOTIFYICONDATAA'
.....
....


but when i did the another application application for system tray icon in VC++.Net then it runs perfectly and the system tray icons shows the balloon tips.

i know its due to the shellapi.h version with respective to the os.
now my question is how can i made VC++6.0 use the latest version of shellapi.h and able to display the balloon tool tips in my application.

please help me to solve this.
Thanks in advance.

-Gopinath
shabbir's Avatar, Join Date: Jul 2004
Go4Expert Founder
Change the header file path in the project settings.
2MuchRiceMakesMeSick's Avatar, Join Date: Aug 2007
Newbie Member
Can someone walk me though the part Add user-defined message handler
I am still learning VC and im familiar with the MFC ClassWizard but where do I go from there?
2MuchRiceMakesMeSick's Avatar, Join Date: Aug 2007
Newbie Member
im using VC++ 6.0 also
shabbir's Avatar, Join Date: Jul 2004
Go4Expert Founder
Quote:
Originally Posted by 2MuchRiceMakesMeSick
Can someone walk me though the part Add user-defined message handler
I am still learning VC and im familiar with the MFC ClassWizard but where do I go from there?
You need to add the code in the Message Map. In Dialog based application you will find that in the Dialog cpp file. Find the MESSAGE_MAP there.
2MuchRiceMakesMeSick's Avatar, Join Date: Aug 2007
Newbie Member
Thanks. Now its saying that it cant find m_TrayMenu
I havent defined a Member Variable called m_TrayMenu is obviously why
But I cant because there is no Menu Control IDs in the wizard.
I did add a IDR_MENU1 by right clicking NEW MENU. Why is it not showing up under the MFC Class Wizard? Or am I doing it wrong?

Thanks for the help...