NTray.cpp 55 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453
  1. /*
  2. Module : NTray.cpp
  3. Purpose: implementation for a MFC class to encapsulate Shell_NotifyIcon
  4. Created: PJN / 14-05-1997
  5. History: PJN / 25-11-1997 Addition of the following
  6. 1. HideIcon(), ShowIcon() & MoveToExtremeRight()
  7. 2. Support for animated tray icons
  8. PJN / 23-06-1998 Class now supports the new Taskbar Creation Notification
  9. message which comes with IE 4. This allows the tray icon
  10. to be recreated whenever the explorer restarts (Crashes!!)
  11. PJN / 22-07-1998 1. Code now compiles cleanly at warning level 4
  12. 2. Code is now UNICODE enabled + build configurations are provided
  13. 3. The documentation for the class has been updated
  14. PJN / 27-01-1999 1. Code first tries to load a 16*16 icon before loading the 32*32
  15. version. This removes the blurryness which was previously occuring
  16. PJN / 28-01-1999 1. Fixed a number of level 4 warnings which were occurring.
  17. PJN / 09-05-1999 1. Fixed a problem as documented in KB article "PRB: Menus for
  18. Notification Icons Do Not Work Correctly", Article ID: Q135788
  19. PJN / 15-05-1999 1. Now uses the author's hookwnd class. This prevents the need to
  20. create the two hidden windows namely CTrayRessurectionWnd and
  21. CTrayTimerWnd
  22. 2. Code now compiles cleanly at warning level 4
  23. 3. General code tidy up and rearrangement
  24. 4. Added numerous ASSERT's to improve the code's robustness
  25. 5. Added functions to allow context menu to be customized
  26. PJN / 01-01-2001 1. Now includes copyright message in the source code and documentation.
  27. 2. Fixed problem where the window does not get focus after double clicking
  28. on the tray icon
  29. 3. Now fully supports the Windows 2000 balloon style tooltips
  30. 4. Fixed a off by one problem in some of the ASSERT's
  31. 5. Fixed problems with Unicode build configurations
  32. 6. Provided Win2k specific build configurations
  33. PJN / 10-02-2001 1. Now fully supports creation of 2 tray icons at the same time
  34. PJN / 13-06-2001 1. Now removes windows hook upon call to RemoveIcon
  35. PJN / 26-08-2001 1. Fixed memory leak in RemoveIcon.
  36. 2. Fixed GPF in RemoveIcon by removing call to Unhook
  37. PJN / 28-08-2001 1. Added support for direct access to the System Tray's HDC. This allows
  38. you to generate an icon for the tray on the fly using GDI calls. The idea
  39. came from the article by Jeff Heaton in the April issue of WDJ. Also added
  40. are overriden Create methods to allow you to easily costruct a dynamic
  41. tray icon given a BITMAP instead of an ICON.
  42. PJN / 21-03-2003 1. Fixed icon resource leaks in SetIcon(LPCTSTR lpIconName) and
  43. SetIcon(UINT nIDResource). Thanks to Egor Pervouninski for reporting this.
  44. 2. Fixed unhooking of the tray icon when the notification window is being
  45. closed.
  46. PJN / 31-03-2003 1. Now uses V1.05 of my Hookwnd class
  47. PJN / 02-04-2003 1. Now uses v1.06 of my Hookwnd class
  48. 2. Fixed a bug in the sample app for this class where the hooks should
  49. have been created as global instances rather than as member variables of
  50. the mainframe window. This ensures that the hooks remain valid even after
  51. calling DefWindowProc on the mainframe.
  52. PJN / 23-07-2004 1. Minor update to remove unnecessary include of "resource.h"
  53. PJN / 03-03-2006 1. Updated copyright details.
  54. 2. Updated the documentation to use the same style as the web site.
  55. 3. Did a spell check of the documentation.
  56. 4. Fixed some issues when the code is compiled using /Wp64. Please note that
  57. to support this the code now requires a recentish Platform SDK to be installed
  58. if the code is compiled with Visual C++ 6.
  59. 5. Replaced all calls to ZeroMemory with memset.
  60. 6. Fixed an issue where SetBalloonDetails was not setting the cbSize parameter.
  61. Thanks to Enrique Granda for reporting this issue.
  62. 7. Added support for NIIF_USER and NIIF_NONE flags.
  63. 8. Now includes support for NIM_NIMSETVERSION via SetVersion. In addition this
  64. is now automatically set in the Create() calls if the Win2k boolean parameter
  65. is set.
  66. 9. Removed derivation from CObject as it was not really needed.
  67. 10. Now includes support for NIM_SETFOCUS
  68. 11. Added support for NIS_HIDDEN via the ShowIcon and HideIcon methods.
  69. 12. Added support for NIIF_NOSOUND
  70. PJN / 27-06-2006 1. Code now uses new C++ style casts rather than old style C casts where necessary.
  71. 2. The class framework now requires the Platform SDK if compiled using VC 6.
  72. 3. Updated the logic of the ASSERTs which validate the various string lengths.
  73. 4. Fixed a bug in CTrayNotifyIcon::SetFocus() where the cbSize value was not being
  74. set correctly.
  75. 5. CTrayIconHooker class now uses ATL's CWindowImpl class in preference to the author's
  76. CHookWnd class. This does mean that for MFC only client projects, you will need to add
  77. ATL support to your project.
  78. 6. Optimized CTrayIconHooker constructor code
  79. 7. Updated code to compile cleanly using VC 2005. Thanks to "Itamar" for prompting this
  80. update.
  81. 8. Addition of a CTRAYNOTIFYICON_EXT_CLASS and CTRAYNOTIFYICON_EXT_API macros which makes
  82. the class easier to use in an extension dll.
  83. 9. Made CTrayNotifyIcon destructor virtual
  84. PJN / 03-07-2005 1. Fixed a bug where the HideIcon functionality did not work on Windows 2000. This was
  85. related to how the cbSize member of the NOTIFYICONDATA structure was initialized. The code
  86. now dynamically determines the correct size to set at runtime according to the instructions
  87. provided by the MSDN documentation for this structure. As a result of this, all "bWin2k"
  88. parameters which were previously exposed via CTrayNotifyIcon have now been removed as there
  89. is no need for them. Thanks to Edwin Geng for reporting this important bug. Client code will
  90. still need to intelligently make decisions on what is supported by the OS. For example balloon
  91. tray icons are only supported on Shell v5 (nominally Windows 2000 or later). CTrayNotifyIcon
  92. will ASSERT if for example calls are made to it to create a balloon tray icon on operating
  93. systems < Windows 2000.
  94. PJN / 04-07-2006 1. Fixed a bug where the menu may pop up a second time after a menu item is chosen on
  95. Windows 2000. The problem was tracked down to the code in CTrayNotifyIcon::OnTrayNotification.
  96. During testing of this bug, I was unable to get a workable solution using the new shell
  97. messages of WM_CONTEXTMENU, NIN_KEYSELECT & NIN_SELECT on Windows 2000 and Windows XP.
  98. This means that the code in CTrayNotifyIcon::OnTrayNotification uses the old way of handling
  99. notifications (WM_RBUTTDOWN*). This does mean that by default, client apps which use the
  100. CTrayNotifyIcon class will not support the new keyboard and mouse semantics for tray icons
  101. (IMHO this is no big loss!). Client code is of course free to handle their own notifications.
  102. If you go down this route then I would advise you to thoroughly test your application on
  103. Windows 2000 and Windows XP as my testing has shown that there is significant differences in
  104. how tray icons handle their messaging on these 2 operating systems. Thanks to Edwin Geng for
  105. reporting this issue.
  106. 2. Class now displays the menu based on the current message's screen coordinates, rather than
  107. the current cursor screen coordinates.
  108. 3. Fixed bug in sample app where if the about dialog is already up and it is reactivated
  109. from the tray menu, it did not bring itself into the foreground
  110. PJN / 06-07-2006 1. Reverted the change made for v1.53 where the screen coordinates used to show the context
  111. menu use the current message's screen coordinates. Instead the pre v1.53 mechanism which
  112. uses the current cursor's screen coordinates is now used. Thanks to Itamar Syn-Hershko for
  113. reporting this issue.
  114. PJN / 19-07-2006 1. The default menu item can now be customized via SetDefaultMenuItem and
  115. GetDefaultMenuItem. Thanks to Mikhail Bykanov for suggesting this nice update.
  116. 2. Optimized CTrayNotifyIcon constructor code
  117. PJN / 19-08-2005 1. Updated the code to operate independent of MFC if so desired. This requires WTL which is an
  118. open source library extension for ATL to provide UI support along the lines of MFC. Thanks to
  119. zhiguo zhao for providing this very nice addition.
  120. PJN / 15-09-2006 1. Fixed a bug where WM_DESTROY messages were not been handled correctly for the top level window
  121. which the CTrayIconHooker class subclasses in order to handle the tray resurrection message,
  122. the animation timers and auto destroying of the icons when the top level window is destroyed.
  123. Thanks to Edward Livingston for reporting this bug.
  124. 2. Fixed a bug where the tray icons were not being recreated correctly when we receive the
  125. "TaskbarCreated" when Explorer is restarted. Thanks to Nuno Esculcas for reporting this bug.
  126. 3. Split the functionality of hiding versus deleting and showing versus creating of the tray
  127. icon into 4 separate functions, namely Delete(), Create(), Hide() and Show(). Note that Hide
  128. and Show functionality is only available on Shell v5 or later.
  129. 4. Fixed an issue with recreation of tray icons which use a dynamic icon created from a bitmap
  130. (through the use of BitmapToIcon).
  131. 5. CTrayNotifyIcon::LoadIconResource now loads up an icon as a shared icon resource using
  132. LoadImage. This should avoid resource leaks using this function.
  133. PJN / 15-06-2007 1. Updated copyright messages.
  134. 2. If the code detects that MFC is not included in the project, the code uses the standard
  135. preprocessor define "_CSTRING_NS" to declare the string class to use rather than explicitly
  136. using WTL::CString. Thanks to Krzysztof Suszka for reporting this issue.
  137. 3. Updated sample app to compile cleanly on VC 2005.
  138. 4. Addition of a "BOOL bShow" to all the Create methods. This allows you to create an icon
  139. without actually showing it. This avoids the flicker which previously occurred if you created
  140. the icon and then immediately hid the icon. Thanks to Krzysztof Suszka for providing this
  141. suggestion.
  142. 5. Demo app now initially creates the first icon as hidden for demonstration purposes.
  143. 6. Added support for NIIF_LARGE_ICON. This Vista only feature allows you to create a large
  144. balloon icon.
  145. 7. Added support for NIF_REALTIME. This Vista only flag allows you to specify not to bother
  146. showing the balloon if it is delayed due to the presence of an existing balloon.
  147. 8. Added support for NOTIFYICONDATA::hBalloonIcon. This Vista only feature allows you to
  148. create a user specified balloon icon which is different to the actual tray icon.
  149. 9. LoadIconResource method now includes support for loading large icons and has been renamed
  150. to simply LoadIcon. Also two overridden versions of this method have been provided which allow
  151. the hInstance resource ID to be specified to load the icon from.
  152. 10. Reworked the internal code to CTrayNotifyIcon which detects the shell version.
  153. 11. Updated the tray icon text in the demo app to better demonstrate the features of the class.
  154. 12. Updated the WTL sample to be consistent with the MFC sample code
  155. 13. Updated comments in documentation about usage of the Platform SDK.
  156. PJN / 13-10-2007 1. Subclassing of the top level window is now not down internally by the CTrayNotifyIcon class
  157. using the CTrayIconHooker class. Instead now a hidden top level window is created for each tray
  158. icon you create and these look after handling the tray resurrection and animated icon timer
  159. messages. This refactoring of the internals of the class now also fixes a bug where an application
  160. which creates multiples tray icons would only get one icon recreated when the tray resurrection
  161. message was received. Thanks to Steven Dwyer for prompting this update.
  162. 2. Updated the MFC sample app to correctly initialize ATL for VC 6
  163. PJN / 12-03-2008 1. Updated copyright details
  164. 2. Fixed a bug in SetBalloonDetails where the code did not set the flag NIF_ICON if a user defined
  165. icon was being set. Thanks to "arni" for reporting this bug.
  166. 3. Updated the sample app to clean compile on VC 2008
  167. PJN / 22-06-2008 1. Code now compiles cleanly using Code Analysis (/analyze)
  168. 2. Updated code to compile correctly using _ATL_CSTRING_EXPLICIT_CONSTRUCTORS define
  169. 3. Removed VC 6 style AppWizard comments from the code.
  170. 4. The code now only supports VC 2005 or later.
  171. PJN / 10-04-2010 1. Updated copyright details.
  172. 2. Updated the project settings to more modern default values.
  173. 3. Updated the WTL version of LoadIcon to use the more modern ModuleHelper class from WTL to get
  174. the resource instance. Thanks to "Yarp" for reporting this issue.
  175. 4. The class now has support for the Windows 7 "NIIF_RESPECT_QUIET_TIME" flag. This value can be
  176. set via the new "bQuietTime" parameter to the Create method.
  177. 5. Updated the code which does version detection of the Shell version
  178. PJN / 10-07-2010 1. Updated the sample app to compile cleanly on VS 2010.
  179. 2. Fixed a bug in CTrayNotifyIcon::Delete where the code would ASSERT if the tray notify icon was
  180. never actually created. Thanks to "trophim" for reporting this bug.
  181. PJN / 06-11-2010 1. Minor update to code in SetTooltipText to code which handles unreferenced variable compiler
  182. warning
  183. 2. Implemented a GetTooltipMaxSize method which reports the maximum size which the tooltip can be
  184. for a tray icon. Thanks to Geert van Horrik for this nice addition
  185. 3. All places which copy text to the underlying NOTIFYICONDATA now use the _TRUNCATE parameter in
  186. their call to the Safe CRT runtime. This change in behaviour means that client apps will no longer
  187. crash if they supply data larger than this Windows structure can accommadate. Thanks to Geert van
  188. Horrik for prompting this update.
  189. 4. All calls to sizeof(struct)/sizeof(first element) have been replaced with _countof
  190. 5. Fixed a linker error when compiling the WTL sample app in release mode.
  191. PJN / 26-11-2010 1. Minor update to use DBG_UNREFERENCED_LOCAL_VARIABLE macro. Thanks to Jukka Ojanen for prompting this
  192. update.
  193. PJN / 27-04-2016 1. Updated copyright details.
  194. 2. Updated the code to clean compile on VC 2012 - VC 2015.
  195. 3. Removed support for CTRAYNOTIFYICON_NOWIN2K preprocessor macro
  196. 4. Removed various redefines of ShellApi.h constants from the code
  197. 5. Added SAL annotations to all the code.
  198. 6. Reworked the definition of the string class to now use a typedef internal to the CTrayNotifyIcon
  199. class.
  200. 7. Updated CTrayNotifyIcon::OnTrayNotification to handle NOTIFYICON_VERSION_4 style notifications.
  201. 8. Reworked the internal storage of the animation icons to use ATL::CHeapPtr
  202. Copyright (c) 1997 - 2016 by PJ Naughter (Web: www.naughter.com, Email: [email protected])
  203. All rights reserved.
  204. Copyright / Usage Details:
  205. You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise)
  206. when your product is released in binary form. You are allowed to modify the source code in any way you want
  207. except you cannot modify the copyright details at the top of each module. If you want to distribute source
  208. code with your application, then you are only allowed to distribute versions released by the author. This is
  209. to maintain a single distribution point for the source code.
  210. */
  211. ///////////////////////////////// Includes //////////////////////////////////
  212. #include "stdafx.h"
  213. #include "NTray.h"
  214. #ifndef _INC_SHELLAPI
  215. #pragma message("To avoid this message, please put ShellApi.h in your pre compiled header (normally stdafx.h)")
  216. #include <ShellApi.h>
  217. #endif //#ifndef _INC_SHELLAPI
  218. ///////////////////////////////// Macros /////////////////////////////////////
  219. #ifdef _AFX
  220. #ifdef _DEBUG
  221. #define new DEBUG_NEW
  222. #endif //#ifdef _DEBUG
  223. #endif //#ifdef _AFX
  224. #ifndef NIF_REALTIME
  225. #define NIF_REALTIME 0x00000040
  226. #endif //#ifndef NIF_REALTIME
  227. #ifndef NIIF_LARGE_ICON
  228. #define NIIF_LARGE_ICON 0x00000020
  229. #endif //#ifndef NIIF_LARGE_ICON
  230. #ifndef NIIF_RESPECT_QUIET_TIME
  231. #define NIIF_RESPECT_QUIET_TIME 0x00000080
  232. #endif //#ifndef NIIF_RESPECT_QUIET_TIME
  233. ///////////////////////////////// Implementation //////////////////////////////
  234. const UINT wm_TaskbarCreated = RegisterWindowMessage(_T("TaskbarCreated"));
  235. CTrayNotifyIcon::CTrayNotifyIcon() : m_bCreated(FALSE),
  236. m_bHidden(FALSE),
  237. m_pNotificationWnd(NULL),
  238. m_bDefaultMenuItemByPos(TRUE),
  239. m_nDefaultMenuItem(0),
  240. m_hDynamicIcon(NULL),
  241. m_ShellVersion(Version4), //Assume version 4 of the shell
  242. m_nNumIcons(0),
  243. m_nTimerID(0),
  244. m_nCurrentIconIndex(0),
  245. m_nTooltipMaxSize(-1)
  246. {
  247. typedef HRESULT (CALLBACK DLLGETVERSION)(DLLVERSIONINFO*);
  248. typedef DLLGETVERSION* LPDLLGETVERSION;
  249. //Try to get the details with DllGetVersion
  250. HMODULE hShell32 = GetModuleHandle(_T("SHELL32.DLL"));
  251. if (hShell32 != NULL)
  252. {
  253. LPDLLGETVERSION lpfnDllGetVersion = reinterpret_cast<LPDLLGETVERSION>(GetProcAddress(hShell32, "DllGetVersion"));
  254. if (lpfnDllGetVersion != NULL)
  255. {
  256. DLLVERSIONINFO vinfo;
  257. vinfo.cbSize = sizeof(DLLVERSIONINFO);
  258. if (SUCCEEDED(lpfnDllGetVersion(&vinfo)))
  259. {
  260. if ((vinfo.dwMajorVersion > 6) || (vinfo.dwMajorVersion == 6 && vinfo.dwMinorVersion > 0))
  261. m_ShellVersion = Version7;
  262. else if (vinfo.dwMajorVersion == 6)
  263. {
  264. if (vinfo.dwBuildNumber >= 6000)
  265. m_ShellVersion = VersionVista;
  266. else
  267. m_ShellVersion = Version6;
  268. }
  269. else if (vinfo.dwMajorVersion >= 5)
  270. m_ShellVersion = Version5;
  271. }
  272. }
  273. }
  274. memset(&m_NotifyIconData, 0, sizeof(m_NotifyIconData));
  275. m_NotifyIconData.cbSize = GetNOTIFYICONDATASizeForOS();
  276. }
  277. CTrayNotifyIcon::~CTrayNotifyIcon()
  278. {
  279. //Delete the tray icon
  280. Delete(TRUE);
  281. //Free up any dynamic icon we may have
  282. if (m_hDynamicIcon != NULL)
  283. {
  284. DestroyIcon(m_hDynamicIcon);
  285. m_hDynamicIcon = NULL;
  286. }
  287. }
  288. BOOL CTrayNotifyIcon::Delete(_In_ BOOL bCloseHelperWindow)
  289. {
  290. //What will be the return value from this function (assume the best)
  291. BOOL bSuccess = TRUE;
  292. if (m_bCreated)
  293. {
  294. m_NotifyIconData.uFlags = 0;
  295. bSuccess = Shell_NotifyIcon(NIM_DELETE, reinterpret_cast<PNOTIFYICONDATA>(&m_NotifyIconData));
  296. m_bCreated = FALSE;
  297. }
  298. //Close the helper window if requested to do so
  299. if (bCloseHelperWindow && IsWindow())
  300. SendMessage(WM_CLOSE);
  301. return bSuccess;
  302. }
  303. BOOL CTrayNotifyIcon::Create(_In_ BOOL bShow)
  304. {
  305. m_NotifyIconData.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
  306. if (!bShow)
  307. {
  308. ATLASSERT(m_ShellVersion >= Version5); //Only supported on Shell v5 or later
  309. m_NotifyIconData.uFlags |= NIF_STATE;
  310. m_NotifyIconData.dwState = NIS_HIDDEN;
  311. m_NotifyIconData.dwStateMask = NIS_HIDDEN;
  312. }
  313. BOOL bSuccess = Shell_NotifyIcon(NIM_ADD, reinterpret_cast<PNOTIFYICONDATA>(&m_NotifyIconData));
  314. if (bSuccess)
  315. {
  316. m_bCreated = TRUE;
  317. if (!bShow)
  318. m_bHidden = TRUE;
  319. }
  320. return bSuccess;
  321. }
  322. BOOL CTrayNotifyIcon::Hide()
  323. {
  324. //Validate our parameters
  325. ATLASSERT(m_ShellVersion >= Version5); //Only supported on Shell v5 or later
  326. // ATLASSERT(!m_bHidden); //Only makes sense to hide the icon if it is not already hidden
  327. m_NotifyIconData.uFlags = NIF_STATE;
  328. m_NotifyIconData.dwState = NIS_HIDDEN;
  329. m_NotifyIconData.dwStateMask = NIS_HIDDEN;
  330. BOOL bSuccess = Shell_NotifyIcon(NIM_MODIFY, reinterpret_cast<PNOTIFYICONDATA>(&m_NotifyIconData));
  331. if (bSuccess)
  332. m_bHidden = TRUE;
  333. return bSuccess;
  334. }
  335. BOOL CTrayNotifyIcon::Show()
  336. {
  337. //Validate our parameters
  338. ATLASSERT(m_ShellVersion >= Version5); //Only supported on Shell v5 or later
  339. // ATLASSERT(m_bHidden); //Only makes sense to show the icon if it has been previously hidden
  340. ATLASSERT(m_bCreated);
  341. m_NotifyIconData.uFlags = NIF_STATE;
  342. m_NotifyIconData.dwState = 0;
  343. m_NotifyIconData.dwStateMask = NIS_HIDDEN;
  344. BOOL bSuccess = Shell_NotifyIcon(NIM_MODIFY, reinterpret_cast<PNOTIFYICONDATA>(&m_NotifyIconData));
  345. if (bSuccess)
  346. m_bHidden = FALSE;
  347. return bSuccess;
  348. }
  349. void CTrayNotifyIcon::SetMenu(_In_ HMENU hMenu, UINT menuId)
  350. {
  351. m_Menu.DestroyMenu();
  352. if (menuId != 0)
  353. {
  354. if (!m_Menu.LoadMenu(menuId))
  355. {
  356. ATLASSERT(FALSE);
  357. return;
  358. }
  359. }
  360. else
  361. {
  362. m_Menu.Attach(hMenu);
  363. }
  364. #ifdef _AFX
  365. CMenu* pSubMenu = m_Menu.GetSubMenu(0);
  366. ATLASSUME(pSubMenu != NULL); //Your menu resource has been designed incorrectly
  367. //Make the specified menu item the default (bold font)
  368. pSubMenu->SetDefaultItem(m_nDefaultMenuItem, m_bDefaultMenuItemByPos);
  369. #else
  370. CMenuHandle subMenu = m_Menu.GetSubMenu(0);
  371. ATLASSERT(subMenu.IsMenu()); //Your menu resource has been designed incorrectly
  372. //Make the specified menu item the default (bold font)
  373. subMenu.SetMenuDefaultItem(m_nDefaultMenuItem, m_bDefaultMenuItemByPos);
  374. #endif //#ifdef _AFX
  375. }
  376. CMenu& CTrayNotifyIcon::GetMenu()
  377. {
  378. return m_Menu;
  379. }
  380. void CTrayNotifyIcon::SetDefaultMenuItem(_In_ UINT uItem, _In_ BOOL fByPos)
  381. {
  382. m_nDefaultMenuItem = uItem;
  383. m_bDefaultMenuItemByPos = fByPos;
  384. //Also update in the live menu if it is present
  385. if (m_Menu.operator HMENU())
  386. {
  387. #ifdef _AFX
  388. CMenu* pSubMenu = m_Menu.GetSubMenu(0);
  389. ATLASSUME(pSubMenu != NULL); //Your menu resource has been designed incorrectly
  390. pSubMenu->SetDefaultItem(m_nDefaultMenuItem, m_bDefaultMenuItemByPos);
  391. #else
  392. CMenuHandle subMenu = m_Menu.GetSubMenu(0);
  393. ATLASSERT(subMenu.IsMenu()); //Your menu resource has been designed incorrectly
  394. subMenu.SetMenuDefaultItem(m_nDefaultMenuItem, m_bDefaultMenuItemByPos);
  395. #endif //#ifdef _AFX
  396. }
  397. }
  398. #ifdef _AFX
  399. BOOL CTrayNotifyIcon::Create(_In_ CWnd* pNotifyWnd, _In_ UINT uID, _In_ LPCTSTR pszTooltipText, _In_ HICON hIcon, _In_ UINT nNotifyMessage, _In_ UINT uMenuID, _In_ BOOL bShow)
  400. #else
  401. BOOL CTrayNotifyIcon::Create(_In_ CWindow* pNotifyWnd, _In_ UINT uID, _In_ LPCTSTR pszTooltipText, _In_ HICON hIcon, _In_ UINT nNotifyMessage, _In_ UINT uMenuID, _In_ BOOL bShow)
  402. #endif //#ifdef _AFX
  403. {
  404. //Validate our parameters
  405. ATLASSUME((pNotifyWnd != NULL) && ::IsWindow(pNotifyWnd->operator HWND()));
  406. #ifdef _DEBUG
  407. if (m_ShellVersion >= Version5) //If on Shell v5 or higher, then use the larger size tooltip
  408. {
  409. NOTIFYICONDATA_2 dummy;
  410. ATLASSERT(_tcslen(pszTooltipText) < _countof(dummy.szTip));
  411. DBG_UNREFERENCED_LOCAL_VARIABLE(dummy);
  412. }
  413. else
  414. {
  415. NOTIFYICONDATA_1 dummy;
  416. ATLASSERT(_tcslen(pszTooltipText) < _countof(dummy.szTip));
  417. DBG_UNREFERENCED_LOCAL_VARIABLE(dummy);
  418. }
  419. #endif //#ifdef _DEBUG
  420. ATLASSERT(hIcon != NULL);
  421. ATLASSERT(nNotifyMessage >= WM_USER); //Make sure we avoid conflict with other messages
  422. //Load up the menu resource which is to be used as the context menu
  423. if (!m_Menu.LoadMenu(uMenuID == 0 ? uID : uMenuID))
  424. {
  425. ATLASSERT(FALSE);
  426. return FALSE;
  427. }
  428. #ifdef _AFX
  429. CMenu* pSubMenu = m_Menu.GetSubMenu(0);
  430. if (pSubMenu == NULL)
  431. {
  432. ATLASSERT(FALSE); //Your menu resource has been designed incorrectly
  433. return FALSE;
  434. }
  435. //Make the specified menu item the default (bold font)
  436. pSubMenu->SetDefaultItem(m_nDefaultMenuItem, m_bDefaultMenuItemByPos);
  437. #else
  438. CMenuHandle subMenu = m_Menu.GetSubMenu(0);
  439. if (!subMenu.IsMenu())
  440. {
  441. ATLASSERT(FALSE); //Your menu resource has been designed incorrectly
  442. return FALSE;
  443. }
  444. subMenu.SetMenuDefaultItem(m_nDefaultMenuItem, m_bDefaultMenuItemByPos);
  445. #endif //#ifdef _AFX
  446. //Create the helper window
  447. if (!CreateHelperWindow())
  448. return FALSE;
  449. //Call the Shell_NotifyIcon function
  450. m_pNotificationWnd = pNotifyWnd;
  451. m_NotifyIconData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
  452. m_NotifyIconData.hWnd = pNotifyWnd->operator HWND();
  453. m_NotifyIconData.uID = uID;
  454. m_NotifyIconData.uCallbackMessage = nNotifyMessage;
  455. m_NotifyIconData.hIcon = hIcon;
  456. _tcsncpy_s(m_NotifyIconData.szTip, _countof(m_NotifyIconData.szTip), pszTooltipText, _TRUNCATE);
  457. if (!bShow)
  458. {
  459. ATLASSERT(m_ShellVersion >= Version5); //Only supported on Shell v5 or later
  460. m_NotifyIconData.uFlags |= NIF_STATE;
  461. m_NotifyIconData.dwState = NIS_HIDDEN;
  462. m_NotifyIconData.dwStateMask = NIS_HIDDEN;
  463. }
  464. m_bCreated = Shell_NotifyIcon(NIM_ADD, reinterpret_cast<PNOTIFYICONDATA>(&m_NotifyIconData));
  465. if (m_bCreated)
  466. {
  467. if (!bShow)
  468. m_bHidden = TRUE;
  469. //Turn on Shell v5 style behaviour if supported
  470. if (m_ShellVersion >= Version5)
  471. SetVersion(NOTIFYICON_VERSION);
  472. }
  473. return m_bCreated;
  474. }
  475. BOOL CTrayNotifyIcon::SetVersion(_In_ UINT uVersion)
  476. {
  477. //Validate our parameters
  478. ATLASSERT(m_ShellVersion >= Version5); //Only supported on Shell v5 or later
  479. //Call the Shell_NotifyIcon function
  480. m_NotifyIconData.uVersion = uVersion;
  481. return Shell_NotifyIcon(NIM_SETVERSION, reinterpret_cast<PNOTIFYICONDATA>(&m_NotifyIconData));
  482. }
  483. HICON CTrayNotifyIcon::BitmapToIcon(_In_ CBitmap* pBitmap)
  484. {
  485. //Validate our parameters
  486. ATLASSUME(pBitmap != NULL);
  487. //Get the width and height of a small icon
  488. int w = GetSystemMetrics(SM_CXSMICON);
  489. int h = GetSystemMetrics(SM_CYSMICON);
  490. //Create a 0 mask
  491. int nMaskSize = h*(w/8);
  492. ATL::CHeapPtr<BYTE> pMask;
  493. if (!pMask.Allocate(nMaskSize))
  494. return NULL;
  495. memset(pMask.m_pData, 0, nMaskSize);
  496. //Create a mask bitmap
  497. CBitmap maskBitmap;
  498. #ifdef _AFX
  499. BOOL bSuccess = maskBitmap.CreateBitmap(w, h, 1, 1, pMask.m_pData);
  500. #else
  501. maskBitmap.CreateBitmap(w, h, 1, 1, pMask.m_pData);
  502. BOOL bSuccess = !maskBitmap.IsNull();
  503. #endif //#ifdef _AFX
  504. //Handle the error
  505. if (!bSuccess)
  506. return NULL;
  507. //Create an ICON base on the bitmap just created
  508. ICONINFO iconInfo;
  509. iconInfo.fIcon = TRUE;
  510. iconInfo.xHotspot = 0;
  511. iconInfo.yHotspot = 0;
  512. iconInfo.hbmMask = maskBitmap;
  513. iconInfo.hbmColor = *pBitmap;
  514. return CreateIconIndirect(&iconInfo);
  515. }
  516. #ifdef _AFX
  517. BOOL CTrayNotifyIcon::Create(_In_ CWnd* pNotifyWnd, _In_ UINT uID, _In_ LPCTSTR pszTooltipText, _In_ CBitmap* pBitmap, _In_ UINT nNotifyMessage, _In_ UINT uMenuID, _In_ BOOL bShow)
  518. #else
  519. BOOL CTrayNotifyIcon::Create(_In_ CWindow* pNotifyWnd, _In_ UINT uID, _In_ LPCTSTR pszTooltipText, _In_ CBitmap* pBitmap, _In_ UINT nNotifyMessage, _In_ UINT uMenuID, _In_ BOOL bShow)
  520. #endif //#ifdef _AFX
  521. {
  522. //Convert the bitmap to an Icon
  523. if (m_hDynamicIcon != NULL)
  524. DestroyIcon(m_hDynamicIcon);
  525. m_hDynamicIcon = BitmapToIcon(pBitmap);
  526. //Pass the buck to the other function to do the work
  527. return Create(pNotifyWnd, uID, pszTooltipText, m_hDynamicIcon, nNotifyMessage, uMenuID, bShow);
  528. }
  529. #ifdef _AFX
  530. BOOL CTrayNotifyIcon::Create(_In_ CWnd* pNotifyWnd, _In_ UINT uID, _In_ LPCTSTR pszTooltipText, _In_ HICON* phIcons, _In_ int nNumIcons, _In_ DWORD dwDelay, _In_ UINT nNotifyMessage, _In_ UINT uMenuID, _In_ BOOL bShow)
  531. #else
  532. BOOL CTrayNotifyIcon::Create(_In_ CWindow* pNotifyWnd, _In_ UINT uID, _In_ LPCTSTR pszTooltipText, _In_ HICON* phIcons, _In_ int nNumIcons, _In_ DWORD dwDelay, _In_ UINT nNotifyMessage, _In_ UINT uMenuID, _In_ BOOL bShow)
  533. #endif //#ifdef _AFX
  534. {
  535. //Validate our parameters
  536. ATLASSUME(phIcons != NULL);
  537. ATLASSERT(nNumIcons >= 2); //must be using at least 2 icons if you are using animation
  538. ATLASSERT(dwDelay);
  539. //let the normal Create function do its stuff
  540. BOOL bSuccess = Create(pNotifyWnd, uID, pszTooltipText, phIcons[0], nNotifyMessage, uMenuID, bShow);
  541. if (bSuccess)
  542. {
  543. //Start the animation
  544. bSuccess = StartAnimation(phIcons, nNumIcons, dwDelay);
  545. }
  546. return bSuccess;
  547. }
  548. #ifdef _AFX
  549. BOOL CTrayNotifyIcon::Create(_In_ CWnd* pNotifyWnd, _In_ UINT uID, _In_ LPCTSTR pszTooltipText, _In_ LPCTSTR pszBalloonText, _In_ LPCTSTR pszBalloonCaption, _In_ UINT nTimeout, _In_ BalloonStyle style, _In_ HICON hIcon, _In_ UINT nNotifyMessage, _In_ UINT uMenuID, _In_ BOOL bNoSound, _In_ BOOL bLargeIcon, _In_ BOOL bRealtime, _In_opt_ HICON hBalloonIcon, _In_ BOOL bQuietTime, _In_ BOOL bShow)
  550. #else
  551. BOOL CTrayNotifyIcon::Create(_In_ CWindow* pNotifyWnd, _In_ UINT uID, _In_ LPCTSTR pszTooltipText, _In_ LPCTSTR pszBalloonText, _In_ LPCTSTR pszBalloonCaption, _In_ UINT nTimeout, _In_ BalloonStyle style, _In_ HICON hIcon, _In_ UINT nNotifyMessage, _In_ UINT uMenuID, _In_ BOOL bNoSound, _In_ BOOL bLargeIcon, _In_ BOOL bRealtime, _In_opt_ HICON hBalloonIcon, _In_ BOOL bQuietTime, _In_ BOOL bShow)
  552. #endif //#ifdef _AFX
  553. {
  554. //Validate our parameters
  555. ATLASSUME((pNotifyWnd != NULL) && ::IsWindow(pNotifyWnd->operator HWND()));
  556. ATLASSERT(m_ShellVersion >= Version5); //Only supported on Shell v5 or later
  557. #ifdef _DEBUG
  558. NOTIFYICONDATA_2 dummy;
  559. ATLASSERT(_tcslen(pszTooltipText) < _countof(dummy.szTip));
  560. ATLASSERT(_tcslen(pszBalloonText) < _countof(dummy.szInfo));
  561. ATLASSERT(_tcslen(pszBalloonCaption) < _countof(dummy.szInfoTitle));
  562. ATLASSERT(hIcon);
  563. ATLASSERT(nNotifyMessage >= WM_USER); //Make sure we avoid conflict with other messages
  564. DBG_UNREFERENCED_LOCAL_VARIABLE(dummy);
  565. #endif //#ifdef _DEBUG
  566. //Load up the menu resource which is to be used as the context menu
  567. if (!m_Menu.LoadMenu(uMenuID == 0 ? uID : uMenuID))
  568. {
  569. ATLASSERT(FALSE);
  570. return FALSE;
  571. }
  572. #ifdef _AFX
  573. CMenu* pSubMenu = m_Menu.GetSubMenu(0);
  574. if (pSubMenu == NULL)
  575. {
  576. ATLASSERT(FALSE); //Your menu resource has been designed incorrectly
  577. return FALSE;
  578. }
  579. //Make the specified menu item the default (bold font)
  580. pSubMenu->SetDefaultItem(m_nDefaultMenuItem, m_bDefaultMenuItemByPos);
  581. #else
  582. CMenuHandle subMenu = m_Menu.GetSubMenu(0);
  583. if (!subMenu.IsMenu())
  584. {
  585. ATLASSERT(FALSE); //Your menu resource has been designed incorrectly
  586. return FALSE;
  587. }
  588. //Make the specified menu item the default (bold font)
  589. subMenu.SetMenuDefaultItem(m_nDefaultMenuItem, m_bDefaultMenuItemByPos);
  590. #endif //#ifdef _AFX
  591. //Create the helper window
  592. if (!CreateHelperWindow())
  593. return FALSE;
  594. //Call the Shell_NotifyIcon function
  595. m_pNotificationWnd = pNotifyWnd;
  596. m_NotifyIconData.hWnd = pNotifyWnd->operator HWND();
  597. m_NotifyIconData.uID = uID;
  598. m_NotifyIconData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP | NIF_INFO;
  599. m_NotifyIconData.uCallbackMessage = nNotifyMessage;
  600. m_NotifyIconData.hIcon = hIcon;
  601. _tcsncpy_s(m_NotifyIconData.szTip, _countof(m_NotifyIconData.szTip), pszTooltipText, _TRUNCATE);
  602. _tcsncpy_s(m_NotifyIconData.szInfo, _countof(m_NotifyIconData.szInfo), pszBalloonText, _TRUNCATE);
  603. _tcsncpy_s(m_NotifyIconData.szInfoTitle, _countof(m_NotifyIconData.szInfoTitle), pszBalloonCaption, _TRUNCATE);
  604. m_NotifyIconData.uTimeout = nTimeout;
  605. switch (style)
  606. {
  607. case Warning:
  608. {
  609. m_NotifyIconData.dwInfoFlags = NIIF_WARNING;
  610. break;
  611. }
  612. case Error:
  613. {
  614. m_NotifyIconData.dwInfoFlags = NIIF_ERROR;
  615. break;
  616. }
  617. case Info:
  618. {
  619. m_NotifyIconData.dwInfoFlags = NIIF_INFO;
  620. break;
  621. }
  622. case None:
  623. {
  624. m_NotifyIconData.dwInfoFlags = NIIF_NONE;
  625. break;
  626. }
  627. case User:
  628. {
  629. if (hBalloonIcon != NULL)
  630. {
  631. ATLASSERT(m_ShellVersion >= VersionVista);
  632. m_NotifyIconData.hBalloonIcon = hBalloonIcon;
  633. }
  634. else
  635. {
  636. ATLASSERT(hIcon != NULL); //You forget to provide a user icon
  637. }
  638. m_NotifyIconData.dwInfoFlags = NIIF_USER;
  639. break;
  640. }
  641. default:
  642. {
  643. ATLASSERT(FALSE);
  644. break;
  645. }
  646. }
  647. if (bNoSound)
  648. m_NotifyIconData.dwInfoFlags |= NIIF_NOSOUND;
  649. if (bLargeIcon)
  650. {
  651. ATLASSERT(m_ShellVersion >= VersionVista); //Only supported on Vista Shell
  652. m_NotifyIconData.dwInfoFlags |= NIIF_LARGE_ICON;
  653. }
  654. if (bRealtime)
  655. {
  656. ATLASSERT(m_ShellVersion >= VersionVista); //Only supported on Vista Shell
  657. m_NotifyIconData.uFlags |= NIF_REALTIME;
  658. }
  659. if (!bShow)
  660. {
  661. ATLASSERT(m_ShellVersion >= Version5); //Only supported on Shell v5 or later
  662. m_NotifyIconData.uFlags |= NIF_STATE;
  663. m_NotifyIconData.dwState = NIS_HIDDEN;
  664. m_NotifyIconData.dwStateMask = NIS_HIDDEN;
  665. }
  666. if (bQuietTime)
  667. {
  668. ATLASSERT(m_ShellVersion >= Version7); //Only supported on Windows 7 Shell
  669. m_NotifyIconData.dwInfoFlags |= NIIF_RESPECT_QUIET_TIME;
  670. }
  671. m_bCreated = Shell_NotifyIcon(NIM_ADD, reinterpret_cast<PNOTIFYICONDATA>(&m_NotifyIconData));
  672. if (m_bCreated)
  673. {
  674. if (!bShow)
  675. m_bHidden = TRUE;
  676. //Turn on Shell v5 tray icon behaviour
  677. SetVersion(NOTIFYICON_VERSION);
  678. }
  679. return m_bCreated;
  680. }
  681. #ifdef _AFX
  682. BOOL CTrayNotifyIcon::Create(_In_ CWnd* pNotifyWnd, _In_ UINT uID, _In_ LPCTSTR pszTooltipText, _In_ LPCTSTR pszBalloonText, _In_ LPCTSTR pszBalloonCaption, _In_ UINT nTimeout, _In_ BalloonStyle style, _In_ CBitmap* pBitmap, _In_ UINT nNotifyMessage, _In_ UINT uMenuID, _In_ BOOL bNoSound, _In_ BOOL bLargeIcon, _In_ BOOL bRealtime, _In_opt_ HICON hBalloonIcon, _In_ BOOL bQuietTime, _In_ BOOL bShow)
  683. #else
  684. BOOL CTrayNotifyIcon::Create(_In_ CWindow* pNotifyWnd, _In_ UINT uID, _In_ LPCTSTR pszTooltipText, _In_ LPCTSTR pszBalloonText, _In_ LPCTSTR pszBalloonCaption, _In_ UINT nTimeout, _In_ BalloonStyle style, _In_ CBitmap* pBitmap, _In_ UINT nNotifyMessage, _In_ UINT uMenuID, _In_ BOOL bNoSound, _In_ BOOL bLargeIcon, _In_ BOOL bRealtime, _In_opt_ HICON hBalloonIcon, _In_ BOOL bQuietTime, _In_ BOOL bShow)
  685. #endif //#ifdef _AFX
  686. {
  687. //Convert the bitmap to an ICON
  688. if (m_hDynamicIcon != NULL)
  689. DestroyIcon(m_hDynamicIcon);
  690. m_hDynamicIcon = BitmapToIcon(pBitmap);
  691. //Pass the buck to the other function to do the work
  692. return Create(pNotifyWnd, uID, pszTooltipText, pszBalloonText, pszBalloonCaption, nTimeout, style, m_hDynamicIcon, nNotifyMessage, uMenuID, bNoSound, bLargeIcon, bRealtime, hBalloonIcon, bQuietTime, bShow);
  693. }
  694. #ifdef _AFX
  695. BOOL CTrayNotifyIcon::Create(_In_ CWnd* pNotifyWnd, _In_ UINT uID, _In_ LPCTSTR pszTooltipText, _In_ LPCTSTR pszBalloonText, _In_ LPCTSTR pszBalloonCaption, _In_ UINT nTimeout, _In_ BalloonStyle style, _In_ HICON* phIcons, _In_ int nNumIcons, _In_ DWORD dwDelay, _In_ UINT nNotifyMessage, _In_ UINT uMenuID, _In_ BOOL bNoSound, _In_ BOOL bLargeIcon, _In_ BOOL bRealtime, _In_opt_ HICON hBalloonIcon, _In_ BOOL bQuietTime, _In_ BOOL bShow)
  696. #else
  697. BOOL CTrayNotifyIcon::Create(_In_ CWindow* pNotifyWnd, _In_ UINT uID, _In_ LPCTSTR pszTooltipText, _In_ LPCTSTR pszBalloonText, _In_ LPCTSTR pszBalloonCaption, _In_ UINT nTimeout, _In_ BalloonStyle style, _In_ HICON* phIcons, _In_ int nNumIcons, _In_ DWORD dwDelay, _In_ UINT nNotifyMessage, _In_ UINT uMenuID, _In_ BOOL bNoSound, _In_ BOOL bLargeIcon, _In_ BOOL bRealtime, _In_opt_ HICON hBalloonIcon, _In_ BOOL bQuietTime, _In_ BOOL bShow)
  698. #endif //#ifdef _AFX
  699. {
  700. //Validate our parameters
  701. ATLASSUME(phIcons != NULL);
  702. ATLASSERT(nNumIcons >= 2); //must be using at least 2 icons if you are using animation
  703. ATLASSERT(dwDelay);
  704. //let the normal Create function do its stuff
  705. BOOL bSuccess = Create(pNotifyWnd, uID, pszTooltipText, pszBalloonText, pszBalloonCaption, nTimeout, style, phIcons[0], nNotifyMessage, uMenuID, bNoSound, bLargeIcon, bRealtime, hBalloonIcon, bQuietTime, bShow);
  706. if (bSuccess)
  707. {
  708. //Start the animation
  709. bSuccess = StartAnimation(phIcons, nNumIcons, dwDelay);
  710. }
  711. return bSuccess;
  712. }
  713. BOOL CTrayNotifyIcon::SetBalloonDetails(_In_ LPCTSTR pszBalloonText, _In_ LPCTSTR pszBalloonCaption, _In_ BalloonStyle style, _In_ UINT nTimeout, _In_ HICON hUserIcon, _In_ BOOL bNoSound, _In_ BOOL bLargeIcon, _In_ BOOL bRealtime, _In_ HICON hBalloonIcon)
  714. {
  715. if (!m_bCreated)
  716. return FALSE;
  717. //Validate our parameters
  718. ATLASSERT(m_ShellVersion >= Version5); //Only supported on Shell v5 or later
  719. #ifdef _DEBUG
  720. NOTIFYICONDATA_2 dummy;
  721. ATLASSERT(_tcslen(pszBalloonText) < _countof(dummy.szInfo));
  722. ATLASSERT(_tcslen(pszBalloonCaption) < _countof(dummy.szInfoTitle));
  723. DBG_UNREFERENCED_LOCAL_VARIABLE(dummy);
  724. #endif //#ifdef _DEBUG
  725. //Call the Shell_NotifyIcon function
  726. m_NotifyIconData.uFlags = NIF_INFO;
  727. _tcsncpy_s(m_NotifyIconData.szInfo, _countof(m_NotifyIconData.szInfo), pszBalloonText, _TRUNCATE);
  728. _tcsncpy_s(m_NotifyIconData.szInfoTitle, _countof(m_NotifyIconData.szInfoTitle), pszBalloonCaption, _TRUNCATE);
  729. m_NotifyIconData.uTimeout = nTimeout;
  730. switch (style)
  731. {
  732. case Warning:
  733. {
  734. m_NotifyIconData.dwInfoFlags = NIIF_WARNING;
  735. break;
  736. }
  737. case Error:
  738. {
  739. m_NotifyIconData.dwInfoFlags = NIIF_ERROR;
  740. break;
  741. }
  742. case Info:
  743. {
  744. m_NotifyIconData.dwInfoFlags = NIIF_INFO;
  745. break;
  746. }
  747. case None:
  748. {
  749. m_NotifyIconData.dwInfoFlags = NIIF_NONE;
  750. break;
  751. }
  752. case User:
  753. {
  754. if (hBalloonIcon != NULL)
  755. {
  756. ATLASSERT(m_ShellVersion >= VersionVista);
  757. m_NotifyIconData.hBalloonIcon = hBalloonIcon;
  758. }
  759. else
  760. {
  761. ATLASSERT(hUserIcon != NULL); //You forget to provide a user icon
  762. m_NotifyIconData.uFlags |= NIF_ICON;
  763. m_NotifyIconData.hIcon = hUserIcon;
  764. }
  765. m_NotifyIconData.dwInfoFlags = NIIF_USER;
  766. break;
  767. }
  768. default:
  769. {
  770. ATLASSERT(FALSE);
  771. break;
  772. }
  773. }
  774. if (bNoSound)
  775. m_NotifyIconData.dwInfoFlags |= NIIF_NOSOUND;
  776. if (bLargeIcon)
  777. m_NotifyIconData.dwInfoFlags |= NIIF_LARGE_ICON;
  778. if (bRealtime)
  779. m_NotifyIconData.uFlags |= NIF_REALTIME;
  780. return Shell_NotifyIcon(NIM_MODIFY, reinterpret_cast<PNOTIFYICONDATA>(&m_NotifyIconData));
  781. }
  782. CTrayNotifyIcon::String CTrayNotifyIcon::GetBalloonText() const
  783. {
  784. //Validate our parameters
  785. ATLASSERT(m_ShellVersion >= Version5); //Only supported on Shell v5 or later
  786. String sText;
  787. if (m_bCreated)
  788. sText = m_NotifyIconData.szInfo;
  789. return sText;
  790. }
  791. CTrayNotifyIcon::String CTrayNotifyIcon::GetBalloonCaption() const
  792. {
  793. //Validate our parameters
  794. ATLASSERT(m_ShellVersion >= Version5); //Only supported on Shell v5 or later
  795. String sText;
  796. if (m_bCreated)
  797. sText = m_NotifyIconData.szInfoTitle;
  798. return sText;
  799. }
  800. UINT CTrayNotifyIcon::GetBalloonTimeout() const
  801. {
  802. //Validate our parameters
  803. ATLASSERT(m_ShellVersion >= Version5); //Only supported on Shell v5 or later
  804. UINT nTimeout = 0;
  805. if (m_bCreated)
  806. nTimeout = m_NotifyIconData.uTimeout;
  807. return nTimeout;
  808. }
  809. BOOL CTrayNotifyIcon::SetTooltipText(_In_ LPCTSTR pszTooltipText)
  810. {
  811. if (!m_bCreated)
  812. return FALSE;
  813. if (m_ShellVersion >= Version5) //Allow the larger size tooltip text if on Shell v5 or later
  814. {
  815. #ifdef _DEBUG
  816. NOTIFYICONDATA_2 dummy;
  817. ATLASSERT(_tcslen(pszTooltipText) < _countof(dummy.szTip));
  818. DBG_UNREFERENCED_LOCAL_VARIABLE(dummy);
  819. #endif //#ifdef _DEBUG
  820. }
  821. else
  822. {
  823. #ifdef _DEBUG
  824. NOTIFYICONDATA_1 dummy;
  825. ATLASSERT(_tcslen(pszTooltipText) < _countof(dummy.szTip));
  826. DBG_UNREFERENCED_LOCAL_VARIABLE(dummy);
  827. #endif //#ifdef _DEBUG
  828. }
  829. //Call the Shell_NotifyIcon function
  830. m_NotifyIconData.uFlags = NIF_TIP;
  831. _tcsncpy_s(m_NotifyIconData.szTip, _countof(m_NotifyIconData.szTip), pszTooltipText, _TRUNCATE);
  832. return Shell_NotifyIcon(NIM_MODIFY, reinterpret_cast<PNOTIFYICONDATA>(&m_NotifyIconData));
  833. }
  834. BOOL CTrayNotifyIcon::SetTooltipText(_In_ UINT nID)
  835. {
  836. String sToolTipText;
  837. if (!sToolTipText.LoadString(nID))
  838. return FALSE;
  839. //Let the other version of the function handle the rest
  840. return SetTooltipText(sToolTipText);
  841. }
  842. int CTrayNotifyIcon::GetTooltipMaxSize()
  843. {
  844. //Return the cached value if we have one
  845. if (m_nTooltipMaxSize != -1)
  846. return m_nTooltipMaxSize;
  847. //Otherwise calculate the maximum based on the shell version
  848. if (m_ShellVersion >= Version5)
  849. {
  850. NOTIFYICONDATA_2 dummy;
  851. m_nTooltipMaxSize = _countof(dummy.szTip) - 1; //The -1 is to allow size for the NULL terminator
  852. DBG_UNREFERENCED_LOCAL_VARIABLE(dummy);
  853. }
  854. else
  855. {
  856. NOTIFYICONDATA_1 dummy;
  857. m_nTooltipMaxSize = _countof(dummy.szTip) - 1; //The -1 is to allow size for the NULL terminator
  858. DBG_UNREFERENCED_LOCAL_VARIABLE(dummy);
  859. }
  860. return m_nTooltipMaxSize;
  861. }
  862. BOOL CTrayNotifyIcon::SetIcon(_In_ CBitmap* pBitmap)
  863. {
  864. //Convert the bitmap to an ICON
  865. if (m_hDynamicIcon != NULL)
  866. DestroyIcon(m_hDynamicIcon);
  867. m_hDynamicIcon = BitmapToIcon(pBitmap);
  868. //Pass the buck to the other function to do the work
  869. return SetIcon(m_hDynamicIcon);
  870. }
  871. BOOL CTrayNotifyIcon::SetIcon(_In_ HICON hIcon)
  872. {
  873. //Validate our parameters
  874. ATLASSERT(hIcon != NULL);
  875. if (!m_bCreated)
  876. return FALSE;
  877. //Since we are going to use one icon, stop any animation
  878. StopAnimation();
  879. //Call the Shell_NotifyIcon function
  880. m_NotifyIconData.uFlags = NIF_ICON;
  881. m_NotifyIconData.hIcon = hIcon;
  882. return Shell_NotifyIcon(NIM_MODIFY, reinterpret_cast<PNOTIFYICONDATA>(&m_NotifyIconData));
  883. }
  884. BOOL CTrayNotifyIcon::SetIcon(_In_ LPCTSTR lpIconName)
  885. {
  886. return SetIcon(LoadIcon(lpIconName));
  887. }
  888. BOOL CTrayNotifyIcon::SetIcon(_In_ UINT nIDResource)
  889. {
  890. return SetIcon(LoadIcon(nIDResource));
  891. }
  892. BOOL CTrayNotifyIcon::SetStandardIcon(_In_ LPCTSTR lpIconName)
  893. {
  894. return SetIcon(::LoadIcon(NULL, lpIconName));
  895. }
  896. BOOL CTrayNotifyIcon::SetStandardIcon(_In_ UINT nIDResource)
  897. {
  898. return SetIcon(::LoadIcon(NULL, MAKEINTRESOURCE(nIDResource)));
  899. }
  900. BOOL CTrayNotifyIcon::SetIcon(_In_ HICON* phIcons, _In_ int nNumIcons, _In_ DWORD dwDelay)
  901. {
  902. //Validate our parameters
  903. ATLASSERT(nNumIcons >= 2); //must be using at least 2 icons if you are using animation
  904. ATLASSUME(phIcons != NULL);
  905. ATLASSERT(dwDelay);
  906. if (!SetIcon(phIcons[0]))
  907. return FALSE;
  908. //Start the animation
  909. return StartAnimation(phIcons, nNumIcons, dwDelay);
  910. }
  911. HICON CTrayNotifyIcon::LoadIcon(_In_ HINSTANCE hInstance, _In_ LPCTSTR lpIconName, _In_ BOOL bLargeIcon)
  912. {
  913. return static_cast<HICON>(::LoadImage(hInstance, lpIconName, IMAGE_ICON, bLargeIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXSMICON), bLargeIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYSMICON), LR_SHARED));
  914. }
  915. HICON CTrayNotifyIcon::LoadIcon(_In_ HINSTANCE hInstance, _In_ UINT nIDResource, _In_ BOOL bLargeIcon)
  916. {
  917. return LoadIcon(hInstance, MAKEINTRESOURCE(nIDResource), bLargeIcon);
  918. }
  919. HICON CTrayNotifyIcon::LoadIcon(_In_ LPCTSTR lpIconName, _In_ BOOL bLargeIcon)
  920. {
  921. #ifdef _AFX
  922. return LoadIcon(AfxGetResourceHandle(), lpIconName, bLargeIcon);
  923. #else
  924. return LoadIcon(ModuleHelper::GetResourceInstance(), lpIconName, bLargeIcon);
  925. #endif //#ifdef _AFX
  926. }
  927. HICON CTrayNotifyIcon::LoadIcon(_In_ UINT nIDResource, _In_ BOOL bLargeIcon)
  928. {
  929. return LoadIcon(MAKEINTRESOURCE(nIDResource), bLargeIcon);
  930. }
  931. #ifdef _AFX
  932. BOOL CTrayNotifyIcon::SetNotificationWnd(_In_ CWnd* pNotifyWnd)
  933. #else
  934. BOOL CTrayNotifyIcon::SetNotificationWnd(_In_ CWindow* pNotifyWnd)
  935. #endif //#ifdef _AFX
  936. {
  937. //Validate our parameters
  938. ATLASSUME((pNotifyWnd != NULL) && ::IsWindow(pNotifyWnd->operator HWND()));
  939. if (!m_bCreated)
  940. return FALSE;
  941. //Call the Shell_NotifyIcon function
  942. m_pNotificationWnd = pNotifyWnd;
  943. m_NotifyIconData.hWnd = pNotifyWnd->operator HWND();
  944. m_NotifyIconData.uFlags = 0;
  945. return Shell_NotifyIcon(NIM_MODIFY, reinterpret_cast<PNOTIFYICONDATA>(&m_NotifyIconData));
  946. }
  947. CTrayNotifyIcon::String CTrayNotifyIcon::GetTooltipText() const
  948. {
  949. String sText;
  950. if (m_bCreated)
  951. sText = m_NotifyIconData.szTip;
  952. return sText;
  953. }
  954. HICON CTrayNotifyIcon::GetIcon() const
  955. {
  956. HICON hIcon = NULL;
  957. if (m_bCreated)
  958. {
  959. if (UsingAnimatedIcon())
  960. hIcon = GetCurrentAnimationIcon();
  961. else
  962. hIcon = m_NotifyIconData.hIcon;
  963. }
  964. return hIcon;
  965. }
  966. #ifdef _AFX
  967. CWnd* CTrayNotifyIcon::GetNotificationWnd() const
  968. #else
  969. CWindow* CTrayNotifyIcon::GetNotificationWnd() const
  970. #endif //#ifdef _AFX
  971. {
  972. return m_pNotificationWnd;
  973. }
  974. BOOL CTrayNotifyIcon::SetFocus()
  975. {
  976. ATLASSERT(m_ShellVersion >= Version5); //Only supported on Shell v5 or greater
  977. //Call the Shell_NotifyIcon function
  978. return Shell_NotifyIcon(NIM_SETFOCUS, reinterpret_cast<PNOTIFYICONDATA>(&m_NotifyIconData));
  979. }
  980. LRESULT CTrayNotifyIcon::OnTrayNotification(WPARAM wParam, LPARAM lParam)
  981. {
  982. BOOL bShowMenu = FALSE;
  983. BOOL bDoubleClick = FALSE;
  984. BOOL bSingleClick = FALSE;
  985. UINT nIconID = 0;
  986. if ((m_NotifyIconData.uVersion == 0) || (m_ShellVersion >= Version5))
  987. {
  988. nIconID = static_cast<UINT>(wParam);
  989. bShowMenu = (lParam == WM_RBUTTONUP);
  990. bDoubleClick = (lParam == WM_LBUTTONDBLCLK);
  991. bSingleClick = (lParam == WM_LBUTTONUP);
  992. }
  993. else
  994. {
  995. nIconID = HIWORD(lParam);
  996. bShowMenu = (LOWORD(lParam) == WM_CONTEXTMENU);
  997. bDoubleClick = (LOWORD(lParam) == WM_LBUTTONDBLCLK);
  998. bSingleClick = (LOWORD(lParam) == WM_LBUTTONUP);
  999. }
  1000. //Return quickly if its not for this tray icon
  1001. if (nIconID != m_NotifyIconData.uID)
  1002. return 0L;
  1003. //Show the context menu or handle the double click
  1004. if (bShowMenu || bDoubleClick || bSingleClick)
  1005. {
  1006. #ifdef _AFX
  1007. CMenu* pSubMenu = m_Menu.GetSubMenu(0);
  1008. ATLASSUME(pSubMenu != NULL); //Your menu resource has been designed incorrectly
  1009. #else
  1010. CMenuHandle subMenu = m_Menu.GetSubMenu(0);
  1011. ATLASSERT(subMenu.IsMenu());
  1012. #endif //#ifdef _AFX
  1013. if (bShowMenu)
  1014. {
  1015. CPoint ptCursor;
  1016. GetCursorPos(&ptCursor);
  1017. ::SetForegroundWindow(m_NotifyIconData.hWnd);
  1018. #ifdef _AFX
  1019. ::TrackPopupMenu(pSubMenu->m_hMenu, TPM_LEFTBUTTON, ptCursor.x, ptCursor.y, 0, m_NotifyIconData.hWnd, NULL);
  1020. #else
  1021. ::TrackPopupMenu(subMenu, TPM_LEFTBUTTON, ptCursor.x, ptCursor.y, 0, m_NotifyIconData.hWnd, NULL);
  1022. #endif //#ifdef _AFX
  1023. ::PostMessage(m_NotifyIconData.hWnd, WM_NULL, 0, 0);
  1024. }
  1025. else if (bDoubleClick || bSingleClick) //double click received, the default action is to execute first menu item
  1026. {
  1027. ::SetForegroundWindow(m_NotifyIconData.hWnd);
  1028. #ifdef _AFX
  1029. UINT nDefaultItem = pSubMenu->GetDefaultItem(GMDI_GOINTOPOPUPS, FALSE);
  1030. #else
  1031. UINT nDefaultItem = subMenu.GetMenuDefaultItem(FALSE, GMDI_GOINTOPOPUPS);
  1032. #endif //#ifdef _AFX
  1033. if (nDefaultItem != -1)
  1034. ::SendMessage(m_NotifyIconData.hWnd, WM_COMMAND, nDefaultItem, 0);
  1035. }
  1036. }
  1037. return 1; // handled
  1038. }
  1039. BOOL CTrayNotifyIcon::GetDynamicDCAndBitmap(_In_ CDC* pDC, _In_ CBitmap* pBitmap)
  1040. {
  1041. //Validate our parameters
  1042. ATLASSUME(pDC != NULL);
  1043. ATLASSUME(pBitmap != NULL);
  1044. //Get the HWND for the desktop
  1045. #ifdef _AFX
  1046. CWnd* pWndScreen = CWnd::GetDesktopWindow();
  1047. if (pWndScreen == NULL)
  1048. return FALSE;
  1049. #else
  1050. CWindow WndScreen(::GetDesktopWindow());
  1051. if (!WndScreen.IsWindow())
  1052. return FALSE;
  1053. #endif //#ifdef _AFX
  1054. //Get the desktop HDC to create a compatible bitmap from
  1055. #ifdef _AFX
  1056. CDC* pDCScreen = pWndScreen->GetDC();
  1057. if (pDCScreen == NULL)
  1058. return FALSE;
  1059. #else
  1060. CDC DCScreen(WndScreen.GetDC());
  1061. if (DCScreen.IsNull())
  1062. return FALSE;
  1063. #endif //#ifdef _AFX
  1064. //Get the width and height of a small icon
  1065. int w = GetSystemMetrics(SM_CXSMICON);
  1066. int h = GetSystemMetrics(SM_CYSMICON);
  1067. //Create an off-screen bitmap that the dynamic tray icon
  1068. //can be drawn into (Compatible with the desktop DC)
  1069. #ifdef _AFX
  1070. BOOL bSuccess = pBitmap->CreateCompatibleBitmap(pDCScreen, w, h);
  1071. #else
  1072. BOOL bSuccess = (pBitmap->CreateCompatibleBitmap(DCScreen.operator HDC(), w, h) != NULL);
  1073. #endif //#ifdef _AFX
  1074. if (!bSuccess)
  1075. {
  1076. #ifdef _AFX
  1077. pWndScreen->ReleaseDC(pDCScreen);
  1078. #else
  1079. WndScreen.ReleaseDC(DCScreen);
  1080. #endif //#ifdef _AFX
  1081. return FALSE;
  1082. }
  1083. //Get a HDC to the newly created off-screen bitmap
  1084. #ifdef _AFX
  1085. bSuccess = pDC->CreateCompatibleDC(pDCScreen);
  1086. #else
  1087. bSuccess = (pDC->CreateCompatibleDC(DCScreen.operator HDC()) != NULL);
  1088. #endif //#ifdef _AFX
  1089. if (!bSuccess)
  1090. {
  1091. //Release the Screen DC now that we are finished with it
  1092. #ifdef _AFX
  1093. pWndScreen->ReleaseDC(pDCScreen);
  1094. #else
  1095. WndScreen.ReleaseDC(DCScreen);
  1096. #endif //#ifdef _AFX
  1097. //Free up the bitmap now that we are finished with it
  1098. pBitmap->DeleteObject();
  1099. return FALSE;
  1100. }
  1101. //Select the bitmap into the offscreen DC
  1102. #ifdef _AFX
  1103. pDC->SelectObject(pBitmap);
  1104. #else
  1105. pDC->SelectBitmap(pBitmap->operator HBITMAP());
  1106. #endif //#ifdef _AFX
  1107. //Release the Screen DC now that we are finished with it
  1108. #ifdef _AFX
  1109. pWndScreen->ReleaseDC(pDCScreen);
  1110. #else
  1111. WndScreen.ReleaseDC(DCScreen);
  1112. #endif //#ifdef _AFX
  1113. return TRUE;
  1114. }
  1115. DWORD CTrayNotifyIcon::GetNOTIFYICONDATASizeForOS()
  1116. {
  1117. //What will be the return value from this function
  1118. DWORD dwSize = sizeof(NOTIFYICONDATA_1);
  1119. switch (m_ShellVersion)
  1120. {
  1121. case Version7: //Deliberate fallthrough
  1122. case VersionVista:
  1123. {
  1124. dwSize = sizeof(NOTIFYICONDATA_4);
  1125. break;
  1126. }
  1127. case Version6:
  1128. {
  1129. dwSize = sizeof(NOTIFYICONDATA_3);
  1130. break;
  1131. }
  1132. case Version5:
  1133. {
  1134. dwSize = sizeof(NOTIFYICONDATA_2);
  1135. break;
  1136. }
  1137. default:
  1138. {
  1139. break;
  1140. }
  1141. }
  1142. return dwSize;
  1143. }
  1144. BOOL CTrayNotifyIcon::StartAnimation(_In_ HICON* phIcons, _In_ int nNumIcons, _In_ DWORD dwDelay)
  1145. {
  1146. //Validate our parameters
  1147. ATLASSERT(nNumIcons >= 2); //must be using at least 2 icons if you are using animation
  1148. ATLASSUME(phIcons != NULL); //array of icon handles must be valid
  1149. ATLASSERT(dwDelay); //must be non zero timer interval
  1150. //Stop the animation if already started
  1151. StopAnimation();
  1152. //Hive away all the values locally
  1153. ATLASSERT(m_Icons.m_pData == NULL);
  1154. if (!m_Icons.Allocate(nNumIcons))
  1155. return FALSE;
  1156. ATLASSUME(m_Icons.m_pData != NULL);
  1157. for (int i=0; i<nNumIcons; i++)
  1158. m_Icons.m_pData[i] = phIcons[i];
  1159. m_nNumIcons = nNumIcons;
  1160. //Start up the timer
  1161. m_nTimerID = SetTimer(m_NotifyIconData.uID, dwDelay);
  1162. return TRUE;
  1163. }
  1164. void CTrayNotifyIcon::StopAnimation()
  1165. {
  1166. //Kill the timer
  1167. if (m_nTimerID)
  1168. {
  1169. if (::IsWindow(m_hWnd))
  1170. KillTimer(m_nTimerID);
  1171. m_nTimerID = 0;
  1172. }
  1173. //Free up the memory
  1174. if (m_Icons.m_pData != NULL)
  1175. m_Icons.Free();
  1176. //Reset the other animation related variables
  1177. m_nCurrentIconIndex = 0;
  1178. m_nNumIcons = 0;
  1179. }
  1180. BOOL CTrayNotifyIcon::UsingAnimatedIcon() const
  1181. {
  1182. return (m_nNumIcons != 0);
  1183. }
  1184. HICON CTrayNotifyIcon::GetCurrentAnimationIcon() const
  1185. {
  1186. //Valiate our parameters
  1187. ATLASSERT(UsingAnimatedIcon());
  1188. ATLASSUME(m_Icons.m_pData != NULL);
  1189. return m_Icons.m_pData[m_nCurrentIconIndex];
  1190. }
  1191. BOOL CTrayNotifyIcon::ProcessWindowMessage(_In_ HWND /*hWnd*/, _In_ UINT nMsg, _In_ WPARAM wParam, _In_ LPARAM lParam, _Inout_ LRESULT& lResult, _In_ DWORD /*dwMsgMapID*/)
  1192. {
  1193. lResult = 0;
  1194. BOOL bHandled = FALSE;
  1195. if (nMsg == wm_TaskbarCreated)
  1196. {
  1197. lResult = OnTaskbarCreated(wParam, lParam);
  1198. bHandled = TRUE;
  1199. }
  1200. else if ((nMsg == WM_TIMER) && (wParam == m_NotifyIconData.uID))
  1201. {
  1202. OnTimer(m_NotifyIconData.uID);
  1203. bHandled = TRUE;
  1204. }
  1205. else if (nMsg == WM_DESTROY)
  1206. {
  1207. OnDestroy();
  1208. bHandled = TRUE;
  1209. }
  1210. return bHandled;
  1211. }
  1212. void CTrayNotifyIcon::OnDestroy()
  1213. {
  1214. StopAnimation();
  1215. }
  1216. LRESULT CTrayNotifyIcon::OnTaskbarCreated(WPARAM /*wParam*/, LPARAM /*lParam*/)
  1217. {
  1218. //Refresh the tray icon if necessary
  1219. BOOL bShowing = IsShowing();
  1220. Delete(FALSE);
  1221. Create(bShowing);
  1222. return 0;
  1223. }
  1224. #ifdef _DEBUG
  1225. void CTrayNotifyIcon::OnTimer(UINT_PTR nIDEvent)
  1226. #else
  1227. void CTrayNotifyIcon::OnTimer(UINT_PTR /*nIDEvent*/)
  1228. #endif //#ifdef _DEBUG
  1229. {
  1230. //Validate our parameters
  1231. ATLASSERT(nIDEvent == m_nTimerID);
  1232. ATLASSUME(m_Icons.m_pData != NULL);
  1233. //increment the icon index
  1234. ++m_nCurrentIconIndex;
  1235. m_nCurrentIconIndex = m_nCurrentIconIndex % m_nNumIcons;
  1236. //update the tray icon
  1237. m_NotifyIconData.uFlags = NIF_ICON;
  1238. m_NotifyIconData.hIcon = m_Icons.m_pData[m_nCurrentIconIndex];
  1239. Shell_NotifyIcon(NIM_MODIFY, reinterpret_cast<PNOTIFYICONDATA>(&m_NotifyIconData));
  1240. }
  1241. BOOL CTrayNotifyIcon::CreateHelperWindow()
  1242. {
  1243. //Let the base class do its thing
  1244. return (CWindowImpl<CTrayNotifyIcon>::Create(NULL, CWindow::rcDefault, _T("CTrayNotifyIcon Helper Window"), WS_OVERLAPPEDWINDOW) != NULL);
  1245. }
  1246. CTrayWnd CTrayNotifyIcon::m_wndInvisible;
  1247. BOOL CTrayNotifyIcon::RemoveTaskbarIcon(CWnd* pWnd)
  1248. {
  1249. LPCTSTR pstrOwnerClass = AfxRegisterWndClass(0);
  1250. // Create static invisible window
  1251. if (!::IsWindow(m_wndInvisible.m_hWnd))
  1252. {
  1253. if (!m_wndInvisible.CreateEx(0, pstrOwnerClass, _T(""), WS_POPUP,
  1254. CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
  1255. NULL, 0))
  1256. {
  1257. return FALSE;
  1258. }
  1259. }
  1260. pWnd->SetParent(&m_wndInvisible);
  1261. return TRUE;
  1262. }
  1263. void CTrayNotifyIcon::MinimiseToTray(CWnd* pWnd)
  1264. {
  1265. RemoveTaskbarIcon(pWnd);
  1266. pWnd->ModifyStyle(WS_VISIBLE, 0);
  1267. }
  1268. void CTrayNotifyIcon::MaximiseFromTray(CWnd* pWnd)
  1269. {
  1270. pWnd->SetParent(NULL);
  1271. pWnd->ModifyStyle(0, WS_VISIBLE);
  1272. pWnd->RedrawWindow(NULL, NULL, RDW_UPDATENOW | RDW_ALLCHILDREN | RDW_FRAME |
  1273. RDW_INVALIDATE | RDW_ERASE);
  1274. // Move focus away and back again to ensure taskbar icon is recreated
  1275. if (::IsWindow(m_wndInvisible.m_hWnd))
  1276. m_wndInvisible.SetActiveWindow();
  1277. pWnd->SetActiveWindow();
  1278. pWnd->SetForegroundWindow();
  1279. }