Click here to Skip to main content
15,886,362 members
Articles / Desktop Programming / MFC

Create Icons at Runtime and Show Them in the System Tray

Rate me:
Please Sign up or sign in to vote.
4.66/5 (18 votes)
10 Jun 2008CPOL4 min read 75.1K   2.2K   78  
Create dynamic icons at runtime and show them in the system tray
// DynIconDlg.cpp : implementation file
//

#include "stdafx.h"
#include "DynIcon.h"
#include "DynIconDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// CAboutDlg dialog used for App About

class CAboutDlg : public CDialog
{
public:
	CAboutDlg();

// Dialog Data
	enum { IDD = IDD_ABOUTBOX };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support

// Implementation
protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
END_MESSAGE_MAP()


// CDynIconDlg dialog




CDynIconDlg::CDynIconDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CDynIconDlg::IDD, pParent)
	,m_nValue1(-10)
	,m_nValue2(-15)
	,m_bActiv(FALSE)
	,m_bFirstDefaultIcon(TRUE)
	,m_bFirstIcon1(TRUE)
	,m_bFirstIcon2(TRUE)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CDynIconDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CDynIconDlg, CDialog)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_WM_TIMER()
	//}}AFX_MSG_MAP
	ON_BN_CLICKED(IDOK,      &CDynIconDlg::OnBnClickedOk)
	ON_BN_CLICKED(IDC_START, &CDynIconDlg::OnBnClickedStart)
	ON_BN_CLICKED(IDC_STOP,  &CDynIconDlg::OnBnClickedStop)
	ON_MESSAGE(WM_TRAY, OnTray)//own message
	ON_WM_SYSCOMMAND()
END_MESSAGE_MAP()


// CDynIconDlg message handlers

BOOL CDynIconDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// Add "About..." menu item to system menu.

	// IDM_ABOUTBOX must be in the system command range.
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		CString strAboutMenu;
		strAboutMenu.LoadString(IDS_ABOUTBOX);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon

	// TODO: Add extra initialization here
	


	//set the defaulticon in the tray
	SetDefaultIconInTray();

	CString strValue;

	strValue.Format(_T("%3d"),m_nValue1);
	SetDlgItemTextW(IDC_VALUE1, strValue);
	
	strValue.Format(_T("%3d"),m_nValue2);
	SetDlgItemTextW(IDC_VALUE2, strValue);
 
	((CButton*)GetDlgItem(IDC_START))->EnableWindow(TRUE);
	((CButton*)GetDlgItem(IDC_STOP))->EnableWindow(FALSE);
	((CButton*)GetDlgItem(IDOK))->EnableWindow(TRUE);





	return TRUE;  // return TRUE  unless you set the focus to a control
}

void CDynIconDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		switch(nID){

			
			case SC_MINIMIZE:
				//if the dialog should be minimized, the dialog will be hidden
				//without a button in the taskbar
				ShowWindow(SW_HIDE);
				return;
				break;

			
			case SC_CLOSE:
				//before the dialog will be closed, we have to clear the icon(s)
				if(m_bActiv){
					//if the measurement is activ, there are two icons to delete
					ClearIcon1();
					ClearIcon2();
				}
				else{
					//if the measurement is not activ, there is only one icon to delete
					ClearDefaultIconInTray();
				}
				break;
			
			
			default:
				break;

		}


		CDialog::OnSysCommand(nID, lParam);
	}
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CDynIconDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

// The system calls this function to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CDynIconDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}

