| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453 |
- /*
- Module : NTray.cpp
- Purpose: implementation for a MFC class to encapsulate Shell_NotifyIcon
- Created: PJN / 14-05-1997
- History: PJN / 25-11-1997 Addition of the following
- 1. HideIcon(), ShowIcon() & MoveToExtremeRight()
- 2. Support for animated tray icons
- PJN / 23-06-1998 Class now supports the new Taskbar Creation Notification
- message which comes with IE 4. This allows the tray icon
- to be recreated whenever the explorer restarts (Crashes!!)
- PJN / 22-07-1998 1. Code now compiles cleanly at warning level 4
- 2. Code is now UNICODE enabled + build configurations are provided
- 3. The documentation for the class has been updated
- PJN / 27-01-1999 1. Code first tries to load a 16*16 icon before loading the 32*32
- version. This removes the blurryness which was previously occuring
- PJN / 28-01-1999 1. Fixed a number of level 4 warnings which were occurring.
- PJN / 09-05-1999 1. Fixed a problem as documented in KB article "PRB: Menus for
- Notification Icons Do Not Work Correctly", Article ID: Q135788
- PJN / 15-05-1999 1. Now uses the author's hookwnd class. This prevents the need to
- create the two hidden windows namely CTrayRessurectionWnd and
- CTrayTimerWnd
- 2. Code now compiles cleanly at warning level 4
- 3. General code tidy up and rearrangement
- 4. Added numerous ASSERT's to improve the code's robustness
- 5. Added functions to allow context menu to be customized
- PJN / 01-01-2001 1. Now includes copyright message in the source code and documentation.
- 2. Fixed problem where the window does not get focus after double clicking
- on the tray icon
- 3. Now fully supports the Windows 2000 balloon style tooltips
- 4. Fixed a off by one problem in some of the ASSERT's
- 5. Fixed problems with Unicode build configurations
- 6. Provided Win2k specific build configurations
- PJN / 10-02-2001 1. Now fully supports creation of 2 tray icons at the same time
- PJN / 13-06-2001 1. Now removes windows hook upon call to RemoveIcon
- PJN / 26-08-2001 1. Fixed memory leak in RemoveIcon.
- 2. Fixed GPF in RemoveIcon by removing call to Unhook
- PJN / 28-08-2001 1. Added support for direct access to the System Tray's HDC. This allows
- you to generate an icon for the tray on the fly using GDI calls. The idea
- came from the article by Jeff Heaton in the April issue of WDJ. Also added
- are overriden Create methods to allow you to easily costruct a dynamic
- tray icon given a BITMAP instead of an ICON.
- PJN / 21-03-2003 1. Fixed icon resource leaks in SetIcon(LPCTSTR lpIconName) and
- SetIcon(UINT nIDResource). Thanks to Egor Pervouninski for reporting this.
- 2. Fixed unhooking of the tray icon when the notification window is being
- closed.
- PJN / 31-03-2003 1. Now uses V1.05 of my Hookwnd class
- PJN / 02-04-2003 1. Now uses v1.06 of my Hookwnd class
- 2. Fixed a bug in the sample app for this class where the hooks should
- have been created as global instances rather than as member variables of
- the mainframe window. This ensures that the hooks remain valid even after
- calling DefWindowProc on the mainframe.
- PJN / 23-07-2004 1. Minor update to remove unnecessary include of "resource.h"
- PJN / 03-03-2006 1. Updated copyright details.
- 2. Updated the documentation to use the same style as the web site.
- 3. Did a spell check of the documentation.
- 4. Fixed some issues when the code is compiled using /Wp64. Please note that
- to support this the code now requires a recentish Platform SDK to be installed
- if the code is compiled with Visual C++ 6.
- 5. Replaced all calls to ZeroMemory with memset.
- 6. Fixed an issue where SetBalloonDetails was not setting the cbSize parameter.
- Thanks to Enrique Granda for reporting this issue.
- 7. Added support for NIIF_USER and NIIF_NONE flags.
- 8. Now includes support for NIM_NIMSETVERSION via SetVersion. In addition this
- is now automatically set in the Create() calls if the Win2k boolean parameter
- is set.
- 9. Removed derivation from CObject as it was not really needed.
- 10. Now includes support for NIM_SETFOCUS
- 11. Added support for NIS_HIDDEN via the ShowIcon and HideIcon methods.
- 12. Added support for NIIF_NOSOUND
- PJN / 27-06-2006 1. Code now uses new C++ style casts rather than old style C casts where necessary.
- 2. The class framework now requires the Platform SDK if compiled using VC 6.
- 3. Updated the logic of the ASSERTs which validate the various string lengths.
- 4. Fixed a bug in CTrayNotifyIcon::SetFocus() where the cbSize value was not being
- set correctly.
- 5. CTrayIconHooker class now uses ATL's CWindowImpl class in preference to the author's
- CHookWnd class. This does mean that for MFC only client projects, you will need to add
- ATL support to your project.
- 6. Optimized CTrayIconHooker constructor code
- 7. Updated code to compile cleanly using VC 2005. Thanks to "Itamar" for prompting this
- update.
- 8. Addition of a CTRAYNOTIFYICON_EXT_CLASS and CTRAYNOTIFYICON_EXT_API macros which makes
- the class easier to use in an extension dll.
- 9. Made CTrayNotifyIcon destructor virtual
- PJN / 03-07-2005 1. Fixed a bug where the HideIcon functionality did not work on Windows 2000. This was
- related to how the cbSize member of the NOTIFYICONDATA structure was initialized. The code
- now dynamically determines the correct size to set at runtime according to the instructions
- provided by the MSDN documentation for this structure. As a result of this, all "bWin2k"
- parameters which were previously exposed via CTrayNotifyIcon have now been removed as there
- is no need for them. Thanks to Edwin Geng for reporting this important bug. Client code will
- still need to intelligently make decisions on what is supported by the OS. For example balloon
- tray icons are only supported on Shell v5 (nominally Windows 2000 or later). CTrayNotifyIcon
- will ASSERT if for example calls are made to it to create a balloon tray icon on operating
- systems < Windows 2000.
- PJN / 04-07-2006 1. Fixed a bug where the menu may pop up a second time after a menu item is chosen on
- Windows 2000. The problem was tracked down to the code in CTrayNotifyIcon::OnTrayNotification.
- During testing of this bug, I was unable to get a workable solution using the new shell
- messages of WM_CONTEXTMENU, NIN_KEYSELECT & NIN_SELECT on Windows 2000 and Windows XP.
- This means that the code in CTrayNotifyIcon::OnTrayNotification uses the old way of handling
- notifications (WM_RBUTTDOWN*). This does mean that by default, client apps which use the
- CTrayNotifyIcon class will not support the new keyboard and mouse semantics for tray icons
- (IMHO this is no big loss!). Client code is of course free to handle their own notifications.
- If you go down this route then I would advise you to thoroughly test your application on
- Windows 2000 and Windows XP as my testing has shown that there is significant differences in
- how tray icons handle their messaging on these 2 operating systems. Thanks to Edwin Geng for
- reporting this issue.
- 2. Class now displays the menu based on the current message's screen coordinates, rather than
- the current cursor screen coordinates.
- 3. Fixed bug in sample app where if the about dialog is already up and it is reactivated
- from the tray menu, it did not bring itself into the foreground
- PJN / 06-07-2006 1. Reverted the change made for v1.53 where the screen coordinates used to show the context
- menu use the current message's screen coordinates. Instead the pre v1.53 mechanism which
- uses the current cursor's screen coordinates is now used. Thanks to Itamar Syn-Hershko for
- reporting this issue.
- PJN / 19-07-2006 1. The default menu item can now be customized via SetDefaultMenuItem and
- GetDefaultMenuItem. Thanks to Mikhail Bykanov for suggesting this nice update.
- 2. Optimized CTrayNotifyIcon constructor code
- PJN / 19-08-2005 1. Updated the code to operate independent of MFC if so desired. This requires WTL which is an
- open source library extension for ATL to provide UI support along the lines of MFC. Thanks to
- zhiguo zhao for providing this very nice addition.
- PJN / 15-09-2006 1. Fixed a bug where WM_DESTROY messages were not been handled correctly for the top level window
- which the CTrayIconHooker class subclasses in order to handle the tray resurrection message,
- the animation timers and auto destroying of the icons when the top level window is destroyed.
- Thanks to Edward Livingston for reporting this bug.
- 2. Fixed a bug where the tray icons were not being recreated correctly when we receive the
- "TaskbarCreated" when Explorer is restarted. Thanks to Nuno Esculcas for reporting this bug.
- 3. Split the functionality of hiding versus deleting and showing versus creating of the tray
- icon into 4 separate functions, namely Delete(), Create(), Hide() and Show(). Note that Hide
- and Show functionality is only available on Shell v5 or later.
- 4. Fixed an issue with recreation of tray icons which use a dynamic icon created from a bitmap
- (through the use of BitmapToIcon).
- 5. CTrayNotifyIcon::LoadIconResource now loads up an icon as a shared icon resource using
- LoadImage. This should avoid resource leaks using this function.
- PJN / 15-06-2007 1. Updated copyright messages.
- 2. If the code detects that MFC is not included in the project, the code uses the standard
- preprocessor define "_CSTRING_NS" to declare the string class to use rather than explicitly
- using WTL::CString. Thanks to Krzysztof Suszka for reporting this issue.
- 3. Updated sample app to compile cleanly on VC 2005.
- 4. Addition of a "BOOL bShow" to all the Create methods. This allows you to create an icon
- without actually showing it. This avoids the flicker which previously occurred if you created
- the icon and then immediately hid the icon. Thanks to Krzysztof Suszka for providing this
- suggestion.
- 5. Demo app now initially creates the first icon as hidden for demonstration purposes.
- 6. Added support for NIIF_LARGE_ICON. This Vista only feature allows you to create a large
- balloon icon.
- 7. Added support for NIF_REALTIME. This Vista only flag allows you to specify not to bother
- showing the balloon if it is delayed due to the presence of an existing balloon.
- 8. Added support for NOTIFYICONDATA::hBalloonIcon. This Vista only feature allows you to
- create a user specified balloon icon which is different to the actual tray icon.
- 9. LoadIconResource method now includes support for loading large icons and has been renamed
- to simply LoadIcon. Also two overridden versions of this method have been provided which allow
- the hInstance resource ID to be specified to load the icon from.
- 10. Reworked the internal code to CTrayNotifyIcon which detects the shell version.
- 11. Updated the tray icon text in the demo app to better demonstrate the features of the class.
- 12. Updated the WTL sample to be consistent with the MFC sample code
- 13. Updated comments in documentation about usage of the Platform SDK.
- PJN / 13-10-2007 1. Subclassing of the top level window is now not down internally by the CTrayNotifyIcon class
- using the CTrayIconHooker class. Instead now a hidden top level window is created for each tray
- icon you create and these look after handling the tray resurrection and animated icon timer
- messages. This refactoring of the internals of the class now also fixes a bug where an application
- which creates multiples tray icons would only get one icon recreated when the tray resurrection
- message was received. Thanks to Steven Dwyer for prompting this update.
- 2. Updated the MFC sample app to correctly initialize ATL for VC 6
- PJN / 12-03-2008 1. Updated copyright details
- 2. Fixed a bug in SetBalloonDetails where the code did not set the flag NIF_ICON if a user defined
- icon was being set. Thanks to "arni" for reporting this bug.
- 3. Updated the sample app to clean compile on VC 2008
- PJN / 22-06-2008 1. Code now compiles cleanly using Code Analysis (/analyze)
- 2. Updated code to compile correctly using _ATL_CSTRING_EXPLICIT_CONSTRUCTORS define
- 3. Removed VC 6 style AppWizard comments from the code.
- 4. The code now only supports VC 2005 or later.
- PJN / 10-04-2010 1. Updated copyright details.
- 2. Updated the project settings to more modern default values.
- 3. Updated the WTL version of LoadIcon to use the more modern ModuleHelper class from WTL to get
- the resource instance. Thanks to "Yarp" for reporting this issue.
- 4. The class now has support for the Windows 7 "NIIF_RESPECT_QUIET_TIME" flag. This value can be
- set via the new "bQuietTime" parameter to the Create method.
- 5. Updated the code which does version detection of the Shell version
- PJN / 10-07-2010 1. Updated the sample app to compile cleanly on VS 2010.
- 2. Fixed a bug in CTrayNotifyIcon::Delete where the code would ASSERT if the tray notify icon was
- never actually created. Thanks to "trophim" for reporting this bug.
- PJN / 06-11-2010 1. Minor update to code in SetTooltipText to code which handles unreferenced variable compiler
- warning
- 2. Implemented a GetTooltipMaxSize method which reports the maximum size which the tooltip can be
- for a tray icon. Thanks to Geert van Horrik for this nice addition
- 3. All places which copy text to the underlying NOTIFYICONDATA now use the _TRUNCATE parameter in
- their call to the Safe CRT runtime. This change in behaviour means that client apps will no longer
- crash if they supply data larger than this Windows structure can accommadate. Thanks to Geert van
- Horrik for prompting this update.
- 4. All calls to sizeof(struct)/sizeof(first element) have been replaced with _countof
- 5. Fixed a linker error when compiling the WTL sample app in release mode.
- PJN / 26-11-2010 1. Minor update to use DBG_UNREFERENCED_LOCAL_VARIABLE macro. Thanks to Jukka Ojanen for prompting this
- update.
- PJN / 27-04-2016 1. Updated copyright details.
- 2. Updated the code to clean compile on VC 2012 - VC 2015.
- 3. Removed support for CTRAYNOTIFYICON_NOWIN2K preprocessor macro
- 4. Removed various redefines of ShellApi.h constants from the code
- 5. Added SAL annotations to all the code.
- 6. Reworked the definition of the string class to now use a typedef internal to the CTrayNotifyIcon
- class.
- 7. Updated CTrayNotifyIcon::OnTrayNotification to handle NOTIFYICON_VERSION_4 style notifications.
- 8. Reworked the internal storage of the animation icons to use ATL::CHeapPtr
- Copyright (c) 1997 - 2016 by PJ Naughter (Web: www.naughter.com, Email: [email protected])
- All rights reserved.
- Copyright / Usage Details:
- You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise)
- when your product is released in binary form. You are allowed to modify the source code in any way you want
- except you cannot modify the copyright details at the top of each module. If you want to distribute source
- code with your application, then you are only allowed to distribute versions released by the author. This is
- to maintain a single distribution point for the source code.
- */
- ///////////////////////////////// Includes //////////////////////////////////
- #include "stdafx.h"
- #include "NTray.h"
- #ifndef _INC_SHELLAPI
- #pragma message("To avoid this message, please put ShellApi.h in your pre compiled header (normally stdafx.h)")
- #include <ShellApi.h>
- #endif //#ifndef _INC_SHELLAPI
- ///////////////////////////////// Macros /////////////////////////////////////
- #ifdef _AFX
- #ifdef _DEBUG
- #define new DEBUG_NEW
- #endif //#ifdef _DEBUG
- #endif //#ifdef _AFX
- #ifndef NIF_REALTIME
- #define NIF_REALTIME 0x00000040
- #endif //#ifndef NIF_REALTIME
- #ifndef NIIF_LARGE_ICON
- #define NIIF_LARGE_ICON 0x00000020
- #endif //#ifndef NIIF_LARGE_ICON
- #ifndef NIIF_RESPECT_QUIET_TIME
- #define NIIF_RESPECT_QUIET_TIME 0x00000080
- #endif //#ifndef NIIF_RESPECT_QUIET_TIME
- ///////////////////////////////// Implementation //////////////////////////////
- const UINT wm_TaskbarCreated = RegisterWindowMessage(_T("TaskbarCreated"));
- CTrayNotifyIcon::CTrayNotifyIcon() : m_bCreated(FALSE),
- m_bHidden(FALSE),
- m_pNotificationWnd(NULL),
- m_bDefaultMenuItemByPos(TRUE),
- m_nDefaultMenuItem(0),
- m_hDynamicIcon(NULL),
- m_ShellVersion(Version4), //Assume version 4 of the shell
- m_nNumIcons(0),
- m_nTimerID(0),
- m_nCurrentIconIndex(0),
- m_nTooltipMaxSize(-1)
- {
- typedef HRESULT (CALLBACK DLLGETVERSION)(DLLVERSIONINFO*);
- typedef DLLGETVERSION* LPDLLGETVERSION;
- //Try to get the details with DllGetVersion
- HMODULE hShell32 = GetModuleHandle(_T("SHELL32.DLL"));
- if (hShell32 != NULL)
- {
- LPDLLGETVERSION lpfnDllGetVersion = reinterpret_cast<LPDLLGETVERSION>(GetProcAddress(hShell32, "DllGetVersion"));
- if (lpfnDllGetVersion != NULL)
- {
- DLLVERSIONINFO vinfo;
- vinfo.cbSize = sizeof(DLLVERSIONINFO);
- if (SUCCEEDED(lpfnDllGetVersion(&vinfo)))
- {
- if ((vinfo.dwMajorVersion > 6) || (vinfo.dwMajorVersion == 6 && vinfo.dwMinorVersion > 0))
- m_ShellVersion = Version7;
- else if (vinfo.dwMajorVersion == 6)
- {
- if (vinfo.dwBuildNumber >= 6000)
- m_ShellVersion = VersionVista;
- else
- m_ShellVersion = Version6;
- }
- else if (vinfo.dwMajorVersion >= 5)
- m_ShellVersion = Version5;
- }
- }
- }
- memset(&m_NotifyIconData, 0, sizeof(m_NotifyIconData));
- m_NotifyIconData.cbSize = GetNOTIFYICONDATASizeForOS();
- }
- CTrayNotifyIcon::~CTrayNotifyIcon()
- {
- //Delete the tray icon
- Delete(TRUE);
-
- //Free up any dynamic icon we may have
- if (m_hDynamicIcon != NULL)
- {
- DestroyIcon(m_hDynamicIcon);
- m_hDynamicIcon = NULL;
- }
- }
- BOOL CTrayNotifyIcon::Delete(_In_ BOOL bCloseHelperWindow)
- {
- //What will be the return value from this function (assume the best)
- BOOL bSuccess = TRUE;
- if (m_bCreated)
- {
- m_NotifyIconData.uFlags = 0;
- bSuccess = Shell_NotifyIcon(NIM_DELETE, reinterpret_cast<PNOTIFYICONDATA>(&m_NotifyIconData));
- m_bCreated = FALSE;
- }
-
- //Close the helper window if requested to do so
- if (bCloseHelperWindow && IsWindow())
- SendMessage(WM_CLOSE);
-
- return bSuccess;
- }
- BOOL CTrayNotifyIcon::Create(_In_ BOOL bShow)
- {
- m_NotifyIconData.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
-
- if (!bShow)
- {
- ATLASSERT(m_ShellVersion >= Version5); //Only supported on Shell v5 or later
- m_NotifyIconData.uFlags |= NIF_STATE;
- m_NotifyIconData.dwState = NIS_HIDDEN;
- m_NotifyIconData.dwStateMask = NIS_HIDDEN;
- }
-
- BOOL bSuccess = Shell_NotifyIcon(NIM_ADD, reinterpret_cast<PNOTIFYICONDATA>(&m_NotifyIconData));
- if (bSuccess)
- {
- m_bCreated = TRUE;
-
- if (!bShow)
- m_bHidden = TRUE;
- }
- return bSuccess;
- }
- BOOL CTrayNotifyIcon::Hide()
- {
- //Validate our parameters
- ATLASSERT(m_ShellVersion >= Version5); //Only supported on Shell v5 or later
- // ATLASSERT(!m_bHidden); //Only makes sense to hide the icon if it is not already hidden
- m_NotifyIconData.uFlags = NIF_STATE;
- m_NotifyIconData.dwState = NIS_HIDDEN;
- m_NotifyIconData.dwStateMask = NIS_HIDDEN;
- BOOL bSuccess = Shell_NotifyIcon(NIM_MODIFY, reinterpret_cast<PNOTIFYICONDATA>(&m_NotifyIconData));
- if (bSuccess)
- m_bHidden = TRUE;
- return bSuccess;
- }
- BOOL CTrayNotifyIcon::Show()
- {
- //Validate our parameters
- ATLASSERT(m_ShellVersion >= Version5); //Only supported on Shell v5 or later
- // ATLASSERT(m_bHidden); //Only makes sense to show the icon if it has been previously hidden
- ATLASSERT(m_bCreated);
- m_NotifyIconData.uFlags = NIF_STATE;
- m_NotifyIconData.dwState = 0;
- m_NotifyIconData.dwStateMask = NIS_HIDDEN;
- BOOL bSuccess = Shell_NotifyIcon(NIM_MODIFY, reinterpret_cast<PNOTIFYICONDATA>(&m_NotifyIconData));
- if (bSuccess)
- m_bHidden = FALSE;
- return bSuccess;
- }
- void CTrayNotifyIcon::SetMenu(_In_ HMENU hMenu, UINT menuId)
- {
- m_Menu.DestroyMenu();
- if (menuId != 0)
- {
- if (!m_Menu.LoadMenu(menuId))
- {
- ATLASSERT(FALSE);
- return;
- }
- }
- else
- {
- m_Menu.Attach(hMenu);
- }
- #ifdef _AFX
- CMenu* pSubMenu = m_Menu.GetSubMenu(0);
- ATLASSUME(pSubMenu != NULL); //Your menu resource has been designed incorrectly
-
- //Make the specified menu item the default (bold font)
- pSubMenu->SetDefaultItem(m_nDefaultMenuItem, m_bDefaultMenuItemByPos);
- #else
- CMenuHandle subMenu = m_Menu.GetSubMenu(0);
- ATLASSERT(subMenu.IsMenu()); //Your menu resource has been designed incorrectly
- //Make the specified menu item the default (bold font)
- subMenu.SetMenuDefaultItem(m_nDefaultMenuItem, m_bDefaultMenuItemByPos);
- #endif //#ifdef _AFX
- }
- CMenu& CTrayNotifyIcon::GetMenu()
- {
- return m_Menu;
- }
- void CTrayNotifyIcon::SetDefaultMenuItem(_In_ UINT uItem, _In_ BOOL fByPos)
- {
- m_nDefaultMenuItem = uItem;
- m_bDefaultMenuItemByPos = fByPos;
- //Also update in the live menu if it is present
- if (m_Menu.operator HMENU())
- {
- #ifdef _AFX
- CMenu* pSubMenu = m_Menu.GetSubMenu(0);
- ATLASSUME(pSubMenu != NULL); //Your menu resource has been designed incorrectly
- pSubMenu->SetDefaultItem(m_nDefaultMenuItem, m_bDefaultMenuItemByPos);
- #else
- CMenuHandle subMenu = m_Menu.GetSubMenu(0);
- ATLASSERT(subMenu.IsMenu()); //Your menu resource has been designed incorrectly
-
- subMenu.SetMenuDefaultItem(m_nDefaultMenuItem, m_bDefaultMenuItemByPos);
- #endif //#ifdef _AFX
- }
- }
- #ifdef _AFX
- BOOL CTrayNotifyIcon::Create(_In_ CWnd* pNotifyWnd, _In_ UINT uID, _In_ LPCTSTR pszTooltipText, _In_ HICON hIcon, _In_ UINT nNotifyMessage, _In_ UINT uMenuID, _In_ BOOL bShow)
- #else
- BOOL CTrayNotifyIcon::Create(_In_ CWindow* pNotifyWnd, _In_ UINT uID, _In_ LPCTSTR pszTooltipText, _In_ HICON hIcon, _In_ UINT nNotifyMessage, _In_ UINT uMenuID, _In_ BOOL bShow)
- #endif //#ifdef _AFX
- {
- //Validate our parameters
- ATLASSUME((pNotifyWnd != NULL) && ::IsWindow(pNotifyWnd->operator HWND()));
- #ifdef _DEBUG
- if (m_ShellVersion >= Version5) //If on Shell v5 or higher, then use the larger size tooltip
- {
- NOTIFYICONDATA_2 dummy;
- ATLASSERT(_tcslen(pszTooltipText) < _countof(dummy.szTip));
- DBG_UNREFERENCED_LOCAL_VARIABLE(dummy);
- }
- else
- {
- NOTIFYICONDATA_1 dummy;
- ATLASSERT(_tcslen(pszTooltipText) < _countof(dummy.szTip));
- DBG_UNREFERENCED_LOCAL_VARIABLE(dummy);
- }
- #endif //#ifdef _DEBUG
- ATLASSERT(hIcon != NULL);
- ATLASSERT(nNotifyMessage >= WM_USER); //Make sure we avoid conflict with other messages
- //Load up the menu resource which is to be used as the context menu
- if (!m_Menu.LoadMenu(uMenuID == 0 ? uID : uMenuID))
- {
- ATLASSERT(FALSE);
- return FALSE;
- }
- #ifdef _AFX
- CMenu* pSubMenu = m_Menu.GetSubMenu(0);
- if (pSubMenu == NULL)
- {
- ATLASSERT(FALSE); //Your menu resource has been designed incorrectly
- return FALSE;
- }
- //Make the specified menu item the default (bold font)
- pSubMenu->SetDefaultItem(m_nDefaultMenuItem, m_bDefaultMenuItemByPos);
- #else
- CMenuHandle subMenu = m_Menu.GetSubMenu(0);
- if (!subMenu.IsMenu())
- {
- ATLASSERT(FALSE); //Your menu resource has been designed incorrectly
- return FALSE;
- }
- subMenu.SetMenuDefaultItem(m_nDefaultMenuItem, m_bDefaultMenuItemByPos);
- #endif //#ifdef _AFX
- //Create the helper window
- if (!CreateHelperWindow())
- return FALSE;
- //Call the Shell_NotifyIcon function
- m_pNotificationWnd = pNotifyWnd;
- m_NotifyIconData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
- m_NotifyIconData.hWnd = pNotifyWnd->operator HWND();
- m_NotifyIconData.uID = uID;
- m_NotifyIconData.uCallbackMessage = nNotifyMessage;
- m_NotifyIconData.hIcon = hIcon;
- _tcsncpy_s(m_NotifyIconData.szTip, _countof(m_NotifyIconData.szTip), pszTooltipText, _TRUNCATE);
- if (!bShow)
- {
- ATLASSERT(m_ShellVersion >= Version5); //Only supported on Shell v5 or later
- m_NotifyIconData.uFlags |= NIF_STATE;
- m_NotifyIconData.dwState = NIS_HIDDEN;
- m_NotifyIconData.dwStateMask = NIS_HIDDEN;
- }
- m_bCreated = Shell_NotifyIcon(NIM_ADD, reinterpret_cast<PNOTIFYICONDATA>(&m_NotifyIconData));
- if (m_bCreated)
- {
- if (!bShow)
- m_bHidden = TRUE;
-
- //Turn on Shell v5 style behaviour if supported
- if (m_ShellVersion >= Version5)
- SetVersion(NOTIFYICON_VERSION);
- }
-
- return m_bCreated;
- }
- BOOL CTrayNotifyIcon::SetVersion(_In_ UINT uVersion)
- {
- //Validate our parameters
- ATLASSERT(m_ShellVersion >= Version5); //Only supported on Shell v5 or later
- //Call the Shell_NotifyIcon function
- m_NotifyIconData.uVersion = uVersion;
- return Shell_NotifyIcon(NIM_SETVERSION, reinterpret_cast<PNOTIFYICONDATA>(&m_NotifyIconData));
- }
- HICON CTrayNotifyIcon::BitmapToIcon(_In_ CBitmap* pBitmap)
- {
- //Validate our parameters
- ATLASSUME(pBitmap != NULL);
- //Get the width and height of a small icon
- int w = GetSystemMetrics(SM_CXSMICON);
- int h = GetSystemMetrics(SM_CYSMICON);
- //Create a 0 mask
- int nMaskSize = h*(w/8);
- ATL::CHeapPtr<BYTE> pMask;
- if (!pMask.Allocate(nMaskSize))
- return NULL;
- memset(pMask.m_pData, 0, nMaskSize);
- //Create a mask bitmap
- CBitmap maskBitmap;
- #ifdef _AFX
- BOOL bSuccess = maskBitmap.CreateBitmap(w, h, 1, 1, pMask.m_pData);
- #else
- maskBitmap.CreateBitmap(w, h, 1, 1, pMask.m_pData);
- BOOL bSuccess = !maskBitmap.IsNull();
- #endif //#ifdef _AFX
- //Handle the error
- if (!bSuccess)
- return NULL;
- //Create an ICON base on the bitmap just created
- ICONINFO iconInfo;
- iconInfo.fIcon = TRUE;
- iconInfo.xHotspot = 0;
- iconInfo.yHotspot = 0;
- iconInfo.hbmMask = maskBitmap;
- iconInfo.hbmColor = *pBitmap;
- return CreateIconIndirect(&iconInfo);
- }
- #ifdef _AFX
- BOOL CTrayNotifyIcon::Create(_In_ CWnd* pNotifyWnd, _In_ UINT uID, _In_ LPCTSTR pszTooltipText, _In_ CBitmap* pBitmap, _In_ UINT nNotifyMessage, _In_ UINT uMenuID, _In_ BOOL bShow)
- #else
- BOOL CTrayNotifyIcon::Create(_In_ CWindow* pNotifyWnd, _In_ UINT uID, _In_ LPCTSTR pszTooltipText, _In_ CBitmap* pBitmap, _In_ UINT nNotifyMessage, _In_ UINT uMenuID, _In_ BOOL bShow)
- #endif //#ifdef _AFX
- {
- //Convert the bitmap to an Icon
- if (m_hDynamicIcon != NULL)
- DestroyIcon(m_hDynamicIcon);
- m_hDynamicIcon = BitmapToIcon(pBitmap);
- //Pass the buck to the other function to do the work
- return Create(pNotifyWnd, uID, pszTooltipText, m_hDynamicIcon, nNotifyMessage, uMenuID, bShow);
- }
- #ifdef _AFX
- 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)
- #else
- 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)
- #endif //#ifdef _AFX
- {
- //Validate our parameters
- ATLASSUME(phIcons != NULL);
- ATLASSERT(nNumIcons >= 2); //must be using at least 2 icons if you are using animation
- ATLASSERT(dwDelay);
- //let the normal Create function do its stuff
- BOOL bSuccess = Create(pNotifyWnd, uID, pszTooltipText, phIcons[0], nNotifyMessage, uMenuID, bShow);
- if (bSuccess)
- {
- //Start the animation
- bSuccess = StartAnimation(phIcons, nNumIcons, dwDelay);
- }
- return bSuccess;
- }
- #ifdef _AFX
- 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)
- #else
- 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)
- #endif //#ifdef _AFX
- {
- //Validate our parameters
- ATLASSUME((pNotifyWnd != NULL) && ::IsWindow(pNotifyWnd->operator HWND()));
- ATLASSERT(m_ShellVersion >= Version5); //Only supported on Shell v5 or later
- #ifdef _DEBUG
- NOTIFYICONDATA_2 dummy;
- ATLASSERT(_tcslen(pszTooltipText) < _countof(dummy.szTip));
- ATLASSERT(_tcslen(pszBalloonText) < _countof(dummy.szInfo));
- ATLASSERT(_tcslen(pszBalloonCaption) < _countof(dummy.szInfoTitle));
- ATLASSERT(hIcon);
- ATLASSERT(nNotifyMessage >= WM_USER); //Make sure we avoid conflict with other messages
- DBG_UNREFERENCED_LOCAL_VARIABLE(dummy);
- #endif //#ifdef _DEBUG
- //Load up the menu resource which is to be used as the context menu
- if (!m_Menu.LoadMenu(uMenuID == 0 ? uID : uMenuID))
- {
- ATLASSERT(FALSE);
- return FALSE;
- }
- #ifdef _AFX
- CMenu* pSubMenu = m_Menu.GetSubMenu(0);
- if (pSubMenu == NULL)
- {
- ATLASSERT(FALSE); //Your menu resource has been designed incorrectly
- return FALSE;
- }
- //Make the specified menu item the default (bold font)
- pSubMenu->SetDefaultItem(m_nDefaultMenuItem, m_bDefaultMenuItemByPos);
- #else
- CMenuHandle subMenu = m_Menu.GetSubMenu(0);
- if (!subMenu.IsMenu())
- {
- ATLASSERT(FALSE); //Your menu resource has been designed incorrectly
- return FALSE;
- }
- //Make the specified menu item the default (bold font)
- subMenu.SetMenuDefaultItem(m_nDefaultMenuItem, m_bDefaultMenuItemByPos);
- #endif //#ifdef _AFX
- //Create the helper window
- if (!CreateHelperWindow())
- return FALSE;
- //Call the Shell_NotifyIcon function
- m_pNotificationWnd = pNotifyWnd;
- m_NotifyIconData.hWnd = pNotifyWnd->operator HWND();
- m_NotifyIconData.uID = uID;
- m_NotifyIconData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP | NIF_INFO;
- m_NotifyIconData.uCallbackMessage = nNotifyMessage;
- m_NotifyIconData.hIcon = hIcon;
- _tcsncpy_s(m_NotifyIconData.szTip, _countof(m_NotifyIconData.szTip), pszTooltipText, _TRUNCATE);
- _tcsncpy_s(m_NotifyIconData.szInfo, _countof(m_NotifyIconData.szInfo), pszBalloonText, _TRUNCATE);
- _tcsncpy_s(m_NotifyIconData.szInfoTitle, _countof(m_NotifyIconData.szInfoTitle), pszBalloonCaption, _TRUNCATE);
- m_NotifyIconData.uTimeout = nTimeout;
- switch (style)
- {
- case Warning:
- {
- m_NotifyIconData.dwInfoFlags = NIIF_WARNING;
- break;
- }
- case Error:
- {
- m_NotifyIconData.dwInfoFlags = NIIF_ERROR;
- break;
- }
- case Info:
- {
- m_NotifyIconData.dwInfoFlags = NIIF_INFO;
- break;
- }
- case None:
- {
- m_NotifyIconData.dwInfoFlags = NIIF_NONE;
- break;
- }
- case User:
- {
- if (hBalloonIcon != NULL)
- {
- ATLASSERT(m_ShellVersion >= VersionVista);
- m_NotifyIconData.hBalloonIcon = hBalloonIcon;
- }
- else
- {
- ATLASSERT(hIcon != NULL); //You forget to provide a user icon
- }
- m_NotifyIconData.dwInfoFlags = NIIF_USER;
- break;
- }
- default:
- {
- ATLASSERT(FALSE);
- break;
- }
- }
- if (bNoSound)
- m_NotifyIconData.dwInfoFlags |= NIIF_NOSOUND;
- if (bLargeIcon)
- {
- ATLASSERT(m_ShellVersion >= VersionVista); //Only supported on Vista Shell
- m_NotifyIconData.dwInfoFlags |= NIIF_LARGE_ICON;
- }
- if (bRealtime)
- {
- ATLASSERT(m_ShellVersion >= VersionVista); //Only supported on Vista Shell
- m_NotifyIconData.uFlags |= NIF_REALTIME;
- }
- if (!bShow)
- {
- ATLASSERT(m_ShellVersion >= Version5); //Only supported on Shell v5 or later
- m_NotifyIconData.uFlags |= NIF_STATE;
- m_NotifyIconData.dwState = NIS_HIDDEN;
- m_NotifyIconData.dwStateMask = NIS_HIDDEN;
- }
- if (bQuietTime)
- {
- ATLASSERT(m_ShellVersion >= Version7); //Only supported on Windows 7 Shell
- m_NotifyIconData.dwInfoFlags |= NIIF_RESPECT_QUIET_TIME;
- }
-
- m_bCreated = Shell_NotifyIcon(NIM_ADD, reinterpret_cast<PNOTIFYICONDATA>(&m_NotifyIconData));
- if (m_bCreated)
- {
- if (!bShow)
- m_bHidden = TRUE;
-
- //Turn on Shell v5 tray icon behaviour
- SetVersion(NOTIFYICON_VERSION);
- }
- return m_bCreated;
- }
- #ifdef _AFX
- 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)
- #else
- 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)
- #endif //#ifdef _AFX
- {
- //Convert the bitmap to an ICON
- if (m_hDynamicIcon != NULL)
- DestroyIcon(m_hDynamicIcon);
- m_hDynamicIcon = BitmapToIcon(pBitmap);
- //Pass the buck to the other function to do the work
- return Create(pNotifyWnd, uID, pszTooltipText, pszBalloonText, pszBalloonCaption, nTimeout, style, m_hDynamicIcon, nNotifyMessage, uMenuID, bNoSound, bLargeIcon, bRealtime, hBalloonIcon, bQuietTime, bShow);
- }
- #ifdef _AFX
- 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)
- #else
- 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)
- #endif //#ifdef _AFX
- {
- //Validate our parameters
- ATLASSUME(phIcons != NULL);
- ATLASSERT(nNumIcons >= 2); //must be using at least 2 icons if you are using animation
- ATLASSERT(dwDelay);
- //let the normal Create function do its stuff
- BOOL bSuccess = Create(pNotifyWnd, uID, pszTooltipText, pszBalloonText, pszBalloonCaption, nTimeout, style, phIcons[0], nNotifyMessage, uMenuID, bNoSound, bLargeIcon, bRealtime, hBalloonIcon, bQuietTime, bShow);
- if (bSuccess)
- {
- //Start the animation
- bSuccess = StartAnimation(phIcons, nNumIcons, dwDelay);
- }
- return bSuccess;
- }
- 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)
- {
- if (!m_bCreated)
- return FALSE;
- //Validate our parameters
- ATLASSERT(m_ShellVersion >= Version5); //Only supported on Shell v5 or later
- #ifdef _DEBUG
- NOTIFYICONDATA_2 dummy;
- ATLASSERT(_tcslen(pszBalloonText) < _countof(dummy.szInfo));
- ATLASSERT(_tcslen(pszBalloonCaption) < _countof(dummy.szInfoTitle));
- DBG_UNREFERENCED_LOCAL_VARIABLE(dummy);
- #endif //#ifdef _DEBUG
- //Call the Shell_NotifyIcon function
- m_NotifyIconData.uFlags = NIF_INFO;
- _tcsncpy_s(m_NotifyIconData.szInfo, _countof(m_NotifyIconData.szInfo), pszBalloonText, _TRUNCATE);
- _tcsncpy_s(m_NotifyIconData.szInfoTitle, _countof(m_NotifyIconData.szInfoTitle), pszBalloonCaption, _TRUNCATE);
- m_NotifyIconData.uTimeout = nTimeout;
- switch (style)
- {
- case Warning:
- {
- m_NotifyIconData.dwInfoFlags = NIIF_WARNING;
- break;
- }
- case Error:
- {
- m_NotifyIconData.dwInfoFlags = NIIF_ERROR;
- break;
- }
- case Info:
- {
- m_NotifyIconData.dwInfoFlags = NIIF_INFO;
- break;
- }
- case None:
- {
- m_NotifyIconData.dwInfoFlags = NIIF_NONE;
- break;
- }
- case User:
- {
- if (hBalloonIcon != NULL)
- {
- ATLASSERT(m_ShellVersion >= VersionVista);
- m_NotifyIconData.hBalloonIcon = hBalloonIcon;
- }
- else
- {
- ATLASSERT(hUserIcon != NULL); //You forget to provide a user icon
- m_NotifyIconData.uFlags |= NIF_ICON;
- m_NotifyIconData.hIcon = hUserIcon;
- }
-
- m_NotifyIconData.dwInfoFlags = NIIF_USER;
- break;
- }
- default:
- {
- ATLASSERT(FALSE);
- break;
- }
- }
- if (bNoSound)
- m_NotifyIconData.dwInfoFlags |= NIIF_NOSOUND;
- if (bLargeIcon)
- m_NotifyIconData.dwInfoFlags |= NIIF_LARGE_ICON;
- if (bRealtime)
- m_NotifyIconData.uFlags |= NIF_REALTIME;
- return Shell_NotifyIcon(NIM_MODIFY, reinterpret_cast<PNOTIFYICONDATA>(&m_NotifyIconData));
- }
- CTrayNotifyIcon::String CTrayNotifyIcon::GetBalloonText() const
- {
- //Validate our parameters
- ATLASSERT(m_ShellVersion >= Version5); //Only supported on Shell v5 or later
- String sText;
- if (m_bCreated)
- sText = m_NotifyIconData.szInfo;
- return sText;
- }
- CTrayNotifyIcon::String CTrayNotifyIcon::GetBalloonCaption() const
- {
- //Validate our parameters
- ATLASSERT(m_ShellVersion >= Version5); //Only supported on Shell v5 or later
- String sText;
- if (m_bCreated)
- sText = m_NotifyIconData.szInfoTitle;
- return sText;
- }
- UINT CTrayNotifyIcon::GetBalloonTimeout() const
- {
- //Validate our parameters
- ATLASSERT(m_ShellVersion >= Version5); //Only supported on Shell v5 or later
- UINT nTimeout = 0;
- if (m_bCreated)
- nTimeout = m_NotifyIconData.uTimeout;
- return nTimeout;
- }
- BOOL CTrayNotifyIcon::SetTooltipText(_In_ LPCTSTR pszTooltipText)
- {
- if (!m_bCreated)
- return FALSE;
- if (m_ShellVersion >= Version5) //Allow the larger size tooltip text if on Shell v5 or later
- {
- #ifdef _DEBUG
- NOTIFYICONDATA_2 dummy;
- ATLASSERT(_tcslen(pszTooltipText) < _countof(dummy.szTip));
- DBG_UNREFERENCED_LOCAL_VARIABLE(dummy);
- #endif //#ifdef _DEBUG
- }
- else
- {
- #ifdef _DEBUG
- NOTIFYICONDATA_1 dummy;
- ATLASSERT(_tcslen(pszTooltipText) < _countof(dummy.szTip));
- DBG_UNREFERENCED_LOCAL_VARIABLE(dummy);
- #endif //#ifdef _DEBUG
- }
- //Call the Shell_NotifyIcon function
- m_NotifyIconData.uFlags = NIF_TIP;
- _tcsncpy_s(m_NotifyIconData.szTip, _countof(m_NotifyIconData.szTip), pszTooltipText, _TRUNCATE);
- return Shell_NotifyIcon(NIM_MODIFY, reinterpret_cast<PNOTIFYICONDATA>(&m_NotifyIconData));
- }
- BOOL CTrayNotifyIcon::SetTooltipText(_In_ UINT nID)
- {
- String sToolTipText;
- if (!sToolTipText.LoadString(nID))
- return FALSE;
- //Let the other version of the function handle the rest
- return SetTooltipText(sToolTipText);
- }
- int CTrayNotifyIcon::GetTooltipMaxSize()
- {
- //Return the cached value if we have one
- if (m_nTooltipMaxSize != -1)
- return m_nTooltipMaxSize;
- //Otherwise calculate the maximum based on the shell version
- if (m_ShellVersion >= Version5)
- {
- NOTIFYICONDATA_2 dummy;
- m_nTooltipMaxSize = _countof(dummy.szTip) - 1; //The -1 is to allow size for the NULL terminator
- DBG_UNREFERENCED_LOCAL_VARIABLE(dummy);
- }
- else
- {
- NOTIFYICONDATA_1 dummy;
- m_nTooltipMaxSize = _countof(dummy.szTip) - 1; //The -1 is to allow size for the NULL terminator
- DBG_UNREFERENCED_LOCAL_VARIABLE(dummy);
- }
- return m_nTooltipMaxSize;
- }
- BOOL CTrayNotifyIcon::SetIcon(_In_ CBitmap* pBitmap)
- {
- //Convert the bitmap to an ICON
- if (m_hDynamicIcon != NULL)
- DestroyIcon(m_hDynamicIcon);
- m_hDynamicIcon = BitmapToIcon(pBitmap);
- //Pass the buck to the other function to do the work
- return SetIcon(m_hDynamicIcon);
- }
- BOOL CTrayNotifyIcon::SetIcon(_In_ HICON hIcon)
- {
- //Validate our parameters
- ATLASSERT(hIcon != NULL);
- if (!m_bCreated)
- return FALSE;
- //Since we are going to use one icon, stop any animation
- StopAnimation();
- //Call the Shell_NotifyIcon function
- m_NotifyIconData.uFlags = NIF_ICON;
- m_NotifyIconData.hIcon = hIcon;
- return Shell_NotifyIcon(NIM_MODIFY, reinterpret_cast<PNOTIFYICONDATA>(&m_NotifyIconData));
- }
- BOOL CTrayNotifyIcon::SetIcon(_In_ LPCTSTR lpIconName)
- {
- return SetIcon(LoadIcon(lpIconName));
- }
- BOOL CTrayNotifyIcon::SetIcon(_In_ UINT nIDResource)
- {
- return SetIcon(LoadIcon(nIDResource));
- }
- BOOL CTrayNotifyIcon::SetStandardIcon(_In_ LPCTSTR lpIconName)
- {
- return SetIcon(::LoadIcon(NULL, lpIconName));
- }
- BOOL CTrayNotifyIcon::SetStandardIcon(_In_ UINT nIDResource)
- {
- return SetIcon(::LoadIcon(NULL, MAKEINTRESOURCE(nIDResource)));
- }
- BOOL CTrayNotifyIcon::SetIcon(_In_ HICON* phIcons, _In_ int nNumIcons, _In_ DWORD dwDelay)
- {
- //Validate our parameters
- ATLASSERT(nNumIcons >= 2); //must be using at least 2 icons if you are using animation
- ATLASSUME(phIcons != NULL);
- ATLASSERT(dwDelay);
- if (!SetIcon(phIcons[0]))
- return FALSE;
- //Start the animation
- return StartAnimation(phIcons, nNumIcons, dwDelay);
- }
- HICON CTrayNotifyIcon::LoadIcon(_In_ HINSTANCE hInstance, _In_ LPCTSTR lpIconName, _In_ BOOL bLargeIcon)
- {
- 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));
- }
- HICON CTrayNotifyIcon::LoadIcon(_In_ HINSTANCE hInstance, _In_ UINT nIDResource, _In_ BOOL bLargeIcon)
- {
- return LoadIcon(hInstance, MAKEINTRESOURCE(nIDResource), bLargeIcon);
- }
- HICON CTrayNotifyIcon::LoadIcon(_In_ LPCTSTR lpIconName, _In_ BOOL bLargeIcon)
- {
- #ifdef _AFX
- return LoadIcon(AfxGetResourceHandle(), lpIconName, bLargeIcon);
- #else
- return LoadIcon(ModuleHelper::GetResourceInstance(), lpIconName, bLargeIcon);
- #endif //#ifdef _AFX
- }
- HICON CTrayNotifyIcon::LoadIcon(_In_ UINT nIDResource, _In_ BOOL bLargeIcon)
- {
- return LoadIcon(MAKEINTRESOURCE(nIDResource), bLargeIcon);
- }
- #ifdef _AFX
- BOOL CTrayNotifyIcon::SetNotificationWnd(_In_ CWnd* pNotifyWnd)
- #else
- BOOL CTrayNotifyIcon::SetNotificationWnd(_In_ CWindow* pNotifyWnd)
- #endif //#ifdef _AFX
- {
- //Validate our parameters
- ATLASSUME((pNotifyWnd != NULL) && ::IsWindow(pNotifyWnd->operator HWND()));
- if (!m_bCreated)
- return FALSE;
- //Call the Shell_NotifyIcon function
- m_pNotificationWnd = pNotifyWnd;
- m_NotifyIconData.hWnd = pNotifyWnd->operator HWND();
- m_NotifyIconData.uFlags = 0;
- return Shell_NotifyIcon(NIM_MODIFY, reinterpret_cast<PNOTIFYICONDATA>(&m_NotifyIconData));
- }
- CTrayNotifyIcon::String CTrayNotifyIcon::GetTooltipText() const
- {
- String sText;
- if (m_bCreated)
- sText = m_NotifyIconData.szTip;
- return sText;
- }
- HICON CTrayNotifyIcon::GetIcon() const
- {
- HICON hIcon = NULL;
- if (m_bCreated)
- {
- if (UsingAnimatedIcon())
- hIcon = GetCurrentAnimationIcon();
- else
- hIcon = m_NotifyIconData.hIcon;
- }
- return hIcon;
- }
- #ifdef _AFX
- CWnd* CTrayNotifyIcon::GetNotificationWnd() const
- #else
- CWindow* CTrayNotifyIcon::GetNotificationWnd() const
- #endif //#ifdef _AFX
- {
- return m_pNotificationWnd;
- }
- BOOL CTrayNotifyIcon::SetFocus()
- {
- ATLASSERT(m_ShellVersion >= Version5); //Only supported on Shell v5 or greater
- //Call the Shell_NotifyIcon function
- return Shell_NotifyIcon(NIM_SETFOCUS, reinterpret_cast<PNOTIFYICONDATA>(&m_NotifyIconData));
- }
- LRESULT CTrayNotifyIcon::OnTrayNotification(WPARAM wParam, LPARAM lParam)
- {
- BOOL bShowMenu = FALSE;
- BOOL bDoubleClick = FALSE;
- BOOL bSingleClick = FALSE;
- UINT nIconID = 0;
- if ((m_NotifyIconData.uVersion == 0) || (m_ShellVersion >= Version5))
- {
- nIconID = static_cast<UINT>(wParam);
- bShowMenu = (lParam == WM_RBUTTONUP);
- bDoubleClick = (lParam == WM_LBUTTONDBLCLK);
- bSingleClick = (lParam == WM_LBUTTONUP);
- }
- else
- {
- nIconID = HIWORD(lParam);
- bShowMenu = (LOWORD(lParam) == WM_CONTEXTMENU);
- bDoubleClick = (LOWORD(lParam) == WM_LBUTTONDBLCLK);
- bSingleClick = (LOWORD(lParam) == WM_LBUTTONUP);
- }
- //Return quickly if its not for this tray icon
- if (nIconID != m_NotifyIconData.uID)
- return 0L;
- //Show the context menu or handle the double click
- if (bShowMenu || bDoubleClick || bSingleClick)
- {
- #ifdef _AFX
- CMenu* pSubMenu = m_Menu.GetSubMenu(0);
- ATLASSUME(pSubMenu != NULL); //Your menu resource has been designed incorrectly
- #else
- CMenuHandle subMenu = m_Menu.GetSubMenu(0);
- ATLASSERT(subMenu.IsMenu());
- #endif //#ifdef _AFX
-
- if (bShowMenu)
- {
- CPoint ptCursor;
- GetCursorPos(&ptCursor);
- ::SetForegroundWindow(m_NotifyIconData.hWnd);
- #ifdef _AFX
- ::TrackPopupMenu(pSubMenu->m_hMenu, TPM_LEFTBUTTON, ptCursor.x, ptCursor.y, 0, m_NotifyIconData.hWnd, NULL);
- #else
- ::TrackPopupMenu(subMenu, TPM_LEFTBUTTON, ptCursor.x, ptCursor.y, 0, m_NotifyIconData.hWnd, NULL);
- #endif //#ifdef _AFX
- ::PostMessage(m_NotifyIconData.hWnd, WM_NULL, 0, 0);
- }
- else if (bDoubleClick || bSingleClick) //double click received, the default action is to execute first menu item
- {
- ::SetForegroundWindow(m_NotifyIconData.hWnd);
- #ifdef _AFX
- UINT nDefaultItem = pSubMenu->GetDefaultItem(GMDI_GOINTOPOPUPS, FALSE);
- #else
- UINT nDefaultItem = subMenu.GetMenuDefaultItem(FALSE, GMDI_GOINTOPOPUPS);
- #endif //#ifdef _AFX
- if (nDefaultItem != -1)
- ::SendMessage(m_NotifyIconData.hWnd, WM_COMMAND, nDefaultItem, 0);
- }
- }
- return 1; // handled
- }
- BOOL CTrayNotifyIcon::GetDynamicDCAndBitmap(_In_ CDC* pDC, _In_ CBitmap* pBitmap)
- {
- //Validate our parameters
- ATLASSUME(pDC != NULL);
- ATLASSUME(pBitmap != NULL);
- //Get the HWND for the desktop
- #ifdef _AFX
- CWnd* pWndScreen = CWnd::GetDesktopWindow();
- if (pWndScreen == NULL)
- return FALSE;
- #else
- CWindow WndScreen(::GetDesktopWindow());
- if (!WndScreen.IsWindow())
- return FALSE;
- #endif //#ifdef _AFX
- //Get the desktop HDC to create a compatible bitmap from
- #ifdef _AFX
- CDC* pDCScreen = pWndScreen->GetDC();
- if (pDCScreen == NULL)
- return FALSE;
- #else
- CDC DCScreen(WndScreen.GetDC());
- if (DCScreen.IsNull())
- return FALSE;
- #endif //#ifdef _AFX
- //Get the width and height of a small icon
- int w = GetSystemMetrics(SM_CXSMICON);
- int h = GetSystemMetrics(SM_CYSMICON);
- //Create an off-screen bitmap that the dynamic tray icon
- //can be drawn into (Compatible with the desktop DC)
- #ifdef _AFX
- BOOL bSuccess = pBitmap->CreateCompatibleBitmap(pDCScreen, w, h);
- #else
- BOOL bSuccess = (pBitmap->CreateCompatibleBitmap(DCScreen.operator HDC(), w, h) != NULL);
- #endif //#ifdef _AFX
- if (!bSuccess)
- {
- #ifdef _AFX
- pWndScreen->ReleaseDC(pDCScreen);
- #else
- WndScreen.ReleaseDC(DCScreen);
- #endif //#ifdef _AFX
- return FALSE;
- }
- //Get a HDC to the newly created off-screen bitmap
- #ifdef _AFX
- bSuccess = pDC->CreateCompatibleDC(pDCScreen);
- #else
- bSuccess = (pDC->CreateCompatibleDC(DCScreen.operator HDC()) != NULL);
- #endif //#ifdef _AFX
- if (!bSuccess)
- {
- //Release the Screen DC now that we are finished with it
- #ifdef _AFX
- pWndScreen->ReleaseDC(pDCScreen);
- #else
- WndScreen.ReleaseDC(DCScreen);
- #endif //#ifdef _AFX
- //Free up the bitmap now that we are finished with it
- pBitmap->DeleteObject();
- return FALSE;
- }
- //Select the bitmap into the offscreen DC
- #ifdef _AFX
- pDC->SelectObject(pBitmap);
- #else
- pDC->SelectBitmap(pBitmap->operator HBITMAP());
- #endif //#ifdef _AFX
- //Release the Screen DC now that we are finished with it
- #ifdef _AFX
- pWndScreen->ReleaseDC(pDCScreen);
- #else
- WndScreen.ReleaseDC(DCScreen);
- #endif //#ifdef _AFX
- return TRUE;
- }
- DWORD CTrayNotifyIcon::GetNOTIFYICONDATASizeForOS()
- {
- //What will be the return value from this function
- DWORD dwSize = sizeof(NOTIFYICONDATA_1);
- switch (m_ShellVersion)
- {
- case Version7: //Deliberate fallthrough
- case VersionVista:
- {
- dwSize = sizeof(NOTIFYICONDATA_4);
- break;
- }
- case Version6:
- {
- dwSize = sizeof(NOTIFYICONDATA_3);
- break;
- }
- case Version5:
- {
- dwSize = sizeof(NOTIFYICONDATA_2);
- break;
- }
- default:
- {
- break;
- }
- }
-
- return dwSize;
- }
- BOOL CTrayNotifyIcon::StartAnimation(_In_ HICON* phIcons, _In_ int nNumIcons, _In_ DWORD dwDelay)
- {
- //Validate our parameters
- ATLASSERT(nNumIcons >= 2); //must be using at least 2 icons if you are using animation
- ATLASSUME(phIcons != NULL); //array of icon handles must be valid
- ATLASSERT(dwDelay); //must be non zero timer interval
- //Stop the animation if already started
- StopAnimation();
- //Hive away all the values locally
- ATLASSERT(m_Icons.m_pData == NULL);
- if (!m_Icons.Allocate(nNumIcons))
- return FALSE;
- ATLASSUME(m_Icons.m_pData != NULL);
- for (int i=0; i<nNumIcons; i++)
- m_Icons.m_pData[i] = phIcons[i];
- m_nNumIcons = nNumIcons;
- //Start up the timer
- m_nTimerID = SetTimer(m_NotifyIconData.uID, dwDelay);
- return TRUE;
- }
- void CTrayNotifyIcon::StopAnimation()
- {
- //Kill the timer
- if (m_nTimerID)
- {
- if (::IsWindow(m_hWnd))
- KillTimer(m_nTimerID);
- m_nTimerID = 0;
- }
-
- //Free up the memory
- if (m_Icons.m_pData != NULL)
- m_Icons.Free();
- //Reset the other animation related variables
- m_nCurrentIconIndex = 0;
- m_nNumIcons = 0;
- }
- BOOL CTrayNotifyIcon::UsingAnimatedIcon() const
- {
- return (m_nNumIcons != 0);
- }
- HICON CTrayNotifyIcon::GetCurrentAnimationIcon() const
- {
- //Valiate our parameters
- ATLASSERT(UsingAnimatedIcon());
- ATLASSUME(m_Icons.m_pData != NULL);
-
- return m_Icons.m_pData[m_nCurrentIconIndex];
- }
- BOOL CTrayNotifyIcon::ProcessWindowMessage(_In_ HWND /*hWnd*/, _In_ UINT nMsg, _In_ WPARAM wParam, _In_ LPARAM lParam, _Inout_ LRESULT& lResult, _In_ DWORD /*dwMsgMapID*/)
- {
- lResult = 0;
- BOOL bHandled = FALSE;
- if (nMsg == wm_TaskbarCreated)
- {
- lResult = OnTaskbarCreated(wParam, lParam);
- bHandled = TRUE;
- }
- else if ((nMsg == WM_TIMER) && (wParam == m_NotifyIconData.uID))
- {
- OnTimer(m_NotifyIconData.uID);
- bHandled = TRUE;
- }
- else if (nMsg == WM_DESTROY)
- {
- OnDestroy();
- bHandled = TRUE;
- }
- return bHandled;
- }
- void CTrayNotifyIcon::OnDestroy()
- {
- StopAnimation();
- }
- LRESULT CTrayNotifyIcon::OnTaskbarCreated(WPARAM /*wParam*/, LPARAM /*lParam*/)
- {
- //Refresh the tray icon if necessary
- BOOL bShowing = IsShowing();
- Delete(FALSE);
- Create(bShowing);
-
- return 0;
- }
- #ifdef _DEBUG
- void CTrayNotifyIcon::OnTimer(UINT_PTR nIDEvent)
- #else
- void CTrayNotifyIcon::OnTimer(UINT_PTR /*nIDEvent*/)
- #endif //#ifdef _DEBUG
- {
- //Validate our parameters
- ATLASSERT(nIDEvent == m_nTimerID);
- ATLASSUME(m_Icons.m_pData != NULL);
- //increment the icon index
- ++m_nCurrentIconIndex;
- m_nCurrentIconIndex = m_nCurrentIconIndex % m_nNumIcons;
- //update the tray icon
- m_NotifyIconData.uFlags = NIF_ICON;
- m_NotifyIconData.hIcon = m_Icons.m_pData[m_nCurrentIconIndex];
- Shell_NotifyIcon(NIM_MODIFY, reinterpret_cast<PNOTIFYICONDATA>(&m_NotifyIconData));
- }
- BOOL CTrayNotifyIcon::CreateHelperWindow()
- {
- //Let the base class do its thing
- return (CWindowImpl<CTrayNotifyIcon>::Create(NULL, CWindow::rcDefault, _T("CTrayNotifyIcon Helper Window"), WS_OVERLAPPEDWINDOW) != NULL);
- }
- CTrayWnd CTrayNotifyIcon::m_wndInvisible;
- BOOL CTrayNotifyIcon::RemoveTaskbarIcon(CWnd* pWnd)
- {
- LPCTSTR pstrOwnerClass = AfxRegisterWndClass(0);
- // Create static invisible window
- if (!::IsWindow(m_wndInvisible.m_hWnd))
- {
- if (!m_wndInvisible.CreateEx(0, pstrOwnerClass, _T(""), WS_POPUP,
- CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
- NULL, 0))
- {
- return FALSE;
- }
- }
- pWnd->SetParent(&m_wndInvisible);
- return TRUE;
- }
- void CTrayNotifyIcon::MinimiseToTray(CWnd* pWnd)
- {
- RemoveTaskbarIcon(pWnd);
- pWnd->ModifyStyle(WS_VISIBLE, 0);
- }
- void CTrayNotifyIcon::MaximiseFromTray(CWnd* pWnd)
- {
- pWnd->SetParent(NULL);
- pWnd->ModifyStyle(0, WS_VISIBLE);
- pWnd->RedrawWindow(NULL, NULL, RDW_UPDATENOW | RDW_ALLCHILDREN | RDW_FRAME |
- RDW_INVALIDATE | RDW_ERASE);
- // Move focus away and back again to ensure taskbar icon is recreated
- if (::IsWindow(m_wndInvisible.m_hWnd))
- m_wndInvisible.SetActiveWindow();
- pWnd->SetActiveWindow();
- pWnd->SetForegroundWindow();
- }
|