TRAYICON.CPP 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. ////////////////////////////////////////////////////////////////
  2. // If this code works, it was written by Paul DiLascia.
  3. // If not, I don't know who wrote it.
  4. //
  5. #include "stdafx.h"
  6. #include "trayicon.h"
  7. #include <afxpriv.h> // for AfxLoadString
  8. IMPLEMENT_DYNAMIC(CTrayIcon, CCmdTarget)
  9. CTrayIcon::CTrayIcon(UINT uID)
  10. {
  11. // Initialize NOTIFYICONDATA
  12. memset(&m_nid, 0 , sizeof(m_nid));
  13. m_nid.cbSize = sizeof(m_nid);
  14. m_nid.uID = uID; // never changes after construction
  15. // Use resource string as tip if there is one
  16. AfxLoadString(uID, m_nid.szTip, sizeof(m_nid.szTip));
  17. }
  18. CTrayIcon::~CTrayIcon()
  19. {
  20. SetIcon(0); // remove icon from system tray
  21. }
  22. //////////////////
  23. // Set notification window. It must created already.
  24. //
  25. void CTrayIcon::SetNotificationWnd(CWnd* pNotifyWnd, UINT uCbMsg)
  26. {
  27. // If the following assert fails, you're probably
  28. // calling me before you created your window. Oops.
  29. ASSERT(pNotifyWnd==NULL || ::IsWindow(pNotifyWnd->GetSafeHwnd()));
  30. m_nid.hWnd = pNotifyWnd->GetSafeHwnd();
  31. ASSERT(uCbMsg==0 || uCbMsg>=WM_USER);
  32. m_nid.uCallbackMessage = uCbMsg;
  33. }
  34. //////////////////
  35. // This is the main variant for setting the icon.
  36. // Sets both the icon and tooltip from resource ID
  37. // To remove the icon, call SetIcon(0)
  38. //
  39. BOOL CTrayIcon::SetIcon(UINT uID)
  40. {
  41. HICON hicon=NULL;
  42. if (uID) {
  43. AfxLoadString(uID, m_nid.szTip, sizeof(m_nid.szTip));
  44. hicon = AfxGetApp()->LoadIcon(uID);
  45. }
  46. return SetIcon(hicon, NULL);
  47. }
  48. //////////////////
  49. // Common SetIcon for all overloads.
  50. //
  51. BOOL CTrayIcon::SetIcon(HICON hicon, LPCSTR lpTip)
  52. {
  53. UINT msg;
  54. m_nid.uFlags = 0;
  55. // Set the icon
  56. if (hicon) {
  57. // Add or replace icon in system tray
  58. msg = m_nid.hIcon ? NIM_MODIFY : NIM_ADD;
  59. m_nid.hIcon = hicon;
  60. m_nid.uFlags |= NIF_ICON;
  61. } else { // remove icon from tray
  62. if (m_nid.hIcon==NULL)
  63. return TRUE; // already deleted
  64. msg = NIM_DELETE;
  65. }
  66. // Use the tip, if any
  67. if (lpTip)
  68. strncpy(m_nid.szTip, lpTip, sizeof(m_nid.szTip));
  69. if (m_nid.szTip[0])
  70. m_nid.uFlags |= NIF_TIP;
  71. // Use callback if any
  72. if (m_nid.uCallbackMessage && m_nid.hWnd)
  73. m_nid.uFlags |= NIF_MESSAGE;
  74. // Do it
  75. BOOL bRet = Shell_NotifyIcon(msg, &m_nid);
  76. if (msg==NIM_DELETE || !bRet)
  77. m_nid.hIcon = NULL; // failed
  78. return bRet;
  79. }
  80. /////////////////
  81. // Default event handler handles right-menu and doubleclick.
  82. // Call this function from your own notification handler.
  83. //
  84. LRESULT CTrayIcon::OnTrayNotification(WPARAM wID, LPARAM lEvent)
  85. {
  86. if (wID!=m_nid.uID ||
  87. (lEvent!=WM_RBUTTONUP && lEvent!=WM_LBUTTONDBLCLK))
  88. return 0;
  89. // If there's a resource menu with the same ID as the icon, use it as
  90. // the right-button popup menu. CTrayIcon will interprets the first
  91. // item in the menu as the default command for WM_LBUTTONDBLCLK
  92. //
  93. CMenu menu;
  94. if (!menu.LoadMenu(m_nid.uID))
  95. return 0;
  96. CMenu* pSubMenu = menu.GetSubMenu(0);
  97. if (!pSubMenu)
  98. return 0;
  99. if (lEvent==WM_RBUTTONUP) {
  100. // Make first menu item the default (bold font)
  101. ::SetMenuDefaultItem(pSubMenu->m_hMenu, 0, TRUE);
  102. // Display the menu at the current mouse location. There's a "bug"
  103. // (Microsoft calls it a feature) in Windows 95 that requires calling
  104. // SetForegroundWindow. To find out more, search for Q135788 in MSDN.
  105. //
  106. CPoint mouse;
  107. GetCursorPos(&mouse);
  108. ::SetForegroundWindow(m_nid.hWnd);
  109. ::TrackPopupMenu(pSubMenu->m_hMenu, 0, mouse.x, mouse.y, 0,
  110. m_nid.hWnd, NULL);
  111. } else // double click: execute first menu item
  112. ::SendMessage(m_nid.hWnd, WM_COMMAND, pSubMenu->GetMenuItemID(0), 0);
  113. return 1; // handled
  114. }