最近初接触MFC,是为了实现一个传感网络的上位机。
在实现托盘提示时,在网上搜索了不少资料,但已经翻译的资料都比较老。
在查看原版的MSDN后,发现NOTIFYICONDATA这个结构中有几项新特性,可以实现比较新的托盘/气泡特性。
例如:气泡操作响应(想想MSN的单击气泡关闭提示?)、隐藏图标|显示图标(不通过删除)、自定义大Balloon Tip图标等,还是比较吸引人的。
但是,实现这些功能的同时,需要一些额外的代码来提高程序的兼容性。
我把自己摸索的一些结果总结出来吧:
在VS2008+MFC+XP和WIN7 64bit下进行测试通过。
先贴下NOTIFYICONDATA结构。
以下挑出几个不同的地方,一一做说明。
cbSize
网上通常的做法是
nid.cbSize=(DWORD)sizeof(NOTIFYICONDATA);
在最新的MSDN中指出:由于NOTIFYICONDATA结构体的大小在不同的Shell32.dll下,是不一样的,若是笼统的使用sizeof(NOTIFYICONDATA)来获取长度,使用的是当前定义的NOTIFYICONDATA结构长度,程序很可能在早期版本的Shell32.dll中无法运行。
在初始化NOTIFYICONDATA结构之前,我们可以使用函数
来获取Shell32.dll的版本,并根据不同版本的Shell32.dll指定cbSize的大小。
DllGetVersion并不是一个API,具体的使用方法,请参看我另一篇博文《正确使用DllGetVersion》。
Shell32.dll Version | cbSize |
---|---|
6.0.6 or higher (Windows Vista and later) | sizeof(NOTIFYICONDATA) |
6.0 (Windows XP) | NOTIFYICONDATA_V3_SIZE |
5.0 (Windows 2000) | NOTIFYICONDATA_V2_SIZE |
Versions lower than 5.0 | NOTIFYICONDATA_V1_SIZE |
请注意,cbSize中的长度不对时,会直接影响托盘图标能否显示,以及特性是否正常。
uFlags
新特性:
NIF_GUID
NIF_REALTIME
NIF_SHOWTIP
uCallbackMessage
这个消息传递的参数在uVersion 设置为 NOTIFYICON_VERSION_4后,变为如下的意义。
hIcon
XP和之后的版本支持32BPP的ICON。最好同时提供16x16、32x32的图标。在追求高DPI图标的情况下,可以使用如下函数加载图标,但此函数仅可在Vista及以上版本的系统中使用,若在代码中包含此语句,即便该函数运行时不被调用,程序也不可以在XP下执行(双击后直接报错)。
szTip
Windows2000之后支持128字节,包括NULL。
uTimeout
该值在Vista及之后系统下无效,此时间由系统决定。在其他情况下:最大值30秒,最小值10秒。单位为毫秒。另外有一点,就是关于XP下气泡提示不会自动消失的情况。MSDN中也指出这是一个存在的现象,当用户没有操作时(任何操作,例如单击开始菜单之类),气泡是不会消失的(XP)。个人觉得,为了保险,还是自己使用定时关闭Balloon Tips的好…
uVersion
这是一个比较关键的值
Windows 2000之前的操作系统使用,也是默认值.
使用Windows 2000特性,用于Windows 2000以及之后版本.
使用当前系统风格,用于Vista与之后的版本.
若我们要实现气泡上的操作的响应,我们必须设定为NOTIFYICON_VERSION_4,才能在CallbackMessage中响应到关于气泡的消息。当然其他消息也要按照上文中说明的来提取消息类型。
还有一点关键就是,要实现uVersion的设置,必须调用
才能实现版本的更改。
dwInfoFlags
新特性:
NIIF_USER
NIIF_LARGE_ICON
NIIF_RESPECT_QUIET_TIME
guidItem
XP和之后系统的特性
若程序要同时运行在Vista 与 WIN7,必须在程序中判断系统版本,再指定该值。
若设置了GUID,GUID则代替uID来操作托盘图标,切记。
可以使用GUID生成工具例如Guidgen.exe来生成一个有效的GUID。
hBalloonIcon
以上就是NOTIFYICONDATA的一些新特性,以2010年12月11日官方英文MSDN为原版的翻译与一些自己的提示。
需注意的是,在网上许多资料对气泡不弹出的解决办法,都是对以下的宏定义进行修改:
#ifndef WINVER // 指定要求的最低平台是 Windows Vista。
#define WINVER 0x0600 // 将此值更改为相应的值,以适用于 Windows 的其他版本。
#endif
#ifndef _WIN32_WINNT // 指定要求的最低平台是 Windows Vista。
#define _WIN32_WINNT 0x0600 // 将此值更改为相应的值,以适用于 Windows 的其他版本。
若是按其更改为0x0501之后,类似 NOTIFYICON_VERSION_4,hBalloonIcon等这些6.0版本的宏定义与成员是不可直接使用的。
其实,这种解决办法是错误的,请设置该值为默认值。
气泡不能正常显示,正是上文提及的cbSize的值设置不正确所导致的。
因为在该宏定义为0x0600时,NOTIFYICONDATA结构声明为上文中贴出的结构,而笼统使用sizeof获取的大小,亦为这个大小。但在XP中运行时,Shell32.dll版本较低,NOTIFYICONDATA中类似hBalloonicon等成员不存在,长度不一致,从而导致托盘异常,气泡无法正常显示。为了正常显示托盘气泡,一定要设置正确的cbSize值。
下面给出一个CallbackMessage的函数例子,用于NOTIFYICON_VERSION_4时的消息处理,可以实现气泡单击,关闭之类的消息处理。
再给出一个简单的大图标Balloon Tip例子:
另外,可能有人不知道如何立即关闭BalloonTip,只要令szInfo的内容为空,再修改图标,就可以立即关闭提示。
最后再提醒一点,使用了新特性的程序,很可能在XP下无法使用。所以,想让自己的程序拥有美丽的外观的同时,又能在XP下正常运行,一定要善用上文提及的函数判断shell32.dll版本之后,再配置NOTIFYICONDATA结构体。
虽然大图标提示很美观,但也不要滥用提示,除非是自用的,不然用户很可能彻底告别你的程序!
若是有帮助,留个言支持下,我会继续写一些个人的经验与大家分享~
欢迎留言交流问题与经验~若是有错误,还请指正!