注:本文转自 https://my.oschina.net/ypimgt/blog/92195

最近初接触MFC,是为了实现一个传感网络的上位机。
在实现托盘提示时,在网上搜索了不少资料,但已经翻译的资料都比较老。
在查看原版的MSDN后,发现NOTIFYICONDATA这个结构中有几项新特性,可以实现比较新的托盘/气泡特性。

例如:气泡操作响应(想想MSN的单击气泡关闭提示?)、隐藏图标|显示图标(不通过删除)、自定义大Balloon Tip图标等,还是比较吸引人的。

但是,实现这些功能的同时,需要一些额外的代码来提高程序的兼容性。

我把自己摸索的一些结果总结出来吧:
在VS2008+MFC+XP和WIN7 64bit下进行测试通过。
先贴下NOTIFYICONDATA结构。

typedef   struct  _NOTIFYICONDATA {   
     DWORD  cbSize; //    
     HWND  hWnd;   
     UINT  uID;   
     UINT  uFlags; //    
     UINT  uCallbackMessage; //    
     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;

以下挑出几个不同的地方,一一做说明。

cbSize

网上通常的做法是

nid.cbSize=(DWORD)sizeof(NOTIFYICONDATA);

在最新的MSDN中指出:由于NOTIFYICONDATA结构体的大小在不同的Shell32.dll下,是不一样的,若是笼统的使用sizeof(NOTIFYICONDATA)来获取长度,使用的是当前定义的NOTIFYICONDATA结构长度,程序很可能在早期版本的Shell32.dll中无法运行。

在初始化NOTIFYICONDATA结构之前,我们可以使用函数

HRESULT  CALLBACK DllGetVersion(DLLVERSIONINFO *pdvi);

来获取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

  • Windows 7 and later: 表示 guidItem  有效.
  • Windows Vista and earlier: 保留.

NIF_REALTIME

  • Windows Vista and later.  新增的特性,Balloon Tip若不能立即显示,则直接忽略掉。用于即时性要求较高的Balloon Tip。例如“你电话响了”(MSDN的例子), 要联合NIF_INFO这个特性使用才有效。

NIF_SHOWTIP

  • Windows Vista and later. 在uVersion 被设置为  NOTIFYICON_VERSION_4时,标准的ToolTip(鼠标指向托盘图标时的那个提示)会被取消,也会被 application-drawn、弹出式UI等替代。在这个情况下,我们可以设置NIF_SHOWTIP打开ToolTip。

uCallbackMessage

这个消息传递的参数在uVersion 设置为 NOTIFYICON_VERSION_4后,变为如下的意义。

  • LOWORD(lParam) 包含了消息类型,例如:NIN_BALLOONSHOW,NIN_POPUPOPEN,WM_CONTEXTMENU。有许多人想实现对用户单击气泡的消息响应,就是在这里做消息的响应。
  • HIWORD(lParam) 为uID,缩短为16位,我们用这个确定是哪一个托盘图标的消息。
  • GET_X_LPARAM(wParam) 返回鼠标消息时,为鼠标的X坐标。如果消息从键盘产生,wParam 包含的坐标为目标ICON的左上角坐标, 其他消息时wParam 未定义 。
  • GET_Y_LPARAM(wParam) 返回鼠标消息时,为鼠标的Y坐标。其他意义与GET_X_LPARAM(wParam)相同。

hIcon

XP和之后的版本支持32BPP的ICON。最好同时提供16x16、32x32的图标。在追求高DPI图标的情况下,可以使用如下函数加载图标,但此函数仅可在Vista及以上版本的系统中使用,若在代码中包含此语句,即便该函数运行时不被调用,程序也不可以在XP下执行(双击后直接报错)。

LoadIconMetric(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_MAINFRAME), LIM_LARGE, &(nid.hBalloonIcon));

szTip

Windows2000之后支持128字节,包括NULL。

uTimeout

该值在Vista及之后系统下无效,此时间由系统决定。在其他情况下:最大值30秒,最小值10秒。单位为毫秒。另外有一点,就是关于XP下气泡提示不会自动消失的情况。MSDN中也指出这是一个存在的现象,当用户没有操作时(任何操作,例如单击开始菜单之类),气泡是不会消失的(XP)。个人觉得,为了保险,还是自己使用定时关闭Balloon Tips的好…

uVersion

这是一个比较关键的值

  • 0

Windows 2000之前的操作系统使用,也是默认值.

  • NOTIFYICON_VERSION

使用Windows 2000特性,用于Windows 2000以及之后版本.

  • NOTIFYICON_VERSION_4

使用当前系统风格,用于Vista与之后的版本.

若我们要实现气泡上的操作的响应,我们必须设定为NOTIFYICON_VERSION_4,才能在CallbackMessage中响应到关于气泡的消息。当然其他消息也要按照上文中说明的来提取消息类型。

还有一点关键就是,要实现uVersion的设置,必须调用

Shell_NotifyIcon(NIM_SETVERSION,&nid);