void CDynIconDlg::SetDefaultIconInTray()
{
	//create a handle for the default icon	
	HICON hIcon;
	
	HINSTANCE hInst = AfxFindResourceHandle(MAKEINTRESOURCE(IDI_ICON1),RT_GROUP_ICON);
				
	hIcon = (HICON)LoadImage(hInst,MAKEINTRESOURCE(IDI_ICON1),IMAGE_ICON,16,16,LR_DEFAULTCOLOR);
    	
	//NOTIFYCONDATA structure	
	NOTIFYICONDATA tnid;
 
	//set the values
    tnid.cbSize = sizeof(NOTIFYICONDATA); 
    tnid.hWnd = m_hWnd; 
    tnid.uID = IDI_ICON1;//resourcename of the icon 
    tnid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP; 
    tnid.uCallbackMessage = WM_TRAY;//user created message 
    tnid.hIcon = hIcon; 

	//defaultstring for the tooltip
	m_strTooltip.Format(_T("Temperature-Monitor (inactiv)"));

	//copy the string to the NOTIFYCONDATA structure
	lstrcpyn(tnid.szTip, m_strTooltip, sizeof(tnid.szTip)); 
	

	//call the Shell_NotifyIcon
	//because it is the first time, we have to use NIM_ADD
	Shell_NotifyIcon(NIM_ADD, &tnid); 
 
    //now the icon is shown in the tray and we can free the icon 
	DestroyIcon(hIcon); 
}


void CDynIconDlg::ClearDefaultIconInTray()
{
	NOTIFYICONDATA tnid;
	
	tnid.hWnd = m_hWnd; 
	tnid.uID = IDI_ICON1;//the default icon

	//Shell_NotifyIcon with NIM_DEL
	Shell_NotifyIcon(NIM_DELETE, &tnid); 	
}


void CDynIconDlg::ChangeValues()
{
	//this method is used to simulate the dynamic of the meassured values
	//increment the values and display them in the dialog


	CString strValue;

	m_nValue1++;
	if(m_nValue1 > 10) m_nValue1 = -10;

	strValue.Format(_T("%3d"),m_nValue1);
	SetDlgItemTextW(IDC_VALUE1, strValue);

	m_nValue2++;
	if(m_nValue2 > 10) m_nValue2 = -15;

	strValue.Format(_T("%3d"),m_nValue2);
	SetDlgItemTextW(IDC_VALUE2, strValue);
}


void CDynIconDlg::CreateIcons()
{
	CreateIcon1();
	CreateIcon2();

}
void CDynIconDlg::CreateIcon1()
{ 
	using namespace Gdiplus;
	
	//we need a widechar array for the value
	wchar_t strValue[4];
	int size = sizeof(strValue)/sizeof(wchar_t);// because the wchar_t requires two byte!!!

	swprintf( strValue, size, L"%3d", m_nValue1 );//the prefix L means, that the string should be a widechar

	//if you already have a char array including the value
	//then you don't need the swprintf(), but
	//you have to convert the char array to a widechar array
	/*
	char txt[4];
	sprintf_s(txt, sizeof(txt),"%3d", m_nValue1);
	MultiByteToWideChar(CP_ACP, 0, txt, -1, strValue, size);
	*/	
	
	//you can change the colors depending on the value
	//here it should be white only

	//white pen to draw some lines in the icon
	Pen whitePen(Color(255, 255, 255));
	
	//white brush for the text
	SolidBrush whiteBrush(Color(255,255,255));
	
	//create a small font to write the values in the bitmap
	Font font(L"Tahoma",8);//, FontStyleRegular,UnitPixel);
	
	//origin for the string
	PointF origin(-1, 1);
	
	//alignment for the string
	StringFormat format;
	format.SetAlignment(StringAlignmentNear);
	

	
	//create a new bitmap with 16x16 pixel
	Bitmap bitmap(16,16);
	
	//use the bitmap to draw
	Graphics *graph = Graphics::FromImage(&bitmap);
	
	//draw two horizontale lines
	//just for the show
	graph->DrawLine(&whitePen, 0, 15, 15, 15);
	graph->DrawLine(&whitePen, 0,  0, 15,  0);

	//draw the string including the value
	//here we need the widechar-array
	graph->DrawString(strValue, -1, &font, origin, &format, &whiteBrush);
	
	//create the icon and put it to the handle (member of our class)
	bitmap.GetHICON(&m_hIcon1);

}

