ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

记一个界面刷新相关的Bug

2019-07-05 09:04:17  阅读:243  来源: 互联网

标签:窗口 WM 我们 PAINT API gc 刷新 界面 Bug


今天遇到一个比较有意思的bug, 这里简单记录下。
Bug的症状是通过拖拉边框把我们客户端主窗口拖小之后,再最大化,会发现窗口显示有问题, 看起来像是刷新问题, 有些地方显示的不对了。 这里要说明的是我这里的主窗口是非常复杂的窗口, 里面集成了很多组件(cpmponent),有很多层的子窗口。 这个问题只有在特定条件下才会发生, 正常情况下都是好的。
遇到这种问题,我们怎么处理? 
首先当然是观察症状, 究竟是刷新问题, 还是Layout出错了。 我们可以通过Spy++查看窗口层次是不是正确, 窗口位置是不是对的。 查看结果是窗口的层次和Layout位置都没有问题。
既然我们这里遇到的刷新问题,所以我们要从WM_PAINT消息着手, 我们通过Spy++查看相关窗口的WM_PAINT是不是正确。 很快我们就会发现某个窗口正在不停地收到WM_PAINT消息, 很可能与我们的bug有关。
一个窗口不停的收到WM_PAINT重画, 无非大概有几类原因: 正常情况是我们正在做动画, 可能是通过定时器之类的东西让窗口不停地InvalidateRect重画某块区域, 我们的窗口明显不属于这种情况。 讨论异常情况前先讨论WM_PAINT消息,我们知道WM_PAINT消息里一定要调用BeginPaint和EndPaint, 前者告诉系统绘画开始,系统会把当前窗口的无效区域变得有效, 后者结束某次绘画。 异常情况有时是WM_PAINT消息里我们的消息处理函数在某些条件下直接返回了,从而没有调用BeginPaint告诉窗口无效区域已经有效, 这样会因为因为窗口一直有无效区域存在,导致窗口一直收到WM_PAINT消息。 还有一种异常情况情况是我们是在WM_PAINT消息里调用BeginPaint后又调用了InvalidateRect, 这样会导致窗口后面会再次收到WM_PAINT消息, 最后窗口陷入WM_PAINT的死循环。 
那么我们这里的问题窗口属于哪类? 用什么方法可以判断出来?
注意到这里关键的三个API:BeginPaint, EndPaint, InvalidateRect的第一个参数都是窗口句柄, 我们可以通过WinDbg的API断点来跟踪执行过程, Attach WinDbg到我们的主窗口进程,比如我们的窗口句柄是0x209A0, 我们可以这样设置API断点: bp USER32!NtUserInvalidateRect ".if(dwo(@esp+0x4)==0x209A0) {kv;gc} .else {gc}" bp USER32!NtUserBeginPaint ".if(dwo(@esp+0x4)==0x209A0) {kv;gc} .else {gc}" bp USER32!NtUserEndPaint ".if(dwo(@esp+0x4)==0x209A0) {kv;gc} .else {gc}" 上面的条件断点表示,当调用我们的对应的API,并且第一个参数(窗口句柄)是我们的目标窗口时,打印堆栈。
很快我定位出Bug发生的原因了, 条件断点显示了API如下的调用次序: BeginPaint->InvalidateRect->InvalidateRect->EndPaint 找到Bug的原因后,然后把Bug assign给该模块的负责人。 (看我够意思吧,不仅找到原因,还把调用栈都提供了)
另外 ,后面还发现这个bug发生时窗口的某些行为会不对, 测试发现原因是所有窗口的定时器都不能正常工作了。 关于这个问题, 你能想到原因吗? 
如果想不到, 请把我的这篇博客《从点击Button到弹出一个MessageBox, 背后发生了什么》看一遍。 如果看了还想不到, 重点看第4条。
最后, 简单总结下:计算机的好处是它永远不会欺骗你, 它只会按部就班的执行, 所以很多看似奇怪(甚至看似不可思议的问题), 只要你理解了程序背后的机制原理,都是可以找出根本原因的。

转载于:https://www.cnblogs.com/weiym/p/3761948.html

标签:窗口,WM,我们,PAINT,API,gc,刷新,界面,Bug
来源: https://blog.csdn.net/weixin_33748818/article/details/94709652

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有