// SystemIcon.cpp : implementation file
#include " stdafx.h "
#include " SystemIcon.h "
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
IMPLEMENT_DYNAMIC(CSystemIcon, CObject)
/**/ /////
CSystemIcon::CSystemIcon()
... {
memset(&m_tnd, 0, sizeof(m_tnd));
m_bEnabled = FALSE;
m_bHidden = FALSE;
}
CSystemIcon::CSystemIcon(CWnd * pWnd, UINT uCallbackMessage, LPCTSTR szToolTip,
HICON icon, UINT uID)
... {
Create(pWnd, uCallbackMessage, szToolTip, icon, uID);
m_bHidden = FALSE;
}
BOOL CSystemIcon::Create(CWnd * pWnd, UINT uCallbackMessage, LPCTSTR szToolTip,
HICON icon, UINT uID)
... {
//文件只能使用在WINDOW 95以上的版本中
VERIFY(m_bEnabled = ( GetVersion() & 0xff ) >= 4);
if (!m_bEnabled)
return FALSE;
//确认通知窗口有效
VERIFY(m_bEnabled = (pWnd && ::IsWindow(pWnd->GetSafeHwnd())));
if (!m_bEnabled)
return FALSE;
//确认自定义消息大于WM_USER
ASSERT(uCallbackMessage >= WM_USER);
//确定提示文本长度小于64
ASSERT(_tcslen(szToolTip) <= 64);
//定义NOTIFYICONDATA结构的数据项
m_tnd.cbSize = sizeof(NOTIFYICONDATA);
m_tnd.hWnd = pWnd->GetSafeHwnd();
m_tnd.uID = uID;
m_tnd.hIcon = icon;
m_tnd.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
m_tnd.uCallbackMessage = uCallbackMessage;
strcpy (m_tnd.szTip, szToolTip);
//设置图标
VERIFY(m_bEnabled = Shell_NotifyIcon(NIM_ADD, &m_tnd));
return m_bEnabled;
}
CSystemIcon:: ~ CSystemIcon()
... {
DeleteIcon();
}
/**/ /////
void CSystemIcon::DeleteIcon()
... {
if (!m_bEnabled)
return;
m_tnd.uFlags = 0;
Shell_NotifyIcon(NIM_DELETE, &m_tnd);
m_bEnabled = FALSE;
}
void CSystemIcon::HideIcon()
... {
if (m_bEnabled && !m_bHidden)
...{
m_tnd.uFlags = NIF_ICON;
Shell_NotifyIcon (NIM_DELETE, &m_tnd);
m_bHidden = TRUE;
}
}
void CSystemIcon::ShowIcon()
... {
if (m_bEnabled && m_bHidden)
...{
m_tnd.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
Shell_NotifyIcon(NIM_ADD, &m_tnd);
m_bHidden = FALSE;
}
}
BOOL CSystemIcon::SetIcon(HICON hIcon)
... {
if (!m_bEnabled)
return FALSE;
m_tnd.uFlags = NIF_ICON;
m_tnd.hIcon = hIcon;
return Shell_NotifyIcon(NIM_MODIFY, &m_tnd);
}
BOOL CSystemIcon::SetIcon(LPCTSTR lpszIconName)
... {
HICON hIcon = AfxGetApp()->LoadIcon(lpszIconName);
return SetIcon(hIcon);
}
BOOL CSystemIcon::SetIcon(UINT nIDResource)
... {
HICON hIcon = AfxGetApp()->LoadIcon(nIDResource);
return SetIcon(hIcon);
}
BOOL CSystemIcon::SetStandardIcon(LPCTSTR lpIconName)
... {
HICON hIcon = LoadIcon(NULL, lpIconName);
return SetIcon(hIcon);
}
BOOL CSystemIcon::SetStandardIcon(UINT nIDResource)
... {
HICON hIcon = LoadIcon(NULL, MAKEINTRESOURCE(nIDResource));
return SetIcon(hIcon);
}
HICON CSystemIcon::GetIcon() const
... {
HICON hIcon = NULL;
if (m_bEnabled)
hIcon = m_tnd.hIcon;
return hIcon;
}
BOOL CSystemIcon::SetTooltipText(LPCTSTR pszTip)
... {
if (!m_bEnabled) return FALSE;
m_tnd.uFlags = NIF_TIP;
_tcscpy(m_tnd.szTip, pszTip);
return Shell_NotifyIcon(NIM_MODIFY, &m_tnd);
}
BOOL CSystemIcon::SetTooltipText(UINT nID)
... {
CString strText;
VERIFY(strText.LoadString(nID));
return SetTooltipText(strText);
}
CString CSystemIcon::GetTooltipText() const
... {
CString strText;
if (m_bEnabled)
strText = m_tnd.szTip;
return strText;
}
BOOL CSystemIcon::SetNotificationWnd(CWnd * pWnd)
... {
if (!m_bEnabled)
return FALSE;
ASSERT(pWnd && ::IsWindow(pWnd->GetSafeHwnd()));
m_tnd.hWnd = pWnd->GetSafeHwnd();
m_tnd.uFlags = 0;
return Shell_NotifyIcon(NIM_MODIFY, &m_tnd);
}
CWnd * CSystemIcon::GetNotificationWnd() const
... {
return CWnd::FromHandle(m_tnd.hWnd);
}
LRESULT CSystemIcon::OnIconNotification(UINT wParam, LONG lParam)
... {
if (wParam != m_tnd.uID)
return 0;
CMenu menu, *pSubMenu;
//单击右键弹出菜单
if (LOWORD(lParam) == WM_RBUTTONUP)
...{
if (!menu.LoadMenu(m_tnd.uID))
return 0;
if (!(pSubMenu = menu.GetSubMenu(0)))
return 0;
//设定第一项为缺省
::SetMenuDefaultItem(pSubMenu->m_hMenu, 0, TRUE);
//定义弹出菜单
CPoint pos;
GetCursorPos(&pos);
::SetForegroundWindow(m_tnd.hWnd);
::TrackPopupMenu(pSubMenu->m_hMenu, 0, pos.x, pos.y, 0, m_tnd.hWnd, NULL);
::PostMessage(m_tnd.hWnd, WM_NULL, 0, 0);
menu.DestroyMenu();
}
else if (LOWORD(lParam) == WM_LBUTTONDBLCLK)
...{
if (!menu.LoadMenu(m_tnd.uID))
return 0;
if (!(pSubMenu = menu.GetSubMenu(0)))
return 0;
//双击左键启动缺省菜单
::SetForegroundWindow(m_tnd.hWnd);
::SendMessage(m_tnd.hWnd, WM_COMMAND, pSubMenu->GetMenuItemID(0), 0);
menu.DestroyMenu();
}
else if (LOWORD(lParam) == WM_LBUTTONDOWN)
...{
if (!IsWindowVisible(m_tnd.hWnd))
...{
ShowWindow(m_tnd.hWnd,SW_SHOW);
}
else
...{
ShowWindow(m_tnd.hWnd,SW_HIDE);
}
}
return 1;
}
.h;
// SystemIcon.h : header file
//
#ifndef _INCLUDED_SYSTEMICON_H_
#define _INCLUDED_SYSTEMICON_H_
/**/ /////
// CSystemIcon window
class CSystemIcon : public CObject
... {
// Construction/destruction
public:
CSystemIcon();
CSystemIcon(CWnd* pWnd, UINT uCallbackMessage, LPCTSTR szTip, HICON icon, UINT uID);
virtual ~CSystemIcon();
// Operations
public:
BOOL Enabled() ...{ return m_bEnabled; }
BOOL Visible() ...{ return !m_bHidden; }
//创建系统图标
Create(CWnd* pWnd, UINT uCallbackMessage, LPCTSTR szTip, HICON icon, UINT uID);
//关于提示文本
BOOL SetTooltipText(LPCTSTR pszTooltipText);
BOOL SetTooltipText(UINT nID);
CString GetTooltipText() const;
//关于图标
BOOL SetIcon(HICON hIcon);
BOOL SetIcon(LPCTSTR lpIconName);
BOOL SetIcon(UINT nIDResource);
BOOL SetStandardIcon(LPCTSTR lpIconName);
BOOL SetStandardIcon(UINT nIDResource);
HICON GetIcon() const;
void HideIcon();
void ShowIcon();
void DeleteIcon();
//关于通知窗口
BOOL SetNotificationWnd(CWnd* pNotifyWnd);
CWnd* GetNotificationWnd() const;
//自定义消息处理函数
virtual LRESULT OnIconNotification(WPARAM uID, LPARAM lEvent);
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CSystemIcon)
//}}AFX_VIRTUAL
// Implementation
protected:
BOOL m_bEnabled; //是否支持图标
BOOL m_bHidden; //是否隐藏图标
NOTIFYICONDATA m_tnd; //数据结构,请参考在线帮助
DECLARE_DYNAMIC(CSystemIcon)
} ;
#endif
使用说明:
a,基于对话框
1. 将SystemIcon.h和SystemIcon.cpp拷贝到项目工作目录,再添加到项目里。
在XXXDlg.h中加入
#include "SystemIcon.h"
2. 为XXXDlg类添加protected变量:CSystemIcon m_trayIcon
3. 建立托盘菜单
也就是当程序隐藏到任务栏上时,你用右键点击托盘图标时显示出的右键菜单。
新建一个Menu资源,命名为IDR_THETRAY。
为这个菜单添加你想要的子菜单。例如:
IDC_ABOUT 关于
IDC_SHOW 显示/隐藏
ID_APP_EXIT 退出
用ClassWizard为IDC_ABOUT添加响应函数OnAbout():
CAboutDlg aboutdlg;
aboutdlg.DoModal();
用ClassWizard为IDC_SHOW添加响应函数OnShow():
if (!IsWindowVisible()) {
ShowWindow(SW_SHOW);
}
else{
ShowWindow(SW_HIDE);
}
4. 在XXDlg头文件中加入:
#define WM_USER_TRAY_NOTIFICATION (WM_USER+0x101)
在cpp文件的OnInitDialog()里添加:
m_trayIcon.Create(this, WM_USER_TRAY_NOTIFICATION, "Blhaaa",
m_hIcon, IDR_THETRAY);//在这里实现了当鼠标放在托盘
//上时会出现一句话Blhaaa
这时编译运行之后你就会看到任务栏上出现了系统托盘,但右键没有响应。
这是因为我们还没有加入消息和消息映射。
5. 在XXXDlg类中加入下面函数:
声明:
afx_msg LRESULT CStuClientDlg::OnIconNotification(WPARAM wParam, LPARAM lParam);
函数定义:
LRESULT CStuClientDlg::OnIconNotification(WPARAM wParam, LPARAM lParam)
{
//return m_systemIcon.OnIconNotification(wParam, lParam);
switch ( lParam )
{
case WM_RBUTTONDOWN:
{
// 用户在托盘图标上单击鼠标右键,弹出上下文菜单隐藏/显示对话框。
CMenu oMenu;
if (oMenu.LoadMenu(IDR_THETRAY))
{
CMenu* pPopup = oMenu.GetSubMenu(0);
ASSERT(pPopup != NULL);
CPoint oPoint;
if (IsWindowVisible())//根据对话框窗口的显示/隐藏状态
//修改菜单名称
oMenu.ModifyMenu(IDC_SHOW,MF_STRING,IDC_SHOW,"隐藏(&H)");
else
oMenu.ModifyMenu(IDC_SHOW,MF_STRING,IDC_SHOW,"显示(&S)");
// 确定鼠标位置以便在该位置附近显示菜单
GetCursorPos( &oPoint );
SetForegroundWindow();
pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON,
oPoint.x, oPoint.y, this);
}
}
break;
// 单击/双击鼠标左键均显示出对话框
case WM_LBUTTONDBLCLK:
case WM_LBUTTONDOWN:
OnShow();
break;
}
return 0;
}
6. 加入消息映射:
LONG CStuClientDlg::OnTrayNotification(WPARAM wparam, LPARAM lparam)
{
switch ( lparam ){// The tray icon sent us a message.
//Let's see what it is
/*case WM_CONTEXTMENU:
TRACE( "WM_CONTEXTMENU/n" );*/
case WM_RBUTTONDOWN:
{// 用户在托盘图标上单击鼠标右键,弹出上下文菜单隐藏/显示对话框。
CMenu oMenu;
if (oMenu.LoadMenu(IDR_THETRAY))
{
CMenu* pPopup = oMenu.GetSubMenu(0);
ASSERT(pPopup != NULL);
CPoint oPoint;
if (IsWindowVisible())//根据对话框窗口的显示/隐藏状态
//修改菜单名称
oMenu.ModifyMenu(IDC_SHOW,MF_STRING,IDC_SHOW,
"隐藏(&H)");
else
oMenu.ModifyMenu(IDC_SHOW,MF_STRING,IDC_SHOW,
"显示(&S)");
// 确定鼠标位置以便在该位置附近显示菜单
GetCursorPos( &oPoint );
SetForegroundWindow();
pPopup->TrackPopupMenu(
TPM_LEFTALIGN | TPM_RIGHTBUTTON,
oPoint.x, oPoint.y, this);
}
}
break;
// 单击/双击鼠标左键均显示出对话框
case WM_LBUTTONDBLCLK:
case WM_LBUTTONDOWN:
OnShow();
break;
}
return 0;
}
7. 修改系统菜单,使我们点击“关闭”按钮时并不是退出程序,而是隐藏窗口。为此,我们
可以修改XXXDlg类中的 OnSysCommand(UINT nID, LPARAM lParam) 函数为:
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else if ((nID & 0xFFF0)==SC_CLOSE){
//OnClose();本来这个是关闭的这里也改为隐藏。
AnimateWindow(GetSafeHwnd(),1000,AW_HIDE|AW_BLEND);
KillTimer(0); //以上这两句实现渐变过渡隐藏窗口
ShowWindow(SW_HIDE);//系统菜单的关闭也改为隐藏。
}
else
{
CDialog::OnSysCommand(nID, lParam);
}
注意,AnimateWindow(GetSafeHwnd(),1000,AW_HIDE|AW_BLEND);和 KillTimer(0);两句是实现渐变过渡隐藏窗口的。
如果你想实现这个功能,除了不注释掉这两行之外,还需要在stdafx.h文件的开头加入下面的代码:
#undef WINVER
#define WINVER 0X500
这样,一个对话框应用程序就具有了系统托盘功能了。
这时编译运行之后我们右键单击托盘图标就会出现菜单。
b,基于文档
1、使用MFC AppWizard(EXE)创建项目文件。
2、用Add to Project添加CSystemIcon类的.h文件与.CPP文件到工程中。
3、在CFrameWnd类中添加下列语句:
//自定义消息
#define WM_ICON_NOTIFY WM_USER+10
//定义成员变量
#include "SystemIcon.h"
CSystemIcon m_systemIcon
4、定义消息映象与消息处理函数
a、BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
...
ON_MESSAGE(WM_ICON_NOTIFY, OnIconNotification)
END_MESSAGE_MAP()
b、LRESULT CMainFrame::OnIconNotification(WPARAM wParam, LPARAM lParam)
{
return m_systemIcon.OnIconNotification(wParam, lParam);
}
c、定义LRESULT OnIconNotification(WPARAM wParam, LPARAM lParam);
5、创建系统图标(在OnCreate中加添加):
HICON hIcon=AfxGetApp()->LoadIcon(IDI_MAINFRAME);
if (!m_systemIcon.Create(this, //消息通知窗口
WM_ICON_NOTIFY,//自定义消息
"MY SAMPLE", //提示字符串
hIcon, //图标ID号
IDR_POPUP_MENU //弹出菜单ID号
))
return -1;
6、打开资源,创建弹出菜单(IDR_POPUP_MENU),CAPTION为(_POPUP_):
菜单项包括:a、关于(ID_APP_ABOUT) b、例子(ID_APP_APP) c、退出(ID_APP_EXIT)
用ClassWizard定义(ID_APP_APP)消息处理函数,添加:AfxGetMainWnd()->ShowWindow(SW_SHOW);
7、打开资源,创建图标(IDI_ICON1)。
8、删除应用类中的函数InitInstance中的pMainFrame->ShowWindow(m_nCmdShow)语句。
9、编译执行形成执行文件。