SYSTEMTRAY.CPP
Upload User: svr_uv
Upload Date: 2008-09-16
Package Size: 93k
Code Size: 12k
Category:

Hook api

Development Platform:

Visual C++

  1. /////////////////////////////////////////////////////////////////////////////
  2. // SystemTray.cpp : implementation file
  3. //
  4. // This is a conglomeration of ideas from the MSJ "Webster" application,
  5. // sniffing round the online docs, and from other implementations such
  6. // as PJ Naughter's "CTrayNotifyIcon" (http://indigo.ie/~pjn/ntray.html)
  7. // especially the "CSystemTray::OnTrayNotification" member function.
  8. // Joerg Koenig suggested the icon animation stuff
  9. //
  10. // This class is a light wrapper around the windows system tray stuff. It
  11. // adds an icon to the system tray with the specified ToolTip text and 
  12. // callback notification value, which is sent back to the Parent window.
  13. //
  14. // The tray icon can be instantiated using either the constructor or by
  15. // declaring the object and creating (and displaying) it later on in the
  16. // program. eg.
  17. //
  18. //        CSystemTray m_SystemTray;    // Member variable of some class
  19. //        
  20. //        ... 
  21. //        // in some member function maybe...
  22. //        m_SystemTray.Create(pParentWnd, WM_MY_NOTIFY, "Click here", 
  23. //                          hIcon, nSystemTrayID);
  24. //
  25. // Written by Chris Maunder (chrismaunder@codeguru.com)
  26. // Copyright (c) 1998.
  27. //
  28. // Updated: 25 Jul 1998 - Added icon animation, and derived class
  29. //                        from CWnd in order to handle messages. (CJM)
  30. //                        (icon animation suggested by Joerg Koenig.
  31. //                        Added API to set default menu item. Code provided
  32. //                        by Enrico Lelina.
  33. //
  34. // This code may be used in compiled form in any way you desire. This
  35. // file may be redistributed unmodified by any means PROVIDING it is 
  36. // not sold for profit without the authors written consent, and 
  37. // providing that this notice and the authors name is included. If 
  38. // the source code in  this file is used in any commercial application 
  39. // then acknowledgement must be made to the author of this file 
  40. // (in whatever form you wish).
  41. //
  42. // This file is provided "as is" with no expressed or implied warranty.
  43. // The author accepts no liability if it causes any damage to your
  44. // computer, causes your pet cat to fall ill, increases baldness or
  45. // makes you car start emitting strange noises when you start it up.
  46. //
  47. // Expect bugs.
  48. // 
  49. // Please use and enjoy. Please let me know of any bugs/mods/improvements 
  50. // that you have found/implemented and I will fix/incorporate them into this
  51. // file. 
  52. //
  53. /////////////////////////////////////////////////////////////////////////////
  54.     
  55. #include "stdafx.h"
  56. #include "SystemTray.h"
  57. #ifdef _DEBUG
  58. #define new DEBUG_NEW
  59. #undef THIS_FILE
  60. static char THIS_FILE[] = __FILE__;
  61. #endif
  62. IMPLEMENT_DYNAMIC(CSystemTray, CWnd)
  63. UINT CSystemTray::m_nIDEvent = 4567;
  64. /////////////////////////////////////////////////////////////////////////////
  65. // CSystemTray construction/creation/destruction
  66. CSystemTray::CSystemTray()
  67. {
  68.     Initialise();
  69. }
  70. CSystemTray::CSystemTray(CWnd* pParent, UINT uCallbackMessage, LPCTSTR szToolTip, 
  71.                          HICON icon, UINT uID)
  72. {
  73.     Initialise();
  74.     Create(pParent, uCallbackMessage, szToolTip, icon, uID);
  75. }
  76. void CSystemTray::Initialise()
  77. {
  78.     memset(&m_tnd, 0, sizeof(m_tnd));
  79.     m_bEnabled   = FALSE;
  80.     m_bHidden    = FALSE;
  81.     m_uIDTimer   = 0;
  82.     m_hSavedIcon = NULL;
  83.     m_DefaultMenuItemID = 0;
  84.     m_DefaultMenuItemByPos = TRUE;
  85. }
  86. BOOL CSystemTray::Create(CWnd* pParent, UINT uCallbackMessage, LPCTSTR szToolTip, 
  87.                          HICON icon, UINT uID)
  88. {
  89.     // this is only for Windows 95 (or higher)
  90.     VERIFY(m_bEnabled = ( GetVersion() & 0xff ) >= 4);
  91.     if (!m_bEnabled) return FALSE;
  92.     // Make sure Notification window is valid (not needed - CJM)
  93.     // VERIFY(m_bEnabled = (pParent && ::IsWindow(pParent->GetSafeHwnd())));
  94.     // if (!m_bEnabled) return FALSE;
  95.     
  96.     // Make sure we avoid conflict with other messages
  97.     ASSERT(uCallbackMessage >= WM_USER);
  98.     // Tray only supports tooltip text up to 64 characters
  99.     ASSERT(_tcslen(szToolTip) <= 64);
  100.     // Create an invisible window
  101.     CWnd::CreateEx(0, AfxRegisterWndClass(0), _T(""), WS_POPUP, 0,0,10,10, NULL, 0);
  102.     // load up the NOTIFYICONDATA structure
  103.     m_tnd.cbSize = sizeof(NOTIFYICONDATA);
  104.     m_tnd.hWnd   = pParent->GetSafeHwnd()? pParent->GetSafeHwnd() : m_hWnd;
  105.     m_tnd.uID    = uID;
  106.     m_tnd.hIcon  = icon;
  107.     m_tnd.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
  108.     m_tnd.uCallbackMessage = uCallbackMessage;
  109.     _tcscpy(m_tnd.szTip, szToolTip);
  110.     // Set the tray icon
  111.     VERIFY(m_bEnabled = Shell_NotifyIcon(NIM_ADD, &m_tnd));
  112.     return m_bEnabled;
  113. }
  114. CSystemTray::~CSystemTray()
  115. {
  116.     RemoveIcon();
  117.     m_IconList.RemoveAll();
  118.     DestroyWindow();
  119. }
  120. /////////////////////////////////////////////////////////////////////////////
  121. // CSystemTray icon manipulation
  122. void CSystemTray::MoveToRight()
  123. {
  124.     HideIcon();
  125.     ShowIcon();
  126. }
  127. void CSystemTray::RemoveIcon()
  128. {
  129.     if (!m_bEnabled) return;
  130.     m_tnd.uFlags = 0;
  131.     Shell_NotifyIcon(NIM_DELETE, &m_tnd);
  132.     m_bEnabled = FALSE;
  133. }
  134. void CSystemTray::HideIcon()
  135. {
  136.     if (m_bEnabled && !m_bHidden) {
  137.         m_tnd.uFlags = NIF_ICON;
  138.         Shell_NotifyIcon (NIM_DELETE, &m_tnd);
  139.         m_bHidden = TRUE;
  140.     }
  141. }
  142. void CSystemTray::ShowIcon()
  143. {
  144.     if (m_bEnabled && m_bHidden) {
  145.         m_tnd.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
  146.         Shell_NotifyIcon(NIM_ADD, &m_tnd);
  147.         m_bHidden = FALSE;
  148.     }
  149. }
  150. BOOL CSystemTray::SetIcon(HICON hIcon)
  151. {
  152.     if (!m_bEnabled) return FALSE;
  153.     m_tnd.uFlags = NIF_ICON;
  154.     m_tnd.hIcon = hIcon;
  155.     return Shell_NotifyIcon(NIM_MODIFY, &m_tnd);
  156. }
  157. BOOL CSystemTray::SetIcon(LPCTSTR lpszIconName)
  158. {
  159.     HICON hIcon = AfxGetApp()->LoadIcon(lpszIconName);
  160.     return SetIcon(hIcon);
  161. }
  162. BOOL CSystemTray::SetIcon(UINT nIDResource)
  163. {
  164.     HICON hIcon = AfxGetApp()->LoadIcon(nIDResource);
  165.     return SetIcon(hIcon);
  166. }
  167. BOOL CSystemTray::SetStandardIcon(LPCTSTR lpIconName)
  168. {
  169.     HICON hIcon = LoadIcon(NULL, lpIconName);
  170.     return SetIcon(hIcon);
  171. }
  172. BOOL CSystemTray::SetStandardIcon(UINT nIDResource)
  173. {
  174.     HICON hIcon = LoadIcon(NULL, MAKEINTRESOURCE(nIDResource));
  175.     return SetIcon(hIcon);
  176. }
  177.  
  178. HICON CSystemTray::GetIcon() const
  179. {
  180.     return (m_bEnabled)? m_tnd.hIcon : NULL;
  181. }
  182. BOOL CSystemTray::SetIconList(UINT uFirstIconID, UINT uLastIconID) 
  183. {
  184. if (uFirstIconID > uLastIconID)
  185.         return FALSE;
  186. UINT uIconArraySize = uLastIconID - uFirstIconID + 1;
  187. const CWinApp * pApp = AfxGetApp();
  188.     ASSERT(pApp != 0);
  189.     m_IconList.RemoveAll();
  190.     try {
  191.     for (UINT i = uFirstIconID; i <= uLastIconID; i++)
  192.     m_IconList.Add(pApp->LoadIcon(i));
  193.     }
  194.     catch (CMemoryException *e)
  195.     {
  196.         e->ReportError();
  197.         e->Delete();
  198.         m_IconList.RemoveAll();
  199.         return FALSE;
  200.     }
  201.     return TRUE;
  202. }
  203. BOOL CSystemTray::SetIconList(HICON* pHIconList, UINT nNumIcons)
  204. {
  205.     m_IconList.RemoveAll();
  206.     try {
  207.     for (UINT i = 0; i <= nNumIcons; i++)
  208.     m_IconList.Add(pHIconList[i]);
  209.     }
  210.     catch (CMemoryException *e)
  211.     {
  212.         e->ReportError();
  213.         e->Delete();
  214.         m_IconList.RemoveAll();
  215.         return FALSE;
  216.     }
  217.     return TRUE;
  218. }
  219. BOOL CSystemTray::Animate(UINT nDelayMilliSeconds, int nNumSeconds /*=-1*/)
  220. {
  221.     StopAnimation();
  222.     m_nCurrentIcon = 0;
  223.     m_StartTime = COleDateTime::GetCurrentTime();
  224.     m_nAnimationPeriod = nNumSeconds;
  225.     m_hSavedIcon = GetIcon();
  226. // Setup a timer for the animation
  227. m_uIDTimer = SetTimer(m_nIDEvent, nDelayMilliSeconds, NULL);
  228.     return (m_uIDTimer != 0);
  229. }
  230. BOOL CSystemTray::StepAnimation()
  231. {
  232.     if (!m_IconList.GetSize())
  233.         return FALSE;
  234.     m_nCurrentIcon++;
  235.     if (m_nCurrentIcon >= m_IconList.GetSize())
  236.         m_nCurrentIcon = 0;
  237.     return SetIcon(m_IconList[m_nCurrentIcon]);
  238. }
  239. BOOL CSystemTray::StopAnimation()
  240. {
  241.     BOOL bResult = FALSE;
  242.     if (m_uIDTimer)
  243.     bResult = KillTimer(m_uIDTimer);
  244.     m_uIDTimer = 0;
  245.     if (m_hSavedIcon)
  246.         SetIcon(m_hSavedIcon);
  247.     m_hSavedIcon = NULL;
  248.     return bResult;
  249. }
  250. /////////////////////////////////////////////////////////////////////////////
  251. // CSystemTray tooltip text manipulation
  252. BOOL CSystemTray::SetTooltipText(LPCTSTR pszTip)
  253. {
  254.     if (!m_bEnabled) return FALSE;
  255.     m_tnd.uFlags = NIF_TIP;
  256.     _tcscpy(m_tnd.szTip, pszTip);
  257.     return Shell_NotifyIcon(NIM_MODIFY, &m_tnd);
  258. }
  259. BOOL CSystemTray::SetTooltipText(UINT nID)
  260. {
  261.     CString strText;
  262.     VERIFY(strText.LoadString(nID));
  263.     return SetTooltipText(strText);
  264. }
  265. CString CSystemTray::GetTooltipText() const
  266. {
  267.     CString strText;
  268.     if (m_bEnabled)
  269.         strText = m_tnd.szTip;
  270.     return strText;
  271. }
  272. /////////////////////////////////////////////////////////////////////////////
  273. // CSystemTray notification window stuff
  274. BOOL CSystemTray::SetNotificationWnd(CWnd* pWnd)
  275. {
  276.     if (!m_bEnabled) return FALSE;
  277.     // Make sure Notification window is valid
  278.     ASSERT(pWnd && ::IsWindow(pWnd->GetSafeHwnd()));
  279.     m_tnd.hWnd = pWnd->GetSafeHwnd();
  280.     m_tnd.uFlags = 0;
  281.     return Shell_NotifyIcon(NIM_MODIFY, &m_tnd);
  282. }
  283. CWnd* CSystemTray::GetNotificationWnd() const
  284. {
  285.     return CWnd::FromHandle(m_tnd.hWnd);
  286. }
  287. /////////////////////////////////////////////////////////////////////////////
  288. // CSystemTray menu manipulation
  289. BOOL CSystemTray::SetMenuDefaultItem(UINT uItem, BOOL bByPos)
  290. {
  291.     if ((m_DefaultMenuItemID == uItem) && (m_DefaultMenuItemByPos == bByPos)) 
  292.         return TRUE;
  293.     m_DefaultMenuItemID = uItem;
  294.     m_DefaultMenuItemByPos = bByPos;   
  295.     CMenu menu, *pSubMenu;
  296.     if (!menu.LoadMenu(m_tnd.uID)) return FALSE;
  297.     if (!(pSubMenu = menu.GetSubMenu(0))) return FALSE;
  298.     ::SetMenuDefaultItem(pSubMenu->m_hMenu, m_DefaultMenuItemID, m_DefaultMenuItemByPos);
  299.     return TRUE;
  300. }
  301. void CSystemTray::GetMenuDefaultItem(UINT& uItem, BOOL& bByPos)
  302. {
  303.     uItem = m_DefaultMenuItemID;
  304.     bByPos = m_DefaultMenuItemByPos;
  305. }
  306. /////////////////////////////////////////////////////////////////////////////
  307. // CSystemTray message handlers
  308. BEGIN_MESSAGE_MAP(CSystemTray, CWnd)
  309. //{{AFX_MSG_MAP(CSystemTray)
  310. ON_WM_TIMER()
  311. //}}AFX_MSG_MAP
  312. END_MESSAGE_MAP()
  313. void CSystemTray::OnTimer(UINT nIDEvent) 
  314. {
  315.     ASSERT(nIDEvent == m_nIDEvent);
  316.     COleDateTime CurrentTime = COleDateTime::GetCurrentTime();
  317.     COleDateTimeSpan period = CurrentTime - m_StartTime;
  318.     if (m_nAnimationPeriod > 0 && m_nAnimationPeriod < period.GetTotalSeconds())
  319.     {
  320.         StopAnimation();
  321.         return;
  322.     }
  323.     StepAnimation();
  324. }
  325. LRESULT CSystemTray::OnTrayNotification(UINT wParam, LONG lParam) 
  326. {
  327.     //Return quickly if its not for this tray icon
  328.     if (wParam != m_tnd.uID)
  329.         return 0L;
  330.     CMenu menu, *pSubMenu;
  331.     CWnd* pTarget = AfxGetMainWnd();
  332.     // Clicking with right button brings up a context menu
  333.     if (LOWORD(lParam) == WM_RBUTTONUP)
  334.     {    
  335.         if (!menu.LoadMenu(m_tnd.uID)) return 0;
  336.         if (!(pSubMenu = menu.GetSubMenu(0))) return 0;
  337.         // Make chosen menu item the default (bold font)
  338.         ::SetMenuDefaultItem(pSubMenu->m_hMenu, m_DefaultMenuItemID, m_DefaultMenuItemByPos);
  339.         // Display and track the popup menu
  340.         CPoint pos;
  341.         GetCursorPos(&pos);
  342.         pTarget->SetForegroundWindow();  
  343.         ::TrackPopupMenu(pSubMenu->m_hMenu, 0, pos.x, pos.y, 0, 
  344.                          pTarget->GetSafeHwnd(), NULL);
  345.         // BUGFIX: See "PRB: Menus for Notification Icons Don't Work Correctly"
  346.         pTarget->PostMessage(WM_NULL, 0, 0);
  347.         menu.DestroyMenu();
  348.     } 
  349.     else if (LOWORD(lParam) == WM_LBUTTONDBLCLK) 
  350.     {
  351.         // double click received, the default action is to execute default menu item
  352.         pTarget->SetForegroundWindow();  
  353.         UINT uItem;
  354.         if (m_DefaultMenuItemByPos)
  355.         {
  356.             if (!menu.LoadMenu(m_tnd.uID)) return 0;
  357.             if (!(pSubMenu = menu.GetSubMenu(0))) return 0;
  358.             uItem = pSubMenu->GetMenuItemID(m_DefaultMenuItemID);
  359.         }
  360.         else
  361.             uItem = m_DefaultMenuItemID;
  362.         
  363.         pTarget->SendMessage(WM_COMMAND, uItem, 0);
  364.         menu.DestroyMenu();
  365.     }
  366.     return 1;
  367. }
  368. LRESULT CSystemTray::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) 
  369. {
  370.     if (message == m_tnd.uCallbackMessage)
  371.         return OnTrayNotification(wParam, lParam);
  372. return CWnd::WindowProc(message, wParam, lParam);
  373. }