【误区分析】TB_BUTTONCOUNT消息获取个数、TBBUTTON结构解析通知图标数据可能是易错的做法
一、基本原理
使用SendMessage函数发送TB_BUTTONCOUNT消息到指定窗口,可以检索工具栏中当前按钮的计数。但这个值可能并不是最新的,个数仅仅是当前个数,而且并非是显示的个数,也非有效按钮窗口的个数。
使用SendMessage函数发送TB_GETBUTTON消息到指定窗口获取指针,然后向指定进程申请访问内存,获取TBBUTTON结构体中dwData字段数据,可以获得远线程的工具栏窗口中当前所有按钮的句柄、标题、进程路径信息。但该信息可能包含旧的内容。
任务栏的通知区域分为四个部分:用户提示的通知区域、系统升级的通知区域,溢出角通知区域、DUI弹出式通知区域(部分图标如:电源电量、音量等的注册记录在溢出通知区域窗口,但是并不是在溢出窗口内显示的,所以单独归类)。通知区域是外壳处理器Shell控件:ToolBarWindow32.
首先我们需要明白任务栏的ToolBarWindow(工具栏视图)的一些特征:
1)除系统升级的通知区域以外的通知区域图标不会自动刷新,需要接收到鼠标移动消息、模拟点击消息才会逐个刷新。
2)如果一个窗口多次在通知区域注册通知图标,即使它是由同一个窗口发出的,也会被记录为独立的窗口,但他们具有相同的信息,在外壳程序内存中相应位置按序排列。
二、案例如何发生?
当开发者尝试使用如下代码获取任务栏图标个数时可能得不到准确的个数:
LRESULT ButtonCount = SendMessage(hWnd, TB_BUTTONCOUNT, 0, 0);// 获取hWnd窗口的图标个数
警告:以下谈到的案例并不局限于任务管理器,其他第三方软件都如此,这和资源管理器外壳Shell的处理逻辑有关系。
误区1:忽略系统升级的通知区域,尽管这个区域经常没有显示,但它位于溢出角按钮和用户通知区之间,当有程序首次创建通知区图标的时候,提供短暂突出显示的时间,这些图标临时显示在该区域,不在用户区和溢出区,当超时完成时(最长60秒)这些图标被放入溢出区(前提是没有被标记为始终显示)。在超时完成前通知统计的用户区和溢出区图标数据中跳过了这些图标。
误区2:忽略重复注册的图标窗口,尽管这在我们看来是相当荒诞的,但它确实发生过,也应该引起相关开发者的注意。
这张图片展示了当任务管理器打开时(等待超时完成后记录的结果),在使用TB_BUTTONCOUNT获取个数时将多次记录到任务管理器窗口,显示为他创建了13个图标按钮,随后通过在外壳进程内存中读取TBBUTTON结构中的dwData数据,得到窗口的标题、句柄、以及目录路径(类名、矩形等其他信息是根据窗口句柄通过相关API遍历枚举的,不是直接获得的结果),不难发现同样的句柄有多条记录,然而我们不需要多余的信息。这是TB类消息得到错误结果的重要原因。
误区3:(对于误区2而言)任务管理器等刚刚注册通知图标的窗口,图标会显示在系统升级通知区,此时记录的个数是真确的(唯一的)。因为他只要接收消息了,就会被移除到溢出区。否则他只允许静默一段时间。
误区4:线程异常退出,而没有注销相应图标。这时候我们把它称作僵尸图标,空有躯壳而没有灵魂。但是这段内存区域中相关信息不会被立即清除。导致获得的计数以及句柄都是无效的。
通过检查窗口的矩形,API调用返回“Error:1400”无效的窗口句柄即可排除该错误带来的影响。
Notice:请观察下图数据
再看下图数据:
以上结果发生在一个已经注册通知图标的程序意外终止时(没有来得及注销图标),外壳程序内存中不会及时删除这些内容,这些内容可能位于错误的内存位置,访问这些位置会带来意外的结果。即使用户已经刷新了视图区域,这些内容依然不会被清除,直到重启资源管理器。
并且对无效的句柄使用GetClassName()返回值为0,但是不会向遍历时候的字符串指针更新数据,所以需要注意变量的作用域或者记得及时检查错误原因,比如此时的LastError为1400,以及最后要记得将内容重新初始化为{0}。一面这些垃圾数据影响用户体验。(显然图中没有考虑到这些问题)
-----------------------------------------------
希望通过我的分析,能够给遇到相关问题的友人一点微薄的解答。文章如果有误,欢迎各位斧正,谢谢!
转载请注明博客来源:@涟幽516(http://t.csdn.cn/CpBeJ)
【误区分析】TB_BUTTONCOUNT消息获取个数、TBBUTTON结构解析通知图标数据可能是易错的做法相关推荐
- 英雄远征Erlang源码分析(1)-源码结构解析
偶然得到了一份英雄远征的Erlang服务端源代码,想着通过对源代码的分析,来熟悉使用Erlang编程语言的游戏服务器的设计,游戏中关键逻辑的实现. 解压压缩文件后,在Idea内导入文件夹创建相关工程, ...
- Swift 系统学习 22 分析错误的三个阶段 (枚举和结构体相关)
//: Playground - noun: a place where people can playimport UIKit/** 本节主要内容:* 1.分析错误处理的三个阶段* 2.三个阶段整合 ...
- Android-33源码分析: Handler消息机制
的声明: ActivityThread 管理应用进程中主线程的执行,根据AMS调度执行广播和其他操作 Handler 发送消息并处理消息 MessageQueue 用于存放消息的消息队列 Looper ...
- 老李推荐:第5章5节《MonkeyRunner源码剖析》Monkey原理分析-启动运行: 获取系统服务引用 1...
老李推荐:第5章5节<MonkeyRunner源码剖析>Monkey原理分析-启动运行: 获取系统服务引用 上一节我们描述了monkey的命令处理入口函数run是如何调用optionPro ...
- RTMPdump(libRTMP) 源代码分析 9: 接收消息(Message)(接收视音频数据)
2019独角兽企业重金招聘Python工程师标准>>> 注:此前写了一些列的分析RTMPdump(libRTMP)源代码的文章,在此列一个列表: RTMPdump 源代码分析 1: ...
- android smack源码分析——接收消息以及如何解析消息
2019独角兽企业重金招聘Python工程师标准>>> 在android里面用的smack包其实叫做asmack,该包提供了两种不同的连接方式:socket和httpclient.该 ...
- RocketMQ 源码分析 事务消息
为什么80%的码农都做不了架构师?>>> 1. 概述 必须必须必须 前置阅读内容: <事务消息(阿里云)> 2. 事务消息发送 2.1 Producer 发送事务消 ...
- 9. 源码分析之消息消费
源码分析之消息消费 Rebalance(针对集群消费模式) (1)消费Group下的所有消费者 (2)Topic的所有Queue队列 (3)Queue分配策略 触发时机 (1)消费者启动 (2)消费者 ...
- 土木工程学生的常见认识误区分析与解答
土木工程学生的常见认识误区分析与解答 2012年01月12日 土木工程学生的常见认识误区分析与解答 误区 1 + `: F. n' [. A7 A 大一大二的时候 好好玩玩 大三大四 考研的时候 在好 ...
最新文章
- python arp扫描_基于python的局域网arp扫描
- django 1.9 mysql_Python3.5+Django1.9+MySQL57+PyCharm5.0.1配置
- 成功的换心手术——Windows Phone 8 发布
- vscode 构建Python ,和C++ 开发环境
- linux c 守护线程,关于守护线程
- 进程的描述与控制 操作系统第二章知识点归纳总结
- 虚拟交换机软件_千兆交换机如何识别优劣,千兆交换机识别方法!
- 安装Eplan时报错的解决方案
- 勒索病毒解密工具的汇总
- thinkphp 页面上循环checkbox选择的值和radio混用,if判断
- 在r中弄方差分析表_R语言——方差分析
- Java 14中对switch的增强,终于可以不写break了
- git 和gitHup工具笔记的详细教程
- 测试开发面试题160道17类21339字
- mysql dual表用法_详解Oracle数据库中DUAL表的使用
- 自我管理 - 希望2015年自己能够做到的几点目标
- Java 编程技术大全(上)实战练习 cp1-cp3
- google退出中国声明原文【翻译版】
- 沅湘流不尽,屈子怨更深,日暮秋风起,潇潇枫树林。
- 电子科技大学 易查分网站 爬虫 批量爬取成绩