才能实现版本的更改。

dwInfoFlags

新特性:

NIIF_USER

  • Windows XP: 使用hIcon做Balloon Tip的标题图标。
  • Windows Vista and later:使用 hBalloonIcon 做Balloon Tip的标题图标。

NIIF_LARGE_ICON

  • Windows Vista and later. 使用大图标做Balloon Tip的标题图标,对应的图标大小为SM_CXICON x SM_CYICON,如果不设置这个标记,那么使用的是XM_CXSMICON x SM_CYSMICON 大小的图标。
  • 使用旧版本定制图标的程序(NIIF_USER 标记,使用 hIcon) ,也就是XP下,必须提供 SM_CXICON x SM_CYICON 版本的 hIcon。 托盘区的hIcon会自动缩小至XM_CXSMICON x SM_CYSMICON 大小。
  • 使用新版本定制图标的程序(NIIF_USER 标记,使用 hBalloonIcon) ,也就是Vista之后的版本,hBalloonIcon必须有 SM_CXICON x SM_CYICON 大小。

NIIF_RESPECT_QUIET_TIME

  • MSDN中指出,在当前用户处于"quiet time"时,不显示,直接忽略该Balloon Tip,亦不进入Balloon Tip的等待队列。
  • 至于这个"quiet time"是指:用户第一次登陆他的账户后的几个小时之内(which is the first hour after a new user logs into his or her account for the first time),并且系统更新与清理之后也会进入"quiet time"。MSDN说,是为了在用户适应新的电脑与环境之时,不被打扰而提供的功能。当然,程序需要用户立即做出回应,可以不用此标记,例如插入一个USB设备,或者正在打印一个文档之类的信息。

guidItem

XP和之后系统的特性

  • Windows 7 and later: 需要一个已注册的GUID代替uID来指示托盘图标(MSDN推荐的做法),需要在uFlags中置位NIF_GUID。
  • Windows XP and Windows Vista:保留,必须为0。

若程序要同时运行在Vista 与 WIN7,必须在程序中判断系统版本,再指定该值。

若设置了GUID,GUID则代替uID来操作托盘图标,切记。

可以使用GUID生成工具例如Guidgen.exe来生成一个有效的GUID。

hBalloonIcon

  • Windows Vista and later. Balloon Tip标题图标句柄,dwInfoFlags 中NIIF_USER中置位后, 若改为为0,则用传统的Balloon Tip标题图标

以上就是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时的消息处理,可以实现气泡单击,关闭之类的消息处理。

LRESULT  CUSB_sensorDlg::OnICON( WPARAM  wParam, LPARAM  lParam)   
{   
     if (HIWORD(lParam) != uID) //uID为你指定的托盘图标uID,过滤其他托盘程序的消息     
         return    0;    
     switch (LOWORD(lParam))    
    {    
     case    WM_RBUTTONUP: //右键弹起    
         //添加代码    
         break ;    
     case    WM_LBUTTONDBLCLK: //双击左键的处理     
         //添加代码    
         break ;    
     case  NIN_BALLOONUSERCLICK: //用户单击气泡处理    
         //添加代码    
         break ;   
    }    
     return    0;    
}

再给出一个简单的大图标Balloon Tip例子:

nid.cbSize=( DWORD ) sizeof (NOTIFYICONDATA);    
nid.hWnd= this -> m_hWnd;    
nid.uID=IDR_MAINFRAME;    
nid.uFlags=NIF_ICON|NIF_MESSAGE|NIF_TIP|NIF_INFO | NIF_SHOWTIP;    
nid.uCallbackMessage=WM_ICON; //自定义的消息名称     
nid.hIcon=LoadIcon(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDR_MAINFRAME));   
wcscpy_s(nid.szTip, _T( "标准ToolTips" ));   
wcscpy_s(nid.szInfo,_T( "气泡内容" ));     
wcscpy_s(nid.szInfoTitle,_T( "气泡标题" ));      
nid.uVersion=NOTIFYICON_VERSION_4; //打开高版本    
nid.dwInfoFlags= NIIF_USER | NIIF_LARGE_ICON ;    //打开自定义及大图标提示    
nid.hBalloonIcon=LoadIcon(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDR_MAINFRAME));   
Shell_NotifyIcon(NIM_ADD,&nid); //在托盘区添加图标     
Shell_NotifyIcon(NIM_SETVERSION,&nid); //设置vista效果的balloon tips

另外,可能有人不知道如何立即关闭BalloonTip,只要令szInfo的内容为空,再修改图标,就可以立即关闭提示。

最后再提醒一点,使用了新特性的程序,很可能在XP下无法使用。所以,想让自己的程序拥有美丽的外观的同时,又能在XP下正常运行,一定要善用上文提及的函数判断shell32.dll版本之后,再配置NOTIFYICONDATA结构体。

虽然大图标提示很美观,但也不要滥用提示,除非是自用的,不然用户很可能彻底告别你的程序!

