用 VC5 控制 Windows 任务栏图标
通过在Windows任务栏中设置图标,我们可以有效控制系统和程序中最常用功
能,使用户实时观察应用程序的工作状态。Windows 95、98中已经有设备状态、
系统时钟、计划任务以及中文输入法程序等,其他应用程序中也有,如调制解调
器通信状态、后台打印任务的执行状态、解霸五中的VCD自动侦测状态、屏幕抓图
程序的控制状态以及其他后台任务事件等。通过在应用程序中合理有效地控制任
务栏中的图标,不仅可以使应用程序具有很高的专业水准,同时极大地方便了用
户操作,避免了通过任务栏中窗口最小化标题切换任务的繁琐操作,而且在节省
使用任务条中有效客户区域和实时获取任务执行状态方面,是任务栏最小化窗口
所无法替代的。
通过任务栏中的图标,既可以弹出各种功能菜单,也能重新激活应用程序窗
口进行各种操作,这些功能是由开发者自行决定的。鉴于目前各种高级应用程序
都是通过VC++开发出来的,所以本文主要阐述在VC5下控制任务栏图标的技巧。
实现任务栏中的图标功能并不困难,只要有效利用Shell-NotifyIcon()函数
和NOTIFYICONDATA数据结构。两者在VC5中的定义和用法如下:
1. Shell-NotifyIcon函数的用法
WINSHELLAPI BOOL Shell-NotifyIcon(
DWORD dwMessage,//处理的消息类型
pNOTIFYICONDATA pnid)//指向NOTIFYICONDATA数据结构的指针
参数dwMessage为函数的控制功能消息,可以是以下标识符之一:
NIM-ADD 在任务栏中增加一个图标
NIM-MODIFY 修改任务栏中的一个图标
NIM-DELETE 删除任务栏中的一个图标
参数lpData为指向由NOTIFYICONDATA定义的数据结构的地址指针。
2. NOTIFYICONDATA数据结构的定义
struct NOTIFYICONDATA{
DWORD cbsize; //该数据结构的大小
HWND hWnd;//处理任务栏中图标的窗口句柄
UINT uID; //自定义的任务栏中图标的标识信息,不同于资源中的标识,注意不能与任务栏中其他图标的ID相同
UINT uFlags //任务栏图标功能控制位,可以是以下值的组合(一般全包括):NIF-MESSAGE 表示发送控制消息;NIF-ICON 表示显示控制栏中的图标; NIF-TIP 表示任务栏中的图标有动态提示
UINT uCallbackMessage; //自定义消息,任务栏图标通过它与用户程序交换信息, 处理这个消息的窗口由hWnd来决定
HICON hIcon; //任务栏中图标的控制句柄
char szTip[64]; //图标的提示信息
}
当函数Shell-NotifyIcon出现错误时,其错误参数的含义与uFlags的内容相同。
在控制任务栏上的图标时应注意以下几点:
1. 当自定义任务栏图标的标识符值不一致时,不能正确对任务栏中对应图标
进行修改和删除等操作,所以各种功能函数中的uID值必须一致并不与系统冲突;
2. 当响应任务栏中图标的窗口无效时,鼠标指针移动了任务栏中的图标上时,图标立刻自动消失,窗口指针的正确获取方法如下:
CWnd* m-pCWnd=AfxGetMainWnd();//取得窗口指针
iData.hWnd=*m-pCWnd; //窗口句柄
3. 当应用程序被关闭后,系统并不马上删除任务栏中的图标,即图标不存在相应的响应窗口,只有鼠标指针移到任务栏图标上时才删除对应空闲图标,所以程序最好能对关闭功能进行完善处理;
4. 应选择合适的任务栏图标自定义消息值,一般为WM-APP或USER以后的数值;
5. 要使应用程序响应任务栏图标发送的自定义消息,必须增加窗口消息处理框架功能函数DefWindowProc,可利用类向导直接增加,并完善其功能实现对自定义消息及鼠标操作类型的判断处理。
6. 当设置任务栏图标再删除它后,设置和修改任务栏图标功能无效,除非重新运行一次应用程序,所以实际应用时最好对这项功能也进行完善。
可视化程序设计步骤
第一步 利用“FILE→NEW→PROJECTS→MFC AppWizard(EXE)”建立名为TICON工程,在建立过程中选择基于对话框(Dialog based)的应用程序类型;
第二步 将对话框中的默认控件删除,并将所有对话框属性中的Language域设置为Chinese(P.R.C.),以使应用程序支持中文;
第三步 建立两个图标IDI-ICON1和IDI-ICON2,用来表示图标的设置和修改两种状态,对于每个图标都应建立32×32和16×16两种大小,以保证程序的需
要;
第四步 在对话框窗口中设计四个按钮(Button)“设置图标”、“修改图标”、“删除图标”和“关闭”,其对应标识分别如下:
按钮名称 标识符号
设置图标 IDC-ADD
修改图标 IDC-MODI
删除图标 IDC-DEL
关 闭 IDOK
第五步 利用类向导ClassWizard向应用程序中增加前三个按钮对应的功能函
数:ONADD()、ONMODI()和ONDEL();
第六步 在应用程序中增加如下代码:
(1) 在TIconDlg.h中增加如下定义
//在开始处增加通用功能函数定义
BOOL SendIconMessage(DWORD dwMessage,UINT uID,HICON hIcon,PSTR pszTip);
...... //其他代码
Protected:
HICON m-hIcon1;//定义图标控制句柄
HICON m-hIcon2;
(2) 在TIconDlg.h和Ticon.h中增加如下代码
//在TIcon.h开始处增加如下定义
static int iIndex=0;
//在TIconDlg.h开始处增加如下定义
#define MYWM-NOTIFYICON (WM-APP+100)
UINT Flag;
...... //其他代码完善类初始化函数
BOOL CTIconDlg::OnInitDialog()
{
CDialog::OnInitDialog();
..... //其他代码
iIndex=0;//清除代码标志
m-hIcon1 = AfxGetApp()->LoadIcon(IDI-ICON1); //调入图标
m-hIcon2 = AfxGetApp()->LoadIcon(IDI-ICON2); //调入图标
return TRUE;
}
...... //其他代码完善各功能函数
void CTIconDlg::OnAdd() //设置任务栏图标功能函数
{
UINT Flag;
Flag=NIM-ADD;
if (iIndex==1) return;
if (iIndex==2) Flag=NIM-MODIFY;
SendIconMessage(Flag,120,m-hIcon1,“设置图标/0”); //三者uID必须统一,指任务栏上的图标标识信息
iIndex=1;
}
void CTIconDlg::OnDel() //删除任务栏图标功能函数
{
if (iIndex==0) return;
SendIconMessage(NIM-DELETE,120,NULL,NULL);
iIndex==0;
CWnd* m-pCWnd=AfxGetMainWnd();
//取得窗口指针
DestroyWindow(*m-pCWnd);
}
void CTIconDlg::OnModi() //修改任务栏图标功能函数
{
Flag=NIM-MODIFY;
if (iIndex==2) return;
if (iIndex==0) Flag=NIM-ADD;
SendIconMessage(Flag,120,m-hIcon2,“修改图标/0”);
iIndex=2;
}
BOOL SendIconMessage(DWORD dwMessage,UINT uID,HICON hIcon,PSTR pszTip)
{ //任务栏图标消息处理通用功能函数
BOOL uRet;
CWnd* m-pCWnd=AfxGetMainWnd();
//取得窗口指针
NOTIFYICONDATA iData; //定义数据结构
iData.cbSize=sizeof(NOTIFYICONDATA);
//结构大小
iData.hWnd=*m-pCWnd; //窗口句柄
iData.uID=uID; //图标标识
iData.uFlags=NIF-MESSAGE|NIF-ICON|NIF-TIP; //设置处理的消息类型
iData.hIcon=hIcon; //图标句柄
iData.uCallbackMessage=MYWM-NOTIFYICON;
//自定义消息名
if(lstrlen(pszTip)>0 && lstrlen(pszTip)<64) {
//处理提示信息
lstrcpy(iData.szTip,pszTip);
//处理动态提示信息
iData.szTip[63]='/0';
} else {
iData.szTip[0]='/0';
}
uRet = Shell-NotifyIcon(dwMessage,&iData);
//发送消息
if (dwMessage==NIM-DELETE){
DestroyWindow(*m-pCWnd); //关闭窗口
}else {
ShowWindow(*m-pCWnd,SW-HIDE);//关闭窗口
}
ShowWindow(*m-pCWnd,SW-HIDE);//关闭窗口
return uRet;
}
第七步 为了使任务栏上的图标能够处理鼠标消息,应利用类向导ClassWizard增加DefWindowProc功能,以实现对自定义消息的处理,用户可以根据自己的实际需要确定要处理的鼠标消息类型和响应消息功能函数,本文只实现了重新激活对话框窗口的功能。代码如下:
LRESULT CTIconDlg::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{//响应自定义类型消息功能函数
if (message==MYWM-NOTIFYICON && lParam==WM-LBUTTONDOWN){ //判断消息AfxMessageBox(“SSSSSSSSSSSSSSSS",IDOK,0);
CWnd* m-pCWnd=AfxGetMainWnd();
//取得窗口指针
ShowWindow(SW-SHOW); //显示窗口
SetForegroundWindow(); //强制为活动窗口
}
return CDialog::DefWindowProc(message, wParam, lParam);
}
第八步 当对话框应用程序关闭后,程序并不对任务栏中的图标进行自动删
除,除非鼠标指针移到任务栏的图标上时系统才自动删除已经关闭窗口所对应的
图标,这时应在TICON.CPP程序中对应用程序窗口关闭功能进行完善。
BOOL CTIconApp::InitInstance()
{
AfxEnableControlContainer();
...... //其他代码
if (nResponse == IDOK)
{
if(iIndex>0){删除任务栏图标
SendIconMessage(NIM-DELETE,120,NULL,NULL);
iIndex=0;
} }
else if (nResponse == IDCANCEL)
{
if(iIndex>0){ //删除任务栏图标
SendIconMessage(NIM-DELETE,120,NULL,NULL);
iIndex=0;
} }
本文程序运行后,选择设置或修改图标后自动隐藏窗口;当用鼠标左键单击
任务栏中对应图标后重新激活窗口。