VC中的托盘程序主要通过自定义消息和一个辅助结构来完成。当然,托盘的响应消息也可以是系统消息。
一、数据结构
用到如下两个数据结构:
1. typedef struct _NOTIFYICONDATA {
DWORD cbSize; //本结构的大小,以字节为单位
HWND hWnd; //接收托盘图标通知消息的窗口句柄
UINT uID; //应用程序定义的托盘图标的ID号,如果不是多个图标,并不重要
UINT uFlags; //设置该图标的属性
UINT uCallbackMessage; //应用程序定义的消息ID号,此消息传递给hWnd
HICON hIcon; //图标的句柄
TCHAR szTip[64]; //鼠标停留在图标上时显示的提示信息
DWORD dwState;
DWORD dwStateMask;
TCHAR szInfo[256];
union {
UINT uTimeout;
UINT uVersion;
};
TCHAR szInfoTitle[64];
DWORD dwInfoFlags;
GUID guidItem;
HICON hBalloonIcon;
} NOTIFYICONDATA, *PNOTIFYICONDATA;
该结构中,成员uFlags可以使下列之一或组合:
NIF_ICON 设置成员hIcon有效
NIF_MESSAGE 设置成员uCallbackMessage有效
NIF_TIP 设置成员szTip有效
其他项见MSDN。
2. BOOL Shell_NotifyIcon(DWORD dwMessage, PNOTIFYICONDATA lpdata);
参数dwMessage是被传递的消息,可以是以下消息之一:
NIM_ADD 增加图标
NIM_DELETE 删除图标
NIM_MODIFY 修改图标
其他项的说明见MSDN。
二、实例
一个对话框为例,托盘所有的实现都放在对话框类中。实现的方法有多种,为简化讨论,尽量不重载函数。如对话框类为CTestTray,则实现步骤如下:
1. CTestTray.h中
#define WM_NOTIFYICON WM_USER + 100 //自定义消息ID
NOTIFYICONDATA m_nd; //定义类结构变量
afx_msg LRESULT OnNotifyIcon(WPARAM wParam, LPARAM lParam); // 自定义托盘图标消息响应函数
2. CTestTray.cpp中
--- ON_MESSAGE(WM_NOTIFYICON, OnNotifyIcon) //映射消息
--- OnInitDialog()中:
//初始化
m_nd.cbSize = sizeof(NOTIFYICONDATA);
m_nd.hWnd = m_hWnd;
m_nd.uID = IDI_ICON1; //IDI_ICON1为自定义图标
m_nd.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
m_nd.uCallbackMessage = WM_NOTIFYICON;
m_nd.hIcon = AfxGetApp()->LoadIcon(IDI_ICON1);
_tcscpy_s(m_nd.szTip, sizeof(m_nd.szTip), _T("托盘测试程序"));
//显示托盘图标
Shell_NotifyIcon(NIM_ADD, &m_nd);
初始化还可放在OnCreate、PreCreateWindow等地方。
--- 实现OnNotifyIcon():
// 自定义托盘图标消息响应函数
afx_msg LRESULT CTestTray::OnNotifyIcon(WPARAM wParam, LPARAM lParam)
{
//响应在托盘图标上的单击
//wParam中是响应消息的图标ID,lParam中则是Windows的消息
if(wParam == IDI_ICON1){
if(lParam == WM_LBUTTONDOWN) //左键显示对话框
ShowWindow(SW_SHOWNORMAL);
else if(lParam == WM_RBUTTONDOWN){ //右键弹出菜单
CMenu menu;
menu.LoadMenu(IDR_MENU_POPUP);
CMenu* pMenu = menu.GetSubMenu(0);
CPoint pos;
GetCursorPos(&pos);
pMenu->TrackPopupMenu(TPM_RIGHTALIGN | TPM_RIGHTBUTTON, pos.x, pos.y, AfxGetMainWnd());
}
}
return afx_msg LRESULT();
}
消息响应还可在WindowProc()中完成。
--- CTestTray::OnSysCommand(UINT nID, LPARAM lParam)中加入:
if(nID == SC_MINIMIZE) //最小化时隐藏对话框
ShowWindow(SW_HIDE);
当然,隐藏窗体可在其他地方,如按钮响应函数中。
--- CTestTray类的析构函数中加入:
Shell_NotifyIcon(NIM_DELETE, &m_nd); //删除托盘图标
还可放在WM_DESTROY和WM_NCDESTROY消息响应函数。
此外,托盘响应的消息也可以是其他消息,如系统消息。
自此,一个托盘程序框架就完成了,可以:最小化到托盘上,左键单击托盘图标重新显示对话框,右键单击托盘图标弹出菜单。
参考文献:
http://www.itepub.net/html/kaifajingcui/C___VC/2006/0515/38042.html
http://www.yesky.com/190/1878190.shtml
http://www.jiuimm.com/article.asp?id=209