trayicon.cpp
来自「管理项目进度工具的原代码」· C++ 代码 · 共 476 行
CPP
476 行
// TrayIcon.cpp : implementation of the CTrayIcon class
//
#include "stdafx.h"
#include "TrayIcon.h"
#include "autoflag.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
const UINT WM_TINOTIFY = (WM_APP+1);
const UINT WM_TASKBARCREATED = ::RegisterWindowMessage(_T("TaskbarCreated"));
enum
{
TIMER_ANIMATE = 1,
TIMER_SINGLECLK,
};
#ifndef NIF_STATE
# define NIF_STATE 0x0008
# define NIF_INFO 0x0010
#endif
struct NOTIFYICONDATA_TI
{
DWORD cbSize;
HWND hWnd;
UINT uID;
UINT uFlags;
UINT uCallbackMessage;
HICON hIcon;
CHAR szTip[128];
DWORD dwState;
DWORD dwStateMask;
CHAR szInfo[256];
UINT uTimeout;
CHAR szInfoTitle[64];
DWORD dwInfoFlags;
};
//////////////////////////////////////////////////////////////////////////
///
// CTrayIcon
BEGIN_MESSAGE_MAP(CTrayIcon, CWnd)
//{{AFX_MSG_MAP(CTrayIcon)
ON_WM_DESTROY()
ON_WM_TIMER()
//}}AFX_MSG_MAP
ON_MESSAGE(WM_TINOTIFY, OnTrayIconNotify)
END_MESSAGE_MAP()
//////////////////////////////////////////////////////////////////////////
///
// CTrayIcon construction/destruction
CTrayIcon::CTrayIcon()
{
m_hIcon = NULL;
m_bVisible = FALSE;
memset(&m_nm, 0, sizeof(m_nm));
m_sTip = _T("");
m_bAnimationOn = FALSE;
m_nPrevMsg = 0;
}
CTrayIcon::~CTrayIcon()
{
}
// this Create takes an ID for the tip text
BOOL CTrayIcon::Create(DWORD dwStyle, CWnd* pParentWnd, UINT uID, UINT uIDIcon, UINT uIDTip)
{
if (!CWnd::Create(NULL, _T("TrayIcon notification window"), WS_CHILD,
CRect(0,0,0,0), pParentWnd, uID))
return FALSE;
m_hIcon = AfxGetApp()->LoadIcon(uIDIcon);
m_sTip.LoadString(uIDTip);
m_nm.hdr.hwndFrom = GetSafeHwnd();
m_nm.hdr.idFrom = GetDlgCtrlID();
if (dwStyle & WS_VISIBLE)
ShowTrayIcon();
return TRUE;
}
// this create takes a text string for the ti text
BOOL CTrayIcon::Create(DWORD dwStyle, CWnd* pParentWnd, UINT uID, UINT uIDIcon, LPCTSTR sTip)
{
if (!CWnd::Create(NULL, _T("TrayIcon notification window"), WS_CHILD,
CRect(0,0,0,0), pParentWnd, uID))
return FALSE;
m_hIcon = AfxGetApp()->LoadIcon(uIDIcon);
m_sTip = sTip;
m_nm.hdr.hwndFrom = GetSafeHwnd();
m_nm.hdr.idFrom = GetDlgCtrlID();
if (dwStyle & WS_VISIBLE)
ShowTrayIcon();
return TRUE;
}
void CTrayIcon::ShowTrayIcon(BOOL bShow /*=TRUE*/)
{
if (bShow && !m_bVisible)
{
AddToTray();
m_bVisible = TRUE;
}
else if (!bShow && m_bVisible)
{
DeleteFromTray();
m_bVisible = FALSE;
}
}
//////////////////////////////////////////////////////////////////////////
///
// CTrayIcon message handlers
void CTrayIcon::OnDestroy()
{
CWnd::OnDestroy();
ShowTrayIcon(FALSE);
}
LRESULT CTrayIcon::OnTrayIconNotify(WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(wParam);
// prevent reentrancy
static BOOL bInNotify = FALSE;
if (bInNotify || !GetParent()->IsWindowEnabled())
return 0L;
CAutoFlag af(bInNotify, TRUE);
BOOL bNotify = TRUE;
GetCursorPos(&m_nm.ptAction);
switch (lParam)
{
case WM_MOUSEMOVE:
case WM_LBUTTONDOWN:
bNotify = FALSE;
break;
case WM_LBUTTONUP:
if (m_nPrevMsg == WM_LBUTTONDOWN) // start a timer to test for double click
{
UINT nDelay = GetDoubleClickTime();
SetTimer(TIMER_SINGLECLK, nDelay, NULL);
}
bNotify = FALSE; // we'll handle it in OnTimer
break;
case WM_LBUTTONDBLCLK:
// if we got here then the timer has not yet been tripped so it's a double click
if (m_nPrevMsg == WM_LBUTTONUP)
{
KillTimer(TIMER_SINGLECLK);
m_nm.hdr.code = NM_DBLCLK;
}
break;
case WM_RBUTTONDOWN:
bNotify = FALSE;
break;
case WM_RBUTTONUP:
if (m_nPrevMsg == WM_RBUTTONDOWN)
m_nm.hdr.code = NM_RCLICK;
else
bNotify = FALSE;
break;
case WM_RBUTTONDBLCLK:
m_nm.hdr.code = NM_RDBLCLK;
break;
case WM_MBUTTONDOWN:
case WM_MBUTTONUP:
case WM_MBUTTONDBLCLK:
bNotify = FALSE;
break;
default:
bNotify = FALSE;
break;
}
if (lParam != WM_MOUSEMOVE)
m_nPrevMsg = lParam;
if (!bNotify)
return TRUE;
LRESULT lr = GetParent()->SendMessage(WM_NOTIFY, GetDlgCtrlID(),
(LPARAM)&m_nm);
return lr;
}
BOOL CTrayIcon::AddToTray()
{
NOTIFYICONDATA_TI nid;
nid.cbSize = sizeof(nid);
nid.hWnd = GetSafeHwnd();
nid.uID = GetDlgCtrlID();
nid.uFlags = NIF_MESSAGE | NIF_ICON;
nid.uCallbackMessage = WM_TINOTIFY;
nid.hIcon = m_hIcon;
if (!m_sTip.IsEmpty())
{
nid.uFlags |= NIF_TIP;
//fabio_2005
#if _MSC_VER >= 1400
_tcsncpy_s(nid.szTip, (LPTSTR)(LPCTSTR)m_sTip, sizeof(nid.szTip)/sizeof(TCHAR));
#else
_tcsncpy(nid.szTip, (LPTSTR)(LPCTSTR)m_sTip, sizeof(nid.szTip)/sizeof(TCHAR));
#endif
nid.szTip[sizeof(nid.szTip)/sizeof(TCHAR)-1] = (TCHAR)0;
}
// create top level parent hook first time around
if (!ScIsHooked())
{
CWnd* pTLParent = GetTopLevelParent();
if (pTLParent)
ScHookWindow(pTLParent->GetSafeHwnd());
}
return Shell_NotifyIcon(NIM_ADD, (PNOTIFYICONDATA)&nid);
}
BOOL CTrayIcon::DeleteFromTray()
{
NOTIFYICONDATA_TI nid;
nid.cbSize = sizeof(nid);
nid.hWnd = GetSafeHwnd();
nid.uID = GetDlgCtrlID();
return Shell_NotifyIcon(NIM_DELETE, (PNOTIFYICONDATA)&nid);
}
BOOL CTrayIcon::ModifyIcon(UINT uIDNewIcon)
{
NOTIFYICONDATA_TI nid;
nid.cbSize = sizeof(nid);
nid.hWnd = GetSafeHwnd();
nid.uID = GetDlgCtrlID();
nid.uFlags = NIF_ICON;
nid.hIcon = m_hIcon = AfxGetApp()->LoadIcon(uIDNewIcon);
return Shell_NotifyIcon(NIM_MODIFY, (PNOTIFYICONDATA)&nid);
}
BOOL CTrayIcon::ModifyTip(UINT uIDNewTip)
{
NOTIFYICONDATA_TI nid;
nid.cbSize = sizeof(nid);
nid.hWnd = GetSafeHwnd();
nid.uID = GetDlgCtrlID();
nid.uFlags = 0;
m_sTip.LoadString(uIDNewTip);
if (!m_sTip.IsEmpty())
{
nid.uFlags |= NIF_TIP;
//fabio_2005
#if _MSC_VER >= 1300
_tcsncpy_s(nid.szTip, (LPTSTR)(LPCTSTR)m_sTip, sizeof(nid.szTip)/sizeof(TCHAR));
#else
_tcsncpy(nid.szTip, (LPTSTR)(LPCTSTR)m_sTip, sizeof(nid.szTip)/sizeof(TCHAR));
#endif
nid.szTip[sizeof(nid.szTip)/sizeof(TCHAR)-1] = (TCHAR)0;
}
return Shell_NotifyIcon(NIM_MODIFY, (PNOTIFYICONDATA)&nid);
}
BOOL CTrayIcon::ModifyTip(LPCTSTR sNewTip)
{
NOTIFYICONDATA_TI nid;
nid.cbSize = sizeof(nid);
nid.hWnd = GetSafeHwnd();
nid.uID = GetDlgCtrlID();
nid.uFlags = 0;
m_sTip = sNewTip;
if (!m_sTip.IsEmpty())
{
nid.uFlags |= NIF_TIP;
//fabio_2005
#if _MSC_VER >= 1300
_tcsncpy_s(nid.szTip, (LPTSTR)(LPCTSTR)m_sTip, sizeof(nid.szTip)/sizeof(TCHAR));
#else
_tcsncpy(nid.szTip, (LPTSTR)(LPCTSTR)m_sTip, sizeof(nid.szTip)/sizeof(TCHAR));
#endif
nid.szTip[sizeof(nid.szTip)/sizeof(TCHAR)-1] = (TCHAR)0;
}
return Shell_NotifyIcon(NIM_MODIFY, (PNOTIFYICONDATA)&nid);
}
BOOL CTrayIcon::SetIcon(UINT uIDNewIcon)
{
if (m_bAnimationOn)
StopAnimation();
return ModifyIcon(uIDNewIcon);
}
BOOL CTrayIcon::SetTip(UINT uIDNewTip)
{
return ModifyTip(uIDNewTip);
}
BOOL CTrayIcon::SetTip(LPCTSTR sNewTip)
{
return ModifyTip(sNewTip);
}
void CTrayIcon::StartAnimation()
{
ASSERT (m_aAnimationIconIDs.GetSize() && m_nAnimationDelay >= 100);
m_nCurIcon = 0; // reset animation
ModifyIcon(m_aAnimationIconIDs[m_nCurIcon]);
SetTimer(TIMER_ANIMATE, m_nAnimationDelay, NULL);
m_bAnimationOn = TRUE;
}
void CTrayIcon::StopAnimation()
{
if (!m_bAnimationOn)
return;
KillTimer(1);
m_bAnimationOn = FALSE;
// reset animation
ModifyIcon(m_aAnimationIconIDs[0]);
}
void CTrayIcon::OnTimer(UINT nIDEvent)
{
switch (nIDEvent)
{
case TIMER_ANIMATE:
m_nCurIcon++;
m_nCurIcon %= m_aAnimationIconIDs.GetSize();
ModifyIcon(m_aAnimationIconIDs[m_nCurIcon]);
break;
case TIMER_SINGLECLK:
// if we got here then the double click did not happen
// so we can issue a single click
KillTimer(TIMER_SINGLECLK);
m_nPrevMsg = 0;
m_nm.hdr.code = NM_CLICK;
GetParent()->SendMessage(WM_NOTIFY, GetDlgCtrlID(), (LPARAM)&m_nm);
break;
}
CWnd::OnTimer(nIDEvent);
}
void CTrayIcon::SetAnimationIcons(UINT pIconIDs[], int nNumIcons)
{
ASSERT (pIconIDs != NULL && nNumIcons > 1);
m_aAnimationIconIDs.SetSize(nNumIcons);
while (nNumIcons--)
m_aAnimationIconIDs.SetAt(nNumIcons, pIconIDs[nNumIcons]);
}
void CTrayIcon::SetAnimationDelay(int nDelay)
{
ASSERT (nDelay >= 100);
m_nAnimationDelay = max(nDelay, 100);
if (m_bAnimationOn)
{
KillTimer(1);
StartAnimation();
}
}
LRESULT CTrayIcon::ScWindowProc(HWND hRealWnd, UINT msg, WPARAM wp, LPARAM lp)
{
if (msg == WM_TASKBARCREATED && m_bVisible)
{
AddToTray();
}
return CSubclasser::ScWindowProc(hRealWnd, msg, wp, lp);
}
BOOL CTrayIcon::ShowBalloon(LPCTSTR szText, LPCTSTR szTitle, DWORD dwIcon, UINT uTimeout)
{
// Verify input parameters.
if (uTimeout <= 0)
return FALSE;
// The balloon tooltip text can be up to 255 chars long.
ASSERT(AfxIsValidString(szText));
ASSERT(lstrlen(szText) < 256);
// The balloon title text can be up to 63 chars long.
if (szTitle)
{
ASSERT(AfxIsValidString( szTitle));
ASSERT(lstrlen(szTitle) < 64);
}
// dwBalloonIcon must be valid.
ASSERT(NIIF_NONE == dwIcon || NIIF_INFO == dwIcon ||
NIIF_WARNING == dwIcon || NIIF_ERROR == dwIcon);
// The timeout must be between 10 and 30 seconds.
uTimeout = min(max(uTimeout, 10), 30);
NOTIFYICONDATA_TI nid;
nid.cbSize = sizeof(nid);
nid.hWnd = GetSafeHwnd();
nid.uID = GetDlgCtrlID();
nid.uFlags = NIF_INFO;
//fabio_2005
#if _MSC_VER >= 1300
_tcsncpy_s(nid.szInfo, szText, 256);
if (szTitle)
_tcsncpy_s(nid.szInfoTitle, szTitle, 64);
#else
_tcsncpy(nid.szInfo, szText, 256);
if (szTitle)
_tcsncpy(nid.szInfoTitle, szTitle, 64);
#endif
else
nid.szInfoTitle[0] = _T('\0');
nid.dwInfoFlags = dwIcon;
nid.uTimeout = uTimeout * 1000; // convert time to ms
return Shell_NotifyIcon(NIM_MODIFY, (PNOTIFYICONDATA)&nid);
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?