1399 lines
48 KiB
C++
1399 lines
48 KiB
C++
/*
|
|
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: pjna@naughter.com)
|
|
|
|
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)
|
|
{
|
|
//Validate our parameters
|
|
ATLASSERT(hMenu);
|
|
|
|
m_Menu.DestroyMenu();
|
|
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;
|
|
UINT nIconID = 0;
|
|
if ((m_NotifyIconData.uVersion == 0) || (m_NotifyIconData.uVersion == NOTIFYICON_VERSION))
|
|
{
|
|
nIconID = static_cast<UINT>(wParam);
|
|
bShowMenu = (lParam == WM_RBUTTONUP);
|
|
bDoubleClick = (lParam == WM_LBUTTONDBLCLK);
|
|
}
|
|
else
|
|
{
|
|
nIconID = HIWORD(lParam);
|
|
bShowMenu = (LOWORD(lParam) == WM_CONTEXTMENU);
|
|
bDoubleClick = (LOWORD(lParam) == WM_LBUTTONDBLCLK);
|
|
}
|
|
|
|
//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)
|
|
{
|
|
#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) //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);
|
|
}
|