HomeC&C++WainTutorialsSamplesTip & TrickTools


A small note on how to work with tray icons, and how to show a baloon text next to the icon.
First the usual include stuff:
#define WINVER  0x0500
#define _WIN32_IE 0x0500
#include <windows.h>
#include <string.h>
#include <stdlib.h>
Next we define some ID's:
#define TRAY_MESSAGE (WM_APP + 123)
#define IDC_BUTTON1 1001
#define IDM_TIMER   1002
There values are more or less don't care, except TRAY_MESSAGE which should have a small (e.g. 0) offset to WM_APP.
Then som variables and function prototypes:
HINSTANCE InstanceHandle;
HICON HIcon;
void Minimize(HWND hwndDlg);
void UnMinimize(HWND hwndDlg);
void SetBaloonTip(HWND hwndDlg);
We will define the functions later, first the message handler for the application:
LRESULT CALLBACK DialogProc(HWND hwndDlg,
                            UINT msg,
                            WPARAM wParam,
                            LPARAM lParam)
{
   switch(msg)
   {
   case WM_CREATE:
      CreateWindow("BUTTON",
                   "Push Me",
                   WS_CHILD | WS_VISIBLE,
                   5, 5, 100, 24,
                   hwndDlg,
                   (HMENU)(IDC_BUTTON1),
                   InstanceHandle,
                   0);
      break;
   case TRAY_MESSAGE:
      if(lParam == WM_LBUTTONDOWN)
      {
         UnMinimize(hwndDlg);
      }
      break;
   case WM_TIMER:
      KillTimer(hwndDlg, IDM_TIMER);
      SetBaloonTip(hwndDlg);
      break;
   case WM_COMMAND:
      if(HIWORD(wParam) == BN_CLICKED &&
         LOWORD(wParam) == IDC_BUTTON1)
      {
         Minimize(hwndDlg);
      }
      break;
   }
   return DefWindowProc(hwndDlg, msg, wParam, lParam);
}
When we receive WM_CREATE we will create a single button on the application and nothing else.
TRAY_MESSAGE is received when the user clicks the icon in the tray.
The WM_COMMAND for IDC_BUTTON1 is recevied when the user press the button.
WM_TIMER is received shortly after the app i minimized, because we we start a timer.
Now the main function:
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, INT)
{
   InstanceHandle = hInstance;
   HIcon = LoadIcon(0, IDI_WINLOGO);

   WNDCLASS wc;
   memset(&wc, 0, sizeof(WNDCLASS));
   wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
   wc.lpfnWndProc = DialogProc;
   wc.hInstance = InstanceHandle;
   wc.hbrBackground = (HBRUSH )(COLOR_BTNFACE + 1);
   wc.lpszClassName = "WhateverClass";
   wc.hCursor = LoadCursor(NULL, IDC_ARROW);
   if(!RegisterClass(&wc))
      return FALSE;
   HWND WindowHandle = CreateWindow("WhateverClass",
                                    "Whatever",
                                    WS_VISIBLE | WS_CLIPSIBLINGS |
                                    WS_CLIPCHILDREN | WS_CAPTION |
                                    WS_BORDER | WS_SYSMENU,
                                    100, 100, 110, 70,
                                    0,
                                    0,
                                    InstanceHandle,
                                    0);
   MSG Msg;
   while(GetMessage(&Msg, WindowHandle, 0, 0xFFFF) > 0)
   {
      if(!IsDialogMessage(WindowHandle, &Msg))
      {
         TranslateMessage(&Msg);
         DispatchMessage(&Msg);
      }
   }
   return 0;
}
We start off by getting a icon, here a standard windows icon.
If you want to use your own from a file called myicon.ico, replace the call to LoadIcon with:
HIcon = (HICON )LoadImage(0,
                          "myicon.ico",
                          IMAGE_ICON,
                          0,
                          0,
                          LR_DEFAULTSIZE | LR_LOADFROMFILE);
Now to the interesting stuff. First the function to hide the application and add the icon in the tray:
void Minimize(HWND hwndDlg)
{
   NOTIFYICONDATA NotifyIconData;
   ShowWindow(hwndDlg, SW_HIDE);
   memset(&NotifyIconData, 0, sizeof(NotifyIconData));
   NotifyIconData.cbSize = sizeof(NotifyIconData);
   NotifyIconData.uID = 123;
   NotifyIconData.hWnd = hwndDlg;
   NotifyIconData.hIcon = HIcon;
   NotifyIconData.uFlags = NIF_ICON | NIF_MESSAGE;
   NotifyIconData.uCallbackMessage = WM_APP + 123;
   strcpy(NotifyIconData.szTip, "TrayTip");
   Shell_NotifyIcon(NIM_ADD, &NotifyIconData);
   SetTimer(hwndDlg, IDM_TIMER, 2000, 0);
}
First the application window is hided, then we add the icon and finaly we start the timer.
Now the function to show the application and remove the icon from the tray:
void UnMinimize(HWND hwndDlg)
{
   NOTIFYICONDATA NotifyIconData;
   ShowWindow(hwndDlg, SW_SHOW);
   memset(&NotifyIconData, 0, sizeof(NotifyIconData));
   NotifyIconData.cbSize = sizeof(NotifyIconData);
   NotifyIconData.uID = 123;
   NotifyIconData.hWnd = hwndDlg;
   NotifyIconData.hIcon = HIcon;
   NotifyIconData.uFlags = NIF_ICON | NIF_MESSAGE;
   NotifyIconData.uCallbackMessage = TRAY_MESSAGE;
   strcpy(NotifyIconData.szTip, "TrayTip");
   Shell_NotifyIcon(NIM_DELETE, &NotifyIconData);
}
And finally the function which shows the ballon tip:
void SetBaloonTip(HWND hwndDlg)
{
   NOTIFYICONDATA  NotifyIconData;
   memset(&NotifyIconData, 0, sizeof(NOTIFYICONDATA));
   NotifyIconData.cbSize = sizeof(NOTIFYICONDATA);
   NotifyIconData.uID = 123;
   NotifyIconData.hWnd = hwndDlg;
   NotifyIconData.hIcon = HIcon;
   NotifyIconData.uFlags = 0x10;
   NotifyIconData.uTimeout = 15000;
   NotifyIconData.uCallbackMessage = TRAY_MESSAGE;
   strcpy(NotifyIconData.szInfoTitle, "BaloonTitle");
   strcpy(NotifyIconData.szInfo, "BalloonInfo");
   strcpy(NotifyIconData.szTip, "TrayTip");
   Shell_NotifyIcon(NIM_MODIFY, (NOTIFYICONDATA *)&NotifyIconData);
}
If your compiler complains about uTimeout, szInfoTitle and szInfo, it is too old, and can't show baloon tip. The rest of the code should work anyway.
The code at a glance.