Shell_NotifyIcon函数用于向Windows系统任务栏的状态区域发送消息,原型如下:
BOOL Shell_NotifyIcon( __in DWORD dwMessage, __in PNOTIFYICONDATA lpdata );
其中
(1)参数dwMessage表示该函数要执行的操作,取值如下:
NIM_ADD:往状态区添加一个图标;在参数lpdata指向的结构中的参数uID或guidItem给这个图标指定了标识;
NIM_MODIFY:修改状态区的一个图标;使用的是NIM_ADD中指定的图标标识;
NIM_DELETE:删除状态区的一个图标;使用的是NIM_ADD中指定的图标标识;
NIM_SETFOCUS:将焦点重新设给任务栏的通知区域;一般通知区域的图标在完成UI操作时使用该函数来重新获取焦点,例如通知区域的图标显示一个快捷菜单,但用户按ESC键取消该菜单的显示时,图标就可以使用NIM_SETFOCUS来重新使通知区域获得焦点;
NIM_SETVERSION:指示通知区域要遵循参数lpdata指向的结构中的参数uVersion指定的版本来操作,版本号指定了哪些成员是可识别的。
(2)参数lpdata是指向NOTIFYICONDATA结构的指针,该结构的内容取决于参数dwMessage的值,例如可以定义一个图标用于添加到通知区域,以用来显示通知;也可以指定一个用于修改或删除的图标。
返回值:
成功返回TRUE,失败返回FALSE;当dwMessage设置为MIN_SETVERSION时,该函数返回TRUE表示版本号更改成功,返回FALSE表示系统不支持指定的版本。
注意:对于Windows 2000(Shell32.dll version 5.0),Shell_NotifyIcon对于鼠标和键盘事件的处理与早期的操作系统的不同点在于:
(1)用户使用键盘选择了通知图标的快捷菜单,Shell将发送WM_CONTEXTMENU消息给图标对应的应用程序,而早期操作系统则发送WM_RBUTTONDOWN和WM_RBUTTONUP消息;
(2)用户使用键盘选择通知图标,并使用空格键或Enter键激活它,则Shell将发送NIN_KEYSELECT通知给应用程序,而早期版本则发送WM_RBUTTONDOWN和WM_RBUTTONUP消息;
(3)用户使用鼠标选择通知图标,并使用Enter键激活它,Shell将发送NIN_SELECT通知给应用程序,而早期版本发送WM_RBUTTONDOWN和WM_RBUTTONUP消息;
对于Windows XP(Shell32.dll version 6.0),当用户将鼠标指向关联着气泡通知的图标时,Shell将发送下列消息:
(1)NIN_BALLOONSHOW:当气泡显示时发送(气泡在队列中排队);
(2)NIN_BALLOONHIDE:当气泡消失时发送,例如,当图标删除时。在气泡因为超时或者用户鼠标单击后消失时,不发送该消息;
(3)NIN_BALLOONTIMEOUT:气泡超时后消失时发送;
(4)NIN_BALLOONUSERCLICK:用户鼠标单击气泡使气泡消失时发送;
结构NOTIFYICONDATA包含了Windows系统在通知区域显示通知所需的信息,本函数Shell_NotifyIcon使用,原型如下:
typedef struct _NOTIFYICONDATA { DWORD cbSize; //结构的大小 HWND hWnd; //接收图标通知的窗口 UINT uID; //任务栏通知区域图标的标识 UINT uFlags; //指定其他哪些参数有效,是如下取值的组合: //NIF_MESSAGE:uCallbackMessage参数有效; //NIF_ICON:hIcon参数有效;NIF_TIP:szTip参数有效; //NIF_STATE:dwState和dwStateMask参数有效; //NIF_INFO:显示气泡通知,szInfo,szInfoTitle,dwInfoFlags和 //uTimeout参数有效; //NIF_GUID、NIF_REALTIME、NIF_SHOWTIP UINT uCallbackMessage; HICON hIcon; //图标句柄 TCHAR szTip[64]; //提示字符串 DWORD dwState; //图标的状态:NIS_HIDDEN(图标隐藏)、 //NIS_SHAREICON(该图标资源被多个图标共享) DWORD dwStateMask; //dwState的掩码 TCHAR szInfo[256]; //图标气泡显示的字符串 union { UINT uTimeout; //超时的时间 UINT uVersion; //图标的版本 } ; TCHAR szInfoTitle[64]; //图标气泡的标题 DWORD dwInfoFlags;//图标气泡的类型:NIIF_NONE,无类型; //NIFF_INFO,通知类型;NIFF_WARNING:警告类型; //NIFF_ERROR,错误类型; //NIFF_USER,在Windows XP中表示使用hIcon参数指定的图标 //在Windows Vista及后续版本,表示使用hBalloonIcon的图标 //NIFF_NOSOUND、NIIF_LARGE_ICON、 //NIFF_RESPECT_QUIET_TIME、NIFF_ICON_MASK GUID guidItem; //在Windows XP和Vista中,保留为0;在Windows 7及后续版本, //用于标识一个图标的注册GUID值 HICON hBalloonIcon; //用于Windows Vista及后续版本中,表示自定义气泡图标类型 } NOTIFYICONDATA, *PNOTIFYICONDATA;
上面两个函数使用的实例当然是在编写系统托盘程序时,下面这个类摘自金山开源作品之ARP防火墙,先看头文件吧:
#pragma once ////////////////////////////////////////////////////////////////////////// #define WM_ARPFW_SYSTRAY (WM_USER+100) #define WM_ARPFW_SETICON (WM_USER+101) ////////////////////////////////////////////////////////////////////////// class CArpTray : public CWindowImpl<CArpTray, CWindow, CFrameWinTraits> { public: CArpTray(); ~CArpTray(); DECLARE_WND_CLASS(_T("KSafeArpTray")) BEGIN_MSG_MAP(CArpTray) MSG_WM_CREATE(OnCreate) MSG_WM_DESTROY(OnDestroy) MSG_WM_CLOSE(OnClose) MSG_WM_COMMAND(OnCommand) MESSAGE_HANDLER(WM_ARPFW_SYSTRAY, OnSysTray) MESSAGE_HANDLER(WM_ARPFW_SETICON, OnSetIcon) END_MSG_MAP() LRESULT OnSysTray(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); LRESULT OnSetIcon(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); int OnCreate(LPCREATESTRUCT lpCreateStruct); void OnDestroy(); void OnClose(); void OnCommand(UINT uNotifyCode, int nID, CWindow wndCtl); void OnShowMain(); void OnExit(); void OnEnable(BOOL bEnable); void InitTrayIconStruct(); void ShowTrayMenu(); NOTIFYICONDATAW m_trayIcon; BOOL m_bArpFwEnable; HICON m_hIcons[2]; }; //////////////////////////////////////////////////////////////////////////
接下来就是实现文件:
#include "stdafx.h" #include "arpfw.h" #include "tray.h" #include "resource.h" ////////////////////////////////////////////////////////////////////////// CArpTray::CArpTray() { //加载防火墙开启和关闭时显示用的图标 m_hIcons[0] = LoadIcon(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDI_ARP_ENABLE)); m_hIcons[1] = LoadIcon(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDI_ARP_DISABLE)); } CArpTray::~CArpTray() { } ////////////////////////////////////////////////////////////////////////// /********************************************* * 初始化系统托盘图标数据结构 *********************************************/ void CArpTray::InitTrayIconStruct() { USES_CONVERSION; CString strArpFw; HICON show_icon = NULL; RtlZeroMemory(&m_trayIcon, sizeof(m_trayIcon)); m_trayIcon.cbSize = NOTIFYICONDATA_V1_SIZE; m_trayIcon.hWnd = m_hWnd; m_trayIcon.uID = 1; //使参数uCallbackMessage、hIcon、szTip有效 m_trayIcon.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP; if (m_bArpFwEnable) { m_trayIcon.hIcon = m_hIcons[0]; strArpFw = _T("金山卫士ARP防火墙 - 已开启"); } else { m_trayIcon.hIcon = m_hIcons[1]; strArpFw = _T("金山卫士ARP防火墙 - 未开启"); } m_trayIcon.uCallbackMessage = WM_ARPFW_SYSTRAY; StringCchCopyW(m_trayIcon.szTip, ARRAYSIZE(m_trayIcon.szTip), strArpFw); } /*********************************************************************************** * 设置系统托盘图标 ***********************************************************************************/ LRESULT CArpTray::OnSetIcon(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { m_bArpFwEnable = (BOOL)wParam; CString strArpFw; if (m_bArpFwEnable) { m_trayIcon.hIcon = m_hIcons[0]; strArpFw = _T("金山卫士ARP防火墙 - 已开启"); } else { m_trayIcon.hIcon = m_hIcons[1]; strArpFw = _T("金山卫士ARP防火墙 - 未开启"); } StringCchCopyW(m_trayIcon.szTip, ARRAYSIZE(m_trayIcon.szTip), strArpFw); Shell_NotifyIcon(NIM_MODIFY, &m_trayIcon); //修改托盘图标 return 0L; } /***************************************************** * 系统初始化 *****************************************************/ int CArpTray::OnCreate(LPCREATESTRUCT lpCreateStruct) { RECT rc = {0, 0, 0, 0}; SetWindowPos(NULL, &rc, SWP_HIDEWINDOW); //隐藏窗口 SetWindowText(_T("")); InitTrayIconStruct(); Shell_NotifyIconW(NIM_ADD, &m_trayIcon); //添加托盘图标 return 0; } /********************************************** * 系统退出 **********************************************/ void CArpTray::OnDestroy() { //删除托盘图标 Shell_NotifyIcon(NIM_DELETE, &m_trayIcon); //关闭主窗口 _Module.CloseMain(); } void CArpTray::OnClose() { DestroyWindow(); } /******************************************************************* * 系统托盘收到消息 *******************************************************************/ LRESULT CArpTray::OnSysTray(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { switch (lParam) { case WM_RBUTTONUP: //鼠标右键弹起则显示上下文菜单 ShowTrayMenu(); break; case WM_LBUTTONUP: //鼠标左键弹起则显示主窗口 _Module.ShowMain(); break; } return 0; } /****************************************************************** * 收到命令消息后的处理 ******************************************************************/ void CArpTray::OnCommand(UINT uNotifyCode, int nID, CWindow wndCtl) { switch (nID) { case ID_ARPFW_SHOWMAIN: //显示主窗口 OnShowMain(); break; case ID_ARPFW_ENABLE: //启动防火墙 OnEnable(TRUE); break; case ID_ARPFW_DISABLE: //关闭防火墙 OnEnable(FALSE); break; case ID_ARPFW_EXIT: //退出系统 OnExit(); break; } } void CArpTray::OnEnable(BOOL bEnable) { _Module.EnableArpFw(bEnable); } void CArpTray::OnShowMain() { _Module.ShowMain(); } /*************************************** * 退出系统 ***************************************/ void CArpTray::OnExit() { CString strText; CString strTitle; int nRetCode; strText = _T("您确认要退出金山卫士ARP防火墙吗?"); strTitle = _T("金山卫士ARP防火墙"); nRetCode = MessageBox(strText, strTitle, MB_ICONQUESTION|MB_OKCANCEL); if (IDOK == nRetCode) { PostMessage(WM_CLOSE, 0, 0); } } /************************************* * 显示系统托盘上下文菜单 *************************************/ void CArpTray::ShowTrayMenu() { POINT pos; CMenu menu; HMENU hMenu = NULL; menu.LoadMenu(IDR_TRAY_MENU); hMenu = menu.GetSubMenu(0); RemoveMenu(hMenu, m_bArpFwEnable ? ID_ARPFW_ENABLE : ID_ARPFW_DISABLE, MF_BYCOMMAND); GetCursorPos(&pos); //获得当前光标位置,在此处显示菜单 TrackPopupMenu(hMenu, TPM_LEFTALIGN | TPM_RIGHTBUTTON, pos.x, pos.y, 0, m_hWnd, NULL); } //////////////////////////////////////////////////////////////////////////