SystemTray.cpp
上传用户:deligs
上传日期:2007-01-08
资源大小:43k
文件大小:28k
源码类别:

网络编程

开发平台:

Visual C++

  1. /////////////////////////////////////////////////////////////////////////////
  2. // SystemTray.cpp : implementation file
  3. //
  4. // MFC VERSION
  5. //
  6. // This is a conglomeration of ideas from the MSJ "Webster" application,
  7. // sniffing round the online docs, and from other implementations such
  8. // as PJ Naughter's "CTrayNotifyIcon" (http://indigo.ie/~pjn/ntray.html)
  9. // especially the "CSystemTray::OnTrayNotification" member function.
  10. // Joerg Koenig suggested the icon animation stuff
  11. //
  12. // This class is a light wrapper around the windows system tray stuff. It
  13. // adds an icon to the system tray with the specified ToolTip text and 
  14. // callback notification value, which is sent back to the Parent window.
  15. //
  16. // The tray icon can be instantiated using either the constructor or by
  17. // declaring the object and creating (and displaying) it later on in the
  18. // program. eg.
  19. //
  20. //        CSystemTray m_SystemTray;    // Member variable of some class
  21. //        
  22. //        ... 
  23. //        // in some member function maybe...
  24. //        m_SystemTray.Create(pParentWnd, WM_MY_NOTIFY, "Click here", 
  25. //                          hIcon, nSystemTrayID);
  26. //
  27. // Written by Chris Maunder (cmaunder@mail.com)
  28. // Copyright (c) 1998.
  29. //
  30. // Updated: 25 Jul 1998 - Added icon animation, and derived class
  31. //                        from CWnd in order to handle messages. (CJM)
  32. //                        (icon animation suggested by Joerg Koenig.
  33. //                        Added API to set default menu item. Code provided
  34. //                        by Enrico Lelina.
  35. //
  36. // Updated: 6 June 1999 - SetIcon can now load non-standard sized icons (Chip Calvert)
  37. //                        Added "bHidden" parameter when creating icon
  38. //                        (Thanks to Michael Gombar for these suggestions)
  39. //                        Restricted tooltip text to 64 characters.
  40. //
  41. // Updated: 9 Nov 1999  - Now works in WindowsCE.
  42. //                        Fix for use in NT services (Thomas Mooney, TeleProc, Inc)
  43. //                        Added W2K stuff by Michael Dunn
  44. //
  45. // Updated: 1 Jan 2000  - Added tray minimisation stuff.
  46. // 
  47. //
  48. // This code may be used in compiled form in any way you desire. This
  49. // file may be redistributed unmodified by any means PROVIDING it is 
  50. // not sold for profit without the authors written consent, and 
  51. // providing that this notice and the authors name is included. If 
  52. // the source code in  this file is used in any commercial application 
  53. // then acknowledgement must be made to the author of this file 
  54. // (in whatever form you wish).
  55. //
  56. // This file is provided "as is" with no expressed or implied warranty.
  57. // The author accepts no liability for any damage caused through use.
  58. //
  59. // Expect bugs.
  60. // 
  61. // Please use and enjoy. Please let me know of any bugs/mods/improvements 
  62. // that you have found/implemented and I will fix/incorporate them into this
  63. // file. 
  64. //
  65. /////////////////////////////////////////////////////////////////////////////
  66.     
  67. #include "stdafx.h"
  68. #include "SystemTray.h"
  69. #include "resource.h"       // main symbols
  70. #ifdef _DEBUG
  71. #define new DEBUG_NEW
  72. #undef THIS_FILE
  73. static char THIS_FILE[] = __FILE__;
  74. #endif
  75. #ifndef _WIN32_WCE  // Use C++ exception handling instead of structured.
  76. #undef TRY
  77. #undef CATCH
  78. #undef END_CATCH
  79. #define TRY try
  80. #define CATCH(ex_class, ex_object) catch(ex_class* ex_object)
  81. #define END_CATCH
  82. #endif  // _WIN32_WCE
  83. #ifndef _countof
  84. #define _countof(x) ( sizeof(x) / sizeof(x[0]) )
  85. #endif
  86. IMPLEMENT_DYNAMIC(CSystemTray, CWnd)
  87. const UINT CSystemTray::m_nTimerID    = 4567;
  88. UINT CSystemTray::m_nMaxTooltipLength  = 64;     // This may change...
  89. const UINT CSystemTray::m_nTaskbarCreatedMsg = ::RegisterWindowMessage(_T("TaskbarCreated"));
  90. CWnd  CSystemTray::m_wndInvisible;
  91. /////////////////////////////////////////////////////////////////////////////
  92. // CSystemTray construction/creation/destruction
  93. CSystemTray::CSystemTray()
  94. {
  95.     Initialise();
  96. }
  97. CSystemTray::CSystemTray(CWnd* pParent,             // The window that will recieve tray notifications
  98.                          UINT uCallbackMessage,     // the callback message to send to parent
  99.                          LPCTSTR szToolTip,         // tray icon tooltip
  100.                          HICON icon,                // Handle to icon
  101.                          UINT uID,                  // Identifier of tray icon
  102.                          BOOL bHidden /*=FALSE*/,   // Hidden on creation?                  
  103.                          LPCTSTR szBalloonTip /*=NULL*/,    // Ballon tip (w2k only)
  104.                          LPCTSTR szBalloonTitle /*=NULL*/,  // Balloon tip title (w2k)
  105.                          DWORD dwBalloonIcon /*=NIIF_NONE*/,// Ballon tip icon (w2k)
  106.                          UINT uBalloonTimeout /*=10*/)      // Balloon timeout (w2k)
  107. {
  108.     Initialise();
  109.     Create(pParent, uCallbackMessage, szToolTip, icon, uID, bHidden,
  110.            szBalloonTip, szBalloonTitle, dwBalloonIcon, uBalloonTimeout);
  111. }
  112. void CSystemTray::Initialise()
  113. {
  114.     memset(&m_tnd, 0, sizeof(m_tnd));
  115.     m_bEnabled = FALSE;
  116.     m_bHidden  = TRUE;
  117.     m_bRemoved = TRUE;
  118.     m_DefaultMenuItemID    = 0;
  119.     m_DefaultMenuItemByPos = TRUE;
  120. m_bMenuItemSuspendEnabled = TRUE;
  121. m_bMenuItemGrayed = FALSE;
  122.     m_bShowIconPending = FALSE;
  123.     m_uIDTimer   = 0;
  124.     m_hSavedIcon = NULL;
  125. m_pTargetWnd = NULL;
  126. m_uCreationFlags = 0;
  127. #ifdef SYSTEMTRAY_USEW2K
  128.     OSVERSIONINFO os = { sizeof(os) };
  129.     GetVersionEx(&os);
  130.     m_bWin2K = ( VER_PLATFORM_WIN32_NT == os.dwPlatformId && os.dwMajorVersion >= 5 );
  131. #else
  132.     m_bWin2K = FALSE;
  133. #endif
  134. }
  135. // update by Michael Dunn, November 1999
  136. //
  137. //  New version of Create() that handles new features in Win 2K.
  138. //
  139. // Changes:
  140. //  szTip: Same as old, but can be 128 characters instead of 64.
  141. //  szBalloonTip: Text for a balloon tooltip that is shown when the icon
  142. //                is first added to the tray.  Pass "" if you don't want
  143. //                a balloon.
  144. //  szBalloonTitle: Title text for the balloon tooltip.  This text is shown
  145. //                  in bold above the szBalloonTip text.  Pass "" if you
  146. //                  don't want a title.
  147. //  dwBalloonIcon: Specifies which icon will appear in the balloon.  Legal
  148. //                 values are:
  149. //                     NIIF_NONE: No icon
  150. //                     NIIF_INFO: Information
  151. //                     NIIF_WARNING: Exclamation
  152. //                     NIIF_ERROR: Critical error (red circle with X)
  153. //  uBalloonTimeout: Number of seconds for the balloon to remain visible.
  154. //                   Must be between 10 and 30 inclusive.
  155. BOOL CSystemTray::Create(CWnd* pParent, UINT uCallbackMessage, LPCTSTR szToolTip, 
  156.                          HICON icon, UINT uID, BOOL bHidden /*=FALSE*/,
  157.                          LPCTSTR szBalloonTip /*=NULL*/, 
  158.                          LPCTSTR szBalloonTitle /*=NULL*/,  
  159.                          DWORD dwBalloonIcon /*=NIIF_NONE*/,
  160.                          UINT uBalloonTimeout /*=10*/)
  161. {
  162. #ifdef _WIN32_WCE
  163.     m_bEnabled = TRUE;
  164. #else
  165.     // this is only for Windows 95 (or higher)
  166.     m_bEnabled = (GetVersion() & 0xff) >= 4;
  167.     if (!m_bEnabled) 
  168.     {
  169.         ASSERT(FALSE);
  170.         return FALSE;
  171.     }
  172. #endif
  173.     m_nMaxTooltipLength = _countof(m_tnd.szTip);
  174.     
  175.     // Make sure we avoid conflict with other messages
  176.     ASSERT(uCallbackMessage >= WM_APP);
  177.     // Tray only supports tooltip text up to m_nMaxTooltipLength) characters
  178.     ASSERT(AfxIsValidString(szToolTip));
  179.     ASSERT(_tcslen(szToolTip) <= m_nMaxTooltipLength);
  180.     // Create an invisible window
  181.     CWnd::CreateEx(0, AfxRegisterWndClass(0), _T(""), WS_POPUP, 0,0,0,0, NULL, 0);
  182.     // load up the NOTIFYICONDATA structure
  183.     m_tnd.cbSize = sizeof(NOTIFYICONDATA);
  184.     m_tnd.hWnd   = pParent->GetSafeHwnd()? pParent->GetSafeHwnd() : m_hWnd;
  185.     m_tnd.uID    = uID;
  186.     m_tnd.hIcon  = icon;
  187.     m_tnd.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
  188.     m_tnd.uCallbackMessage = uCallbackMessage;
  189.     _tcsncpy(m_tnd.szTip, szToolTip, m_nMaxTooltipLength-1);
  190. #ifdef SYSTEMTRAY_USEW2K
  191.     if (m_bWin2K && szBalloonTip)
  192.     {
  193.         // The balloon tooltip text can be up to 255 chars long.
  194.         ASSERT(AfxIsValidString(szBalloonTip));
  195.         ASSERT(lstrlen(szBalloonTip) < 256);
  196.         // The balloon title text can be up to 63 chars long.
  197.         if (szBalloonTitle)
  198.         {
  199.             ASSERT(AfxIsValidString(szBalloonTitle));
  200.             ASSERT(lstrlen(szBalloonTitle) < 64);
  201.         }
  202.         // dwBalloonIcon must be valid.
  203.         ASSERT(NIIF_NONE == dwBalloonIcon    || NIIF_INFO == dwBalloonIcon ||
  204.                NIIF_WARNING == dwBalloonIcon || NIIF_ERROR == dwBalloonIcon);
  205.         // The timeout must be between 10 and 30 seconds.
  206.         ASSERT(uBalloonTimeout >= 10 && uBalloonTimeout <= 30);
  207.         m_tnd.uFlags |= NIF_INFO;
  208.         _tcsncpy(m_tnd.szInfo, szBalloonTip, 255);
  209.         if (szBalloonTitle)
  210.             _tcsncpy(m_tnd.szInfoTitle, szBalloonTitle, 63);
  211.         else
  212.             m_tnd.szInfoTitle[0] = _T('');
  213.         m_tnd.uTimeout    = uBalloonTimeout * 1000; // convert time to ms
  214.         m_tnd.dwInfoFlags = dwBalloonIcon;
  215.     }
  216. #endif
  217.     m_bHidden = bHidden;
  218. #ifdef SYSTEMTRAY_USEW2K    
  219.     if (m_bWin2K && m_bHidden)
  220.     {
  221.         m_tnd.uFlags = NIF_STATE;
  222.         m_tnd.dwState = NIS_HIDDEN;
  223.         m_tnd.dwStateMask = NIS_HIDDEN;
  224.     }
  225. #endif
  226. m_uCreationFlags = m_tnd.uFlags; // Store in case we need to recreate in OnTaskBarCreate
  227.     BOOL bResult = TRUE;
  228.     if (!m_bHidden || m_bWin2K)
  229.     {
  230.         bResult = Shell_NotifyIcon(NIM_ADD, &m_tnd);
  231.         m_bShowIconPending = m_bHidden = m_bRemoved = !bResult;
  232.     }
  233.     
  234. #ifdef SYSTEMTRAY_USEW2K    
  235.     if (m_bWin2K && szBalloonTip)
  236.     {
  237.         // Zero out the balloon text string so that later operations won't redisplay
  238.         // the balloon.
  239.         m_tnd.szInfo[0] = _T('');
  240.     }
  241. #endif
  242.     return bResult;
  243. }
  244. CSystemTray::~CSystemTray()
  245. {
  246.     RemoveIcon();
  247.     m_IconList.RemoveAll();
  248.     DestroyWindow();
  249. }
  250. /////////////////////////////////////////////////////////////////////////////
  251. // CSystemTray icon manipulation
  252. //////////////////////////////////////////////////////////////////////////
  253. //
  254. // Function:    SetFocus()
  255. //
  256. // Description:
  257. //  Sets the focus to the tray icon.  Microsoft's Win 2K UI guidelines
  258. //  say you should do this after the user dismisses the icon's context
  259. //  menu.
  260. //
  261. // Input:
  262. //  Nothing.
  263. //
  264. // Returns:
  265. //  Nothing.
  266. //
  267. //////////////////////////////////////////////////////////////////////////
  268. // Added by Michael Dunn, November, 1999
  269. //////////////////////////////////////////////////////////////////////////
  270. void CSystemTray::SetFocus()
  271. {
  272. #ifdef SYSTEMTRAY_USEW2K
  273.     Shell_NotifyIcon ( NIM_SETFOCUS, &m_tnd );
  274. #endif
  275. }
  276. BOOL CSystemTray::MoveToRight()
  277. {
  278.     RemoveIcon();
  279.     return AddIcon();
  280. }
  281. BOOL CSystemTray::AddIcon()
  282. {
  283.     if (!m_bRemoved)
  284.         RemoveIcon();
  285.     if (m_bEnabled)
  286.     {
  287.         m_tnd.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
  288.         if (!Shell_NotifyIcon(NIM_ADD, &m_tnd))
  289.             m_bShowIconPending = TRUE;
  290.         else
  291.             m_bRemoved = m_bHidden = FALSE;
  292.     }
  293.     return (m_bRemoved == FALSE);
  294. }
  295. BOOL CSystemTray::RemoveIcon()
  296. {
  297.     m_bShowIconPending = FALSE;
  298.     if (!m_bEnabled || m_bRemoved)
  299.         return TRUE;
  300.     m_tnd.uFlags = 0;
  301.     if (Shell_NotifyIcon(NIM_DELETE, &m_tnd))
  302.         m_bRemoved = m_bHidden = TRUE;
  303.     return (m_bRemoved == TRUE);
  304. }
  305. BOOL CSystemTray::HideIcon()
  306. {
  307.     if (!m_bEnabled || m_bRemoved || m_bHidden)
  308.         return TRUE;
  309. #ifdef SYSTEMTRAY_USEW2K
  310.     if (m_bWin2K)
  311.     {
  312.         m_tnd.uFlags = NIF_STATE;
  313.         m_tnd.dwState = NIS_HIDDEN;
  314.         m_tnd.dwStateMask = NIS_HIDDEN;
  315.         m_bHidden = Shell_NotifyIcon( NIM_MODIFY, &m_tnd);
  316.     }
  317.     else
  318. #endif
  319.         RemoveIcon();
  320.     return (m_bHidden == TRUE);
  321. }
  322. BOOL CSystemTray::ShowIcon()
  323. {
  324.     if (m_bRemoved)
  325.         return AddIcon();
  326.     if (!m_bHidden)
  327.         return TRUE;
  328. #ifdef SYSTEMTRAY_USEW2K
  329.     if (m_bWin2K)
  330.     {
  331.         m_tnd.uFlags = NIF_STATE;
  332.         m_tnd.dwState = 0;
  333.         m_tnd.dwStateMask = NIS_HIDDEN;
  334.         Shell_NotifyIcon ( NIM_MODIFY, &m_tnd );
  335.     }
  336.     else
  337. #endif
  338.         AddIcon();
  339.     return (m_bHidden == FALSE);
  340. }
  341. BOOL CSystemTray::SetIcon(HICON hIcon)
  342. {
  343.     if (!m_bEnabled)
  344.         return FALSE;
  345.     m_tnd.uFlags = NIF_ICON;
  346.     m_tnd.hIcon = hIcon;
  347.     if (m_bHidden)
  348.         return TRUE;
  349.     else
  350.         return Shell_NotifyIcon(NIM_MODIFY, &m_tnd);
  351. }
  352. BOOL CSystemTray::SetIcon(LPCTSTR lpszIconName)
  353. {
  354.     HICON hIcon = (HICON) ::LoadImage(AfxGetResourceHandle(), 
  355.                                       lpszIconName,
  356.                                       IMAGE_ICON, 
  357.                                       0, 0,
  358.                                       LR_DEFAULTCOLOR);
  359.     return SetIcon(hIcon);
  360. }
  361. BOOL CSystemTray::SetIcon(UINT nIDResource)
  362. {
  363.     return SetIcon(MAKEINTRESOURCE(nIDResource));
  364. }
  365. BOOL CSystemTray::SetStandardIcon(LPCTSTR lpIconName)
  366. {
  367.     HICON hIcon = LoadIcon(NULL, lpIconName);
  368.     return SetIcon(hIcon);
  369. }
  370. BOOL CSystemTray::SetStandardIcon(UINT nIDResource)
  371. {
  372. return SetStandardIcon(MAKEINTRESOURCE(nIDResource));
  373. }
  374.  
  375. HICON CSystemTray::GetIcon() const
  376. {
  377.     return (m_bEnabled)? m_tnd.hIcon : NULL;
  378. }
  379. BOOL CSystemTray::SetIconList(UINT uFirstIconID, UINT uLastIconID) 
  380. {
  381. if (uFirstIconID > uLastIconID)
  382.         return FALSE;
  383. const CWinApp* pApp = AfxGetApp();
  384.     if (!pApp)
  385.     {
  386.         ASSERT(FALSE);
  387.         return FALSE;
  388.     }
  389.     m_IconList.RemoveAll();
  390.     TRY {
  391.     for (UINT i = uFirstIconID; i <= uLastIconID; i++)
  392.     m_IconList.Add(pApp->LoadIcon(i));
  393.     }
  394.     CATCH(CMemoryException, e)
  395.     {
  396.         e->ReportError();
  397.         e->Delete();
  398.         m_IconList.RemoveAll();
  399.         return FALSE;
  400.     }
  401.     END_CATCH
  402.     return TRUE;
  403. }
  404. BOOL CSystemTray::SetIconList(HICON* pHIconList, UINT nNumIcons)
  405. {
  406.     m_IconList.RemoveAll();
  407.     TRY {
  408.     for (UINT i = 0; i <= nNumIcons; i++)
  409.     m_IconList.Add(pHIconList[i]);
  410.     }
  411.     CATCH (CMemoryException, e)
  412.     {
  413.         e->ReportError();
  414.         e->Delete();
  415.         m_IconList.RemoveAll();
  416.         return FALSE;
  417.     }
  418.     END_CATCH
  419.     return TRUE;
  420. }
  421. BOOL CSystemTray::Animate(UINT nDelayMilliSeconds, int nNumSeconds /*=-1*/)
  422. {
  423.     StopAnimation();
  424.     m_nCurrentIcon = 0;
  425.     m_StartTime = COleDateTime::GetCurrentTime();
  426.     m_nAnimationPeriod = nNumSeconds;
  427.     m_hSavedIcon = GetIcon();
  428. // Setup a timer for the animation
  429. m_uIDTimer = SetTimer(m_nTimerID, nDelayMilliSeconds, NULL);
  430.     return (m_uIDTimer != 0);
  431. }
  432. BOOL CSystemTray::StepAnimation()
  433. {
  434.     if (!m_IconList.GetSize())
  435.         return FALSE;
  436.     m_nCurrentIcon++;
  437.     if (m_nCurrentIcon >= m_IconList.GetSize())
  438.         m_nCurrentIcon = 0;
  439.     return SetIcon(m_IconList[m_nCurrentIcon]);
  440. }
  441. BOOL CSystemTray::StopAnimation()
  442. {
  443.     BOOL bResult = FALSE;
  444.     if (m_uIDTimer)
  445.     bResult = KillTimer(m_uIDTimer);
  446.     m_uIDTimer = 0;
  447.     if (m_hSavedIcon)
  448.         SetIcon(m_hSavedIcon);
  449.     m_hSavedIcon = NULL;
  450.     return bResult;
  451. }
  452. /////////////////////////////////////////////////////////////////////////////
  453. // CSystemTray tooltip text manipulation
  454. BOOL CSystemTray::SetTooltipText(LPCTSTR pszTip)
  455. {
  456.     ASSERT(AfxIsValidString(pszTip)); // (md)
  457.     ASSERT(_tcslen(pszTip) < m_nMaxTooltipLength);
  458.     if (!m_bEnabled) 
  459.         return FALSE;
  460.     m_tnd.uFlags = NIF_TIP;
  461.     _tcsncpy(m_tnd.szTip, pszTip, m_nMaxTooltipLength-1);
  462.     if (m_bHidden)
  463.         return TRUE;
  464.     else
  465.         return Shell_NotifyIcon(NIM_MODIFY, &m_tnd);
  466. }
  467. BOOL CSystemTray::SetTooltipText(UINT nID)
  468. {
  469.     CString strText;
  470.     VERIFY(strText.LoadString(nID));
  471.     return SetTooltipText(strText);
  472. }
  473. CString CSystemTray::GetTooltipText() const
  474. {
  475.     CString strText;
  476.     if (m_bEnabled)
  477.         strText = m_tnd.szTip;
  478.     return strText;
  479. }
  480. /////////////////////////////////////////////////////////////////////////////
  481. // CSystemTray support for Win 2K features.
  482. //////////////////////////////////////////////////////////////////////////
  483. //
  484. // Function:    ShowBalloon
  485. //
  486. // Description:
  487. //  Shows a balloon tooltip over the tray icon.
  488. //
  489. // Input:
  490. //  szText: [in] Text for the balloon tooltip.
  491. //  szTitle: [in] Title for the balloon.  This text is shown in bold above
  492. //           the tooltip text (szText).  Pass "" if you don't want a title.
  493. //  dwIcon: [in] Specifies an icon to appear in the balloon.  Legal values are:
  494. //                 NIIF_NONE: No icon
  495. //                 NIIF_INFO: Information
  496. //                 NIIF_WARNING: Exclamation
  497. //                 NIIF_ERROR: Critical error (red circle with X)
  498. //  uTimeout: [in] Number of seconds for the balloon to remain visible.  Can
  499. //            be between 10 and 30 inclusive.
  500. //
  501. // Returns:
  502. //  TRUE if successful, FALSE if not.
  503. //
  504. //////////////////////////////////////////////////////////////////////////
  505. // Added by Michael Dunn, November 1999
  506. //////////////////////////////////////////////////////////////////////////
  507. BOOL CSystemTray::ShowBalloon(LPCTSTR szText,
  508.                               LPCTSTR szTitle  /*=NULL*/,
  509.                               DWORD   dwIcon   /*=NIIF_NONE*/,
  510.                               UINT    uTimeout /*=10*/ )
  511. {
  512. #ifndef SYSTEMTRAY_USEW2K
  513.     return FALSE;
  514. #else
  515.     // Bail out if we're not on Win 2K.
  516.     if (!m_bWin2K)
  517.         return FALSE;
  518.     // Verify input parameters.
  519.     // The balloon tooltip text can be up to 255 chars long.
  520.     ASSERT(AfxIsValidString(szText));
  521.     ASSERT(lstrlen(szText) < 256);
  522.     // The balloon title text can be up to 63 chars long.
  523.     if (szTitle)
  524.     {
  525.         ASSERT(AfxIsValidString( szTitle));
  526.         ASSERT(lstrlen(szTitle) < 64);
  527.     }
  528.     // dwBalloonIcon must be valid.
  529.     ASSERT(NIIF_NONE == dwIcon    || NIIF_INFO == dwIcon ||
  530.            NIIF_WARNING == dwIcon || NIIF_ERROR == dwIcon);
  531.     // The timeout must be between 10 and 30 seconds.
  532.     ASSERT(uTimeout >= 10 && uTimeout <= 30);
  533.     m_tnd.uFlags = NIF_INFO;
  534.     _tcsncpy(m_tnd.szInfo, szText, 256);
  535.     if (szTitle)
  536.         _tcsncpy(m_tnd.szInfoTitle, szTitle, 64);
  537.     else
  538.         m_tnd.szInfoTitle[0] = _T('');
  539.     m_tnd.dwInfoFlags = dwIcon;
  540.     m_tnd.uTimeout = uTimeout * 1000;   // convert time to ms
  541.     BOOL bSuccess = Shell_NotifyIcon (NIM_MODIFY, &m_tnd);
  542.     // Zero out the balloon text string so that later operations won't redisplay
  543.     // the balloon.
  544.     m_tnd.szInfo[0] = _T('');
  545.     return bSuccess;
  546. #endif
  547. }
  548. /////////////////////////////////////////////////////////////////////////////
  549. // CSystemTray notification window stuff
  550. BOOL CSystemTray::SetNotificationWnd(CWnd* pWnd)
  551. {
  552.     if (!m_bEnabled) 
  553.         return FALSE;
  554.     // Make sure Notification window is valid
  555.     if (!pWnd || !::IsWindow(pWnd->GetSafeHwnd()))
  556.     {
  557.         ASSERT(FALSE);
  558.         return FALSE;
  559.     }
  560.     m_tnd.hWnd = pWnd->GetSafeHwnd();
  561.     m_tnd.uFlags = 0;
  562.     if (m_bHidden)
  563.         return TRUE;
  564.     else
  565.         return Shell_NotifyIcon(NIM_MODIFY, &m_tnd);
  566. }
  567. CWnd* CSystemTray::GetNotificationWnd() const
  568. {
  569.     return CWnd::FromHandle(m_tnd.hWnd);
  570. }
  571. // Hatr added
  572. // Hatr added
  573. // Change or retrive the window to send menu commands to
  574. BOOL CSystemTray::SetTargetWnd(CWnd* pTargetWnd)
  575. {
  576.     m_pTargetWnd = pTargetWnd;
  577.     return TRUE;
  578. } // CSystemTray::SetTargetWnd()
  579. CWnd* CSystemTray::GetTargetWnd() const
  580. {
  581.     if (m_pTargetWnd)
  582.         return m_pTargetWnd;
  583.     else
  584.         return AfxGetMainWnd();
  585. } // CSystemTray::GetTargetWnd()
  586. /////////////////////////////////////////////////////////////////////////////
  587. // CSystemTray notification message stuff
  588. BOOL CSystemTray::SetCallbackMessage(UINT uCallbackMessage)
  589. {
  590.     if (!m_bEnabled)
  591.         return FALSE;
  592.     // Make sure we avoid conflict with other messages
  593.     ASSERT(uCallbackMessage >= WM_APP);
  594.     m_tnd.uCallbackMessage = uCallbackMessage;
  595.     m_tnd.uFlags = NIF_MESSAGE;
  596.     if (m_bHidden)
  597.         return TRUE;
  598.     else
  599.         return Shell_NotifyIcon(NIM_MODIFY, &m_tnd);
  600. }
  601. UINT CSystemTray::GetCallbackMessage() const
  602. {
  603.     return m_tnd.uCallbackMessage;
  604. }
  605. /////////////////////////////////////////////////////////////////////////////
  606. // CSystemTray menu manipulation
  607. BOOL CSystemTray::SetMenuDefaultItem(UINT uItem, BOOL bByPos)
  608. {
  609. #ifdef _WIN32_WCE
  610.     return FALSE;
  611. #else
  612.     if ((m_DefaultMenuItemID == uItem) && (m_DefaultMenuItemByPos == bByPos)) 
  613.         return TRUE;
  614.     m_DefaultMenuItemID = uItem;
  615.     m_DefaultMenuItemByPos = bByPos;   
  616.     CMenu menu, *pSubMenu;
  617.     if (!menu.LoadMenu(m_tnd.uID))
  618.         return FALSE;
  619.     pSubMenu = menu.GetSubMenu(0);
  620.     if (!pSubMenu)
  621.         return FALSE;
  622.     ::SetMenuDefaultItem(pSubMenu->m_hMenu, m_DefaultMenuItemID, m_DefaultMenuItemByPos);
  623.     return TRUE;
  624. #endif
  625. }
  626. void CSystemTray::GetMenuDefaultItem(UINT& uItem, BOOL& bByPos)
  627. {
  628.     uItem = m_DefaultMenuItemID;
  629.     bByPos = m_DefaultMenuItemByPos;
  630. }
  631. /////////////////////////////////////////////////////////////////////////////
  632. // CSystemTray message handlers
  633. BEGIN_MESSAGE_MAP(CSystemTray, CWnd)
  634. //{{AFX_MSG_MAP(CSystemTray)
  635. ON_WM_TIMER()
  636. //}}AFX_MSG_MAP
  637. #ifndef _WIN32_WCE
  638. ON_WM_SETTINGCHANGE()
  639. #endif
  640.     ON_REGISTERED_MESSAGE(CSystemTray::m_nTaskbarCreatedMsg, OnTaskbarCreated)
  641. END_MESSAGE_MAP()
  642. void CSystemTray::OnTimer(UINT nIDEvent) 
  643. {
  644.     if (nIDEvent != m_uIDTimer)
  645.     {
  646.         ASSERT(FALSE);
  647.         return;
  648.     }
  649.     COleDateTime CurrentTime = COleDateTime::GetCurrentTime();
  650.     COleDateTimeSpan period = CurrentTime - m_StartTime;
  651.     if (m_nAnimationPeriod > 0 && m_nAnimationPeriod < period.GetTotalSeconds())
  652.     {
  653.         StopAnimation();
  654.         return;
  655.     }
  656.     StepAnimation();
  657. }
  658. // This is called whenever the taskbar is created (eg after explorer crashes
  659. // and restarts. Please note that the WM_TASKBARCREATED message is only passed
  660. // to TOP LEVEL windows (like WM_QUERYNEWPALETTE)
  661. void CSystemTray::OnTaskbarCreated(WPARAM /*wParam*/, LPARAM /*lParam*/) 
  662. {
  663.     InstallIconPending();
  664. }
  665. #ifndef _WIN32_WCE
  666. void CSystemTray::OnSettingChange(UINT uFlags, LPCTSTR lpszSection) 
  667. {
  668. CWnd::OnSettingChange(uFlags, lpszSection);
  669.     if (uFlags == SPI_SETWORKAREA)
  670.         InstallIconPending();
  671. }
  672. #endif
  673. LRESULT CSystemTray::OnTrayNotification(UINT wParam, LONG lParam) 
  674. {
  675.     //Return quickly if its not for this tray icon
  676.     if (wParam != m_tnd.uID)
  677.         return 0L;
  678.     CMenu menu, *pSubMenu;
  679.     CWnd *pTargetWnd = GetTargetWnd();
  680.     if (!pTargetWnd)
  681.         return 0L;
  682.     // Clicking with right button brings up a context menu
  683. #if defined(_WIN32_WCE) //&& _WIN32_WCE < 211
  684.     BOOL bAltPressed = ((GetKeyState(VK_MENU) & (1 << (sizeof(SHORT)*8-1))) != 0);
  685.     if (LOWORD(lParam) == WM_LBUTTONUP && bAltPressed)
  686. #else
  687.     if (LOWORD(lParam) == WM_RBUTTONUP)
  688. #endif
  689.     {    
  690.         if (!menu.LoadMenu(m_tnd.uID))
  691.             return 0;
  692.         
  693.         pSubMenu = menu.GetSubMenu(0);
  694.         if (!pSubMenu)
  695.             return 0;
  696. #ifndef _WIN32_WCE
  697.         // Make chosen menu item the default (bold font)
  698.         ::SetMenuDefaultItem(pSubMenu->m_hMenu, m_DefaultMenuItemID, m_DefaultMenuItemByPos);
  699. #endif
  700.         // Display and track the popup menu
  701.         CPoint pos;
  702. #ifdef _WIN32_WCE
  703.         pos = CPoint(GetMessagePos());
  704. #else
  705.         GetCursorPos(&pos);
  706. #endif
  707.         pTargetWnd->SetForegroundWindow(); 
  708.         
  709. #ifndef _WIN32_WCE
  710.         ::TrackPopupMenu(pSubMenu->m_hMenu, 0, pos.x, pos.y, 0, 
  711.                          pTargetWnd->GetSafeHwnd(), NULL);
  712. #else
  713.         pSubMenu->TrackPopupMenu(TPM_LEFTALIGN, pos.x, pos.y, pTargetWnd, NULL);
  714. #endif
  715.         // BUGFIX: See "PRB: Menus for Notification Icons Don't Work Correctly"
  716.         pTargetWnd->PostMessage(WM_NULL, 0, 0);
  717.         menu.DestroyMenu();
  718.     } 
  719. #if defined(_WIN32_WCE) //&& _WIN32_WCE < 211
  720.     if (LOWORD(lParam) == WM_LBUTTONDBLCLK && bAltPressed)
  721. #else
  722.     else if (LOWORD(lParam) == WM_LBUTTONDBLCLK) 
  723. #endif
  724.     {
  725.         pTargetWnd->SendMessage(WM_COMMAND, ID_APP_ABOUT, 0);
  726.     }
  727.     return 1;
  728. }
  729. LRESULT CSystemTray::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) 
  730. {
  731.     if (message == m_tnd.uCallbackMessage)
  732.         return OnTrayNotification(wParam, lParam);
  733. return CWnd::WindowProc(message, wParam, lParam);
  734. }
  735. void CSystemTray::InstallIconPending()
  736. {
  737.     // Is the icon display pending, and it's not been set as "hidden"?
  738.     if (!m_bShowIconPending || m_bHidden)
  739.         return;
  740. // Reset the flags to what was used at creation
  741. m_tnd.uFlags = m_uCreationFlags;
  742.     // Try and recreate the icon
  743.     m_bHidden = !Shell_NotifyIcon(NIM_ADD, &m_tnd);
  744.     // If it's STILL hidden, then have another go next time...
  745.     m_bShowIconPending = !m_bHidden;
  746.     ASSERT(m_bHidden == FALSE);
  747. }
  748. /////////////////////////////////////////////////////////////////////////////
  749. // For minimising/maximising from system tray
  750. BOOL CALLBACK FindTrayWnd(HWND hwnd, LPARAM lParam)
  751. {
  752.     TCHAR szClassName[256];
  753.     GetClassName(hwnd, szClassName, 255);
  754.     // Did we find the Main System Tray? If so, then get its size and keep going
  755.     if (_tcscmp(szClassName, _T("TrayNotifyWnd")) == 0)
  756.     {
  757.         CRect *pRect = (CRect*) lParam;
  758.         ::GetWindowRect(hwnd, pRect);
  759.         return TRUE;
  760.     }
  761.     // Did we find the System Clock? If so, then adjust the size of the rectangle
  762.     // we have and quit (clock will be found after the system tray)
  763.     if (_tcscmp(szClassName, _T("TrayClockWClass")) == 0)
  764.     {
  765.         CRect *pRect = (CRect*) lParam;
  766.         CRect rectClock;
  767.         ::GetWindowRect(hwnd, rectClock);
  768.         pRect->right = rectClock.left;
  769.         return FALSE;
  770.     }
  771.  
  772.     return TRUE;
  773. }
  774.  
  775. #ifndef _WIN32_WCE
  776. CRect CSystemTray::GetTrayWndRect()
  777. {
  778.     CRect rect(0,0,0,0);
  779.     CWnd* pWnd = FindWindow(_T("Shell_TrayWnd"), NULL);
  780.     if (pWnd)
  781.     {
  782.         pWnd->GetWindowRect(rect);
  783.         EnumChildWindows(pWnd->m_hWnd, FindTrayWnd, (LPARAM)&rect);
  784.     }
  785.     else
  786.     {
  787.         int nWidth = GetSystemMetrics(SM_CXSCREEN);
  788.         int nHeight = GetSystemMetrics(SM_CYSCREEN);
  789.         rect.SetRect(nWidth-40, nHeight-20, nWidth, nHeight);
  790.     }
  791.     return rect;
  792. }
  793. #endif
  794. BOOL CSystemTray::RemoveTaskbarIcon(CWnd* pWnd)
  795. {
  796.     LPCTSTR pstrOwnerClass = AfxRegisterWndClass(0);
  797.     // Create static invisible window
  798.     if (!::IsWindow(m_wndInvisible.m_hWnd))
  799.     {
  800. if (!m_wndInvisible.CreateEx(0, pstrOwnerClass, _T(""), WS_POPUP,
  801. CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
  802. NULL, 0))
  803. return FALSE;
  804.     }
  805.     pWnd->SetParent(&m_wndInvisible);
  806.     return TRUE;
  807. }
  808. void CSystemTray::MinimiseToTray(CWnd* pWnd)
  809. {
  810. #ifndef _WIN32_WCE
  811.     CRect rectFrom, rectTo;
  812.     pWnd->GetWindowRect(rectFrom);
  813.     rectTo = GetTrayWndRect();
  814. DrawAnimatedRects(pWnd->m_hWnd, IDANI_CAPTION, rectFrom, rectTo);
  815.     RemoveTaskbarIcon(pWnd);
  816.     pWnd->ModifyStyle(WS_VISIBLE, 0);
  817. #endif
  818. }
  819. void CSystemTray::MaximiseFromTray(CWnd* pWnd)
  820. {
  821. #ifndef _WIN32_WCE
  822.     CRect rectTo;
  823.     pWnd->GetWindowRect(rectTo);
  824.     CRect rectFrom;
  825.     rectFrom = GetTrayWndRect();
  826.     pWnd->SetParent(NULL);
  827. DrawAnimatedRects(pWnd->m_hWnd, IDANI_CAPTION, rectFrom, rectTo);
  828.     pWnd->ModifyStyle(0, WS_VISIBLE);
  829.     pWnd->RedrawWindow(NULL, NULL, RDW_UPDATENOW | RDW_ALLCHILDREN | RDW_FRAME |
  830.                                    RDW_INVALIDATE | RDW_ERASE);
  831.     // Move focus away and back again to ensure taskbar icon is recreated
  832.     if (::IsWindow(m_wndInvisible.m_hWnd))
  833.         m_wndInvisible.SetActiveWindow();
  834.     pWnd->SetActiveWindow();
  835.     pWnd->SetForegroundWindow();
  836. #endif
  837. }