void CDynIconDlg::CreateIcon2()
{ 
	using namespace Gdiplus;


	//we need a widechar array for the value
	wchar_t strValue[4];
	int size = sizeof(strValue)/sizeof(wchar_t);// because the wchar_t requires two byte!!!

	swprintf( strValue, size, L"%3d", m_nValue2 );//the prefix L means, that the string should be a widechar

	//if you already have a char array including the value
	//then you don't need the swprintf(), but
	//you have to convert the char array to a widechar array
	/*
	char txt[4];
	sprintf_s(txt, sizeof(txt),"%3d", m_nValue2);
	MultiByteToWideChar(CP_ACP, 0, txt, -1, strValue, size);
	*/
	
	
	//you can change the colors depending on the value
	//here it should be white only

	//white pen to draw some lines in the icon
	Pen whitePen(Color(255, 255, 255));
	
	//white brush for the text
	SolidBrush whiteBrush(Color(255,255,255));
	
	//create a small font to write the values in the bitmap
	Font font(L"Tahoma",8);//, FontStyleRegular,UnitPixel);
	
	//origin for the string
	PointF origin(-1, 1);
	
	//alignment for the string
	StringFormat format;
	format.SetAlignment(StringAlignmentNear);
	

	
	//create a new bitmap with 16x16 pixel
	Bitmap bitmap(16,16);
	
	//use the bitmap to draw
	Graphics *graph = Graphics::FromImage(&bitmap);
	
	//draw two horizontale lines
	//just for the show
	graph->DrawLine(&whitePen, 0, 15, 15, 15);
	graph->DrawLine(&whitePen, 0,  0, 15,  0);

	//draw the string including the value
	//here we need the widechar-array
	graph->DrawString(strValue, -1, &font, origin, &format, &whiteBrush);
	
	//create the icon and put it to the handle (member of our class)
	bitmap.GetHICON(&m_hIcon2);

}


void CDynIconDlg::PushIcons()
{
	//at the first time we have to clear the defaulticon
	if(m_bFirstDefaultIcon){
		m_bFirstDefaultIcon = FALSE;
		ClearDefaultIconInTray();
	}


	//we change the content of the tooltip
	//we use the same tooltip for the two icons
	m_strTooltip.Format(_T("Value1:%3d\nValue2:%3d"),m_nValue1, m_nValue2);

	//update the icons
	PushIcon2();
	PushIcon1();
}

void CDynIconDlg::PushIcon1()
{
	// set NOTIFYCONDATA structure	
	NOTIFYICONDATA tnid;
 
    tnid.cbSize = sizeof(NOTIFYICONDATA); 
    tnid.hWnd = m_hWnd; 
    tnid.uID = ICON_VALUE1; //Resourcename
    tnid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP; 
    tnid.uCallbackMessage = WM_TRAY;//user message 
    tnid.hIcon = m_hIcon1; //handle of the created icon

	//copy the string to the NOTIFYCONDATA structure
	lstrcpyn(tnid.szTip, m_strTooltip, sizeof(tnid.szTip));
	
	
	if(m_bFirstIcon1){
		
		//for the first time we have to use the Shell_NotifyIcon with NIM_ADD
		//to add the icon to the tray
		Shell_NotifyIcon(NIM_ADD, &tnid); 
		m_bFirstIcon1 = FALSE;
	}
	else{
		//the icon already exists
		//Shell_NotifyIcon with NIM_MODIFY
		Shell_NotifyIcon(NIM_MODIFY, &tnid);
	}
 
	// free icon 
	DestroyIcon(m_hIcon1); 
}