MFC--关于NOTIFYICONDATA的一些新特性相关推荐

  1. 关于NOTIFYICONDATA的一些新特性

    最近初接触MFC,是为了实现一个传感网络的上位机. 在实现托盘提示时,在网上搜索了不少资料,但已经翻译的资料都比较老. 在查看原版的MSDN后,发现NOTIFYICONDATA这个结构中有几项新特性, ...

  2. Visual Studio 2008 SP1 和 net framework 3.5 新特性

    [IT168 分析评论]盼望已久的SP1终于发布了,新特性果然不少,我最关注的是对JavaScript的支持以及WPF性能的改进.先把这文章翻译一下,等我体验一番后再来补充前面的废话就不翻译了,主要关 ...

  3. Visual Studio 2010带来的新机遇、新特性和新动力

    新机遇:一键实现部署云计算开发 当前, 微软最新的战略和愿景是"三屏一云",即怎样通过互联网.以软件为主体,通过不同的设备为广大客户带来无缝体验.主旨就是研究怎样将互联网和数据中心 ...

  4. 我要学ASP.NET MVC 3.0(一): MVC 3.0 的新特性

    摘要 MVC经过其1.0和2.0版本的发展,现在已经到了3.0的领军时代,随着技术的不断改进,MVC也越来越成熟.使开发也变得简洁人性化艺术化. 园子里有很多大鸟都对MVC了如指掌,面对问题犹同孙悟空 ...

  5. .NET 4.0 Interop新特性ICustomQueryInterface (转载)

    .NET 4.0 Interop新特性ICustomQueryInterface 在.NET Framework v4.0发布的新功能中,在名字空间System.Runtime.InteropServ ...

  6. oracle如何查询虚拟列,Oracle11g新特性之--虚拟列(VirtualColumn)

    Oracle 11g新特性之--虚拟列(Virtual Column) Oracle 11G虚拟列Virtual Column介绍 在老的 Oracle 版本,当我们需要使用表达式或者一些计算公式时, ...

  7. mysql8导入 psc 没有数据_新特性解读 | MySQL 8.0.22 任意格式数据导入

    作者:杨涛涛 资深数据库专家,专研 MySQL 十余年.擅长 MySQL.PostgreSQL.MongoDB 等开源数据库相关的备份恢复.SQL 调优.监控运维.高可用架构设计等.目前任职于爱可生, ...

  8. mysql query browswer_MySQL数据库新特性之存储过程入门教程

    MySQL数据库新特性之存储过程入门教程 在MySQL 5中,终于引入了存储过程这一新特性,这将大大增强MYSQL的数据库处理能力.在本文中将指导读者快速掌握MySQL 5的存储过程的基本知识,带领用 ...

  9. windows无法配置此无线连接_Kubernetes 1.18功能详解:OIDC发现、Windows节点支持,还有哪些新特性值得期待?...

    Kubernetes 1.18发布,一些对社区产生影响的新特性日渐完善,如 KSA(Kubernetes Service Account) tokens的OIDC发现和对Windows节点的支持.在A ...

最新文章

  1. 吴恩达新书《Machine Learning Yearning》中7个实用建议(附论文)
  2. redis java对象操作
  3. 2019-10-14 无约束条件的泛函极值问题的举例说明
  4. java中英对比_2017-11-09 中英文代码对比系列之Java一例
  5. javafx 自定义控件_JavaFX技巧10:自定义复合控件
  6. cocos2d-x系列 Mac下配置cocos2d-x开发环境(android和ios)
  7. springboot整合Mybatis例子
  8. html树图制作,d3.js制作树结构图
  9. Java人脸识别登录案例(基于百度人脸识别AI)
  10. java 替换pdf 文本_java 查找替换pdf中的指定文本
  11. Docker-删除untagged docker images
  12. 深度解析 steam密码js逆向(篇幅很长)
  13. vue里面实现百度地图 标记多点 地点连线
  14. 清理FLASH_RECOVERY_AREA
  15. 数据库sql优化总结之1-百万级数据库优化方案+案例分析
  16. mysql 设置忽略大小写
  17. String的intern()方法详解
  18. 基于微信小程序的校园信息共享平台 毕业设计-附源码211615
  19. 支付宝APP支付 (JAVA生成支付信息,uniapp拉起支付宝支付)
  20. Java反序列化(一) - Java反射机制

热门文章

  1. 微信小程序--查看变量类型的方法(简易)
  2. 系统找不到指定的路径。 (异常来自 HRESULT:0x80070003)
  3. 问题 : 最少钱币数
  4. 如何给 ESP32 选择外接 Flash 以及如何使能 QIO 模式
  5. uniApp填坑之旅
  6. pycharm终端运行manage.py没有反应
  7. 91期百淘感想-创世记
  8. POWERBI 连接 DM ODBC
  9. [FAQ11117] 如何把状态栏信号格改为5格
  10. DELL INSPIRON 1501键盘响应速度慢及最终解决