How do I place an icon in the system tray?

This loads the systray icon, giving it an ID because I have more than one tray icon. The private message is also specified.

#define TRAY_ICON_01  1
#define MY_SYSTEM_TRAY_ICON(WM_APP+1657)

// Note that a registered message would be better, I'm simplifying here.

void CMainFrame::AddMyIcon (void)
{
   NOTIFYICONDATA nid;
   CString csTip ;

   nid.cbSize = sizeof(NOTIFYICONDATA); 
   nid.hWnd = GetSafeHwnd(); 
   nid.uID = TRAY_ICON_01; // personal ID
   nid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
   nid.uCallbackMessage = MY_SYSTEM_TRAY_MSG;
   nid.hIcon = m_hIconPhone;

   if (csTip.LoadString (IDS_TRAY_MENU_TIP))
      strncpy (nid.szTip, csTip, sizeof(nid.szTip));
   else 
      nid.szTip[0] = '\0';

   Shell_NotifyIcon(NIM_ADD, &nid);
}

This appears in the mainframe message map, and specifies a message sent when the user interacts with the icon. Note that the message ID matches that specified in the uCallbackMessage structure member.

ON_MESSAGE (MY_SYSTEM_TRAY_MSG, OnSystemTrayIconClick)

This handles the click message declared above.

afx_msg LONG CMainFrame::OnSystemTrayIconClick (WPARAM wParam, LPARAM lParam)
{
   switch (wParam)
   {
      // bunch of other code omitted here. Note that the
      // ID here matches that specified when the icon
      // was inserted, in the uID structure member.

      case TRAY_ICON_01:
         switch (lParam)
         {
            case WM_LBUTTONDOWN:
            case WM_RBUTTONDOWN:
               ShowLittleMenu ();
               break;
         }
         break ;

      default:
         OutputDebugString ("invalid icon id from tray\n");
         break;
   }
   return TRUE;
}

This shows the menu for the systray icon. The popup menu is loaded elsewhere (and it MUST be a popup, or you'll get a bizarre minimal-width empty menu appearing). The easiest way is to create a single bar menu with several popups, load that, and use GetSubMenu to choose the one you want for any particular circumstance.

void CMainFrame::ShowLittleMenu ()
{
   POINT CurPos ;

   GetCursorPos (&CurPos);
   SetForegroundWindow ();// Bodge to get around a documented bug in Explorer

   // Display the menu. m_hLittleMenu is a popup loaded elsewhere.
   TrackPopupMenu (m_hLittleMenu, 
                   TPM_LEFTBUTTON,
                   CurPos.x,
                   CurPos.y,
                   0,
                   GetSafeHwnd(),
                   NULL);
   PostMessage (WM_NULL, 0, 0);// Bodge to get around a documented bug in Explorer
}
Download