void CDynIconDlg::PushIcon2()
{
	// set NOTIFYCONDATA structure	
	NOTIFYICONDATA tnid;
 
    tnid.cbSize = sizeof(NOTIFYICONDATA); 
    tnid.hWnd = m_hWnd; 
    tnid.uID = ICON_VALUE2; //resourcename
    tnid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP; 
    tnid.uCallbackMessage = WM_TRAY;//user message 
    tnid.hIcon = m_hIcon2; //handle of the created icon

	//copy the string to the NOTIFYCONDATA structure
	lstrcpyn(tnid.szTip, m_strTooltip, sizeof(tnid.szTip));
	
	
	if(m_bFirstIcon2){
		
		//for the first time we have to use the Shell_NotifyIcon with NIM_ADD
		//to add the icon to the tray
		Shell_NotifyIcon(NIM_ADD, &tnid); 
		m_bFirstIcon2 = FALSE;
	}
	else{
		//the icon already exists
		//Shell_NotifyIcon with NIM_MODIFY
		Shell_NotifyIcon(NIM_MODIFY, &tnid);
	}
 
	// free icon 
	DestroyIcon(m_hIcon2); 
}

void CDynIconDlg::ClearIcon1()
{
	NOTIFYICONDATA tnid;
	
	tnid.hWnd = m_hWnd; 
	tnid.uID = ICON_VALUE1;

	//Shell_NotifyIcon with NIM_DEL
	Shell_NotifyIcon(NIM_DELETE, &tnid); 	
}

void CDynIconDlg::ClearIcon2()
{
	NOTIFYICONDATA tnid;
	
	tnid.hWnd = m_hWnd; 
	tnid.uID = ICON_VALUE2;

	//Shell_NotifyIcon with NIM_DEL
	Shell_NotifyIcon(NIM_DELETE, &tnid); 	
}






void CDynIconDlg::OnTimer(UINT_PTR nIDEvent)
{	
	switch(nIDEvent){
		case TIMER1: 
				ChangeValues();
				CreateIcons();
				PushIcons();
				break;
		
		default: break;
	}

}


void CDynIconDlg::OnBnClickedStart()
{
	//start Timer1
	SetTimer(TIMER1, 1000, NULL);

	//set the states of the buttons
	((CButton*)GetDlgItem(IDC_START))->EnableWindow(FALSE);
	((CButton*)GetDlgItem(IDC_STOP))->EnableWindow(TRUE);
	((CButton*)GetDlgItem(IDOK))->EnableWindow(FALSE);

	m_bActiv = TRUE;

}

void CDynIconDlg::OnBnClickedStop()
{
	//stop Timer1
	KillTimer(TIMER1);

	//clear icon1
	ClearIcon1();

	//clear icon2
	ClearIcon2();

	//set the defaulticon in the tray
	SetDefaultIconInTray();

	//set the states of the buttons
	((CButton*)GetDlgItem(IDC_START))->EnableWindow(TRUE);
	((CButton*)GetDlgItem(IDC_STOP))->EnableWindow(FALSE);
	((CButton*)GetDlgItem(IDOK))->EnableWindow(TRUE);

	m_bActiv = FALSE;

	m_bFirstDefaultIcon = TRUE;
	m_bFirstIcon1 = TRUE;
	m_bFirstIcon2 = TRUE;
}

void CDynIconDlg::OnBnClickedOk()
{
	//clear the Icon in the tray
	ClearDefaultIconInTray();
	OnOK();
}


LRESULT	CDynIconDlg::OnTray(WPARAM wParam, LPARAM lParam)
{
	//Messagehandler of the icons in the tray

	UINT uMouseMsg = (UINT) lParam;
	
	switch(uMouseMsg){
	
		case WM_LBUTTONDBLCLK:
			
			//show or hide the dialog

			if(IsWindowVisible())
				ShowWindow(SW_HIDE);
			else
				ShowWindow(SW_NORMAL);
				BringWindowToTop();
			break;
		

		case WM_RBUTTONDOWN:
			//here you can popup a menue
			//PopupMenue();
			break;

		default: 
			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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
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