即时焦点:记一次有教益的焦点窗口查找过程—— 一定注意 spy++ 的这个坑
前一阵子,同事遇到了一个诡异的 bug,新版本发出来后之前运行好好的功能不好使了。原来的逻辑是:点击板上某个埋件的时候,会弹出四个定位编辑框,其中的一个编辑框需要获得焦点,方便用户直接修改,按 tab会切换到下一个编辑框。但是新程序的行为发生了变化——点击埋件的时候,四个编辑框没有一个获得焦点。本文记录了使用 spyxx和 accevent.exe定位此问题的过程。
初步调查同事演示了一下现象,大概现象如下:
抢焦点可以发现,左侧的编辑框先是获得了焦点(获得焦点的时候会选中全部文字),然后很快被抢走了。
(相关资料图)
因为之前在开发其它功能时也遇到过焦点被命令编辑框(软件底部中央的编辑框)抢走的情况,所以经过一定的观察后,断定跟上次是一样的问题。由于之前遇到的那个问题是通过其它方式解决的,这次的问题不能用相同的方式解决,于是建议同事跟客户反馈一下,让平台同事帮忙处理一下抢焦点的问题。
再次调查过了一天,客户那边反馈可以使用某个命令禁止命令编辑框抢焦点。执行这个命令后,发现命令编辑框确实不抢焦点了,但是焦点还是会被抢走。
跟同事了解完相关代码逻辑后,找到了被抢走焦点的编辑框类。该类中包含一个响应函数 OnKillFocus(CWnd* pNewWnd)。从名字可以看出,该函数是处理失去焦点事件的,该函数只有一个参数,从名字看该参数是新获得焦点的窗口对象指针。于是,果断在这里设置断点,并且设置中断时输出调试信息后继续执行代码。经过几次观察,可以发现,焦点总是被某个固定的窗口抢走。
OnKillFocus既然焦点总被固定的窗口抢走,说明这个窗口是固定存在的,不是临时窗口。既然是固定存在的窗口,就可以通过 spyxx查看到底是哪个窗口。但是当我在 spyxx中输入这个窗口句柄时,却怎么也找不到这个句柄对应的窗口!真是怪事!
can-not-find-this-window 保存调用栈虽然没能通过 spyxx找到对应的窗口,但是却发现了一条非常有用的信息 —— 每次焦点都会被同一个窗口抢走。那么可以在 OnKillFocus()函数内部设置条件断点,当 pNewWnd是特定值时才中断。这样就可以在目标编辑框失去焦点时中断下来。中断下来后,简单查看调用栈,由于缺少调试符号,没有发现什么有用信息。保存一份完整转储文件,后面可以发给平台同事,让他们帮忙查看具体原因。
提示: 转储文件是程序某个时刻的快照。调试时保存转储文件个非常好的习惯,尤其是那种不轻易重现的问题。好不容易抓到一次,一定要先拍个照。防止调试器意外退出,追悔莫及。懂的都懂,对吧。
其实,这个问题调查到这一步已经够了。因为这个问题已经很明确了(焦点被其它窗口抢走了),而且外网没有相关代码,只能等平台同事处理。但是,我特别好奇到底是哪个窗口把焦点抢走了,为什么在调试输出中看到焦点每次都被同一个窗口抢走,但是在 spyxx中却查不到这个窗口。
继续折腾之前做读屏软件开发的时候了解到,除了 spyxx,还有其它工具可以查看窗口信息。比如,可以通过 Inspect, UISpy, accevent等工具以追踪焦点的方式自动获取当前获得焦点的窗口。但是,这次在使用这几个工具的过程中,发现很大概率会导致主程序发生 StackOverflow异常(在这里浪费了很长时间)。最后发现,使用 accevent32,并且只监听 OBJ_FOCUS事件的时候,不会发生异常。
accevent32-setting按上图设置好之后,点击 OK按钮,即可监听焦点变化事件。终于抓到了这个偷抢焦点的窗口。
accevent-watch-focused-window好像抢焦点的是主窗口?赶紧用 spyxx查看主窗口句柄,果然主窗口的句柄是 00541376,与使用 accevent捕获到的窗口句柄是一样的。
这次,终于知道是哪个窗口抢走了焦点,但是为什么主窗口会抢焦点,还是需要平台同事帮忙调查原因了。
为什么 spyxx 找不到窗口为什么之前在 spyxx里输入窗口句柄,但是却找不到对应的窗口呢?在 vs输出窗口中显示的窗口句柄是 0x0000000000541376,在 spyxx中输入的也是 0x0000000000541376,没道理找不到。但是在 accevent里看到的窗口句柄是 00541376,难道在spyxx中输入 00541376就可以查找到了?赶紧试试。
find-window-by-spyxx果然,输入 00541376是可以找到对应的窗口的。但是当我尝试使用 0x00541376查找窗口时,却无法找到匹配的窗口。看来,在 spyxx中通过输入句柄查找窗口时不能输入 0x前缀。
反思在整个过程中有一点做的特别不好:本来可以修改 OnKillFocus()函数中的代码,多打印一些信息,比如获取窗口范围,窗口类名等信息。这样就可以直接在代码里定位到是哪个窗口抢走了焦点。但是根据之前的经验,编译一次比较耗时,所以潜意识里不想修改代码,只是想着通过为断点设置输出信息的方式打印了一些辅助信息。
总结Inspect, UISpy, accevent等工具也是一种可以查看窗口信息的工具,在某些情况下可能非常有用。
在 spyxx中通过输入窗口句柄查找窗口时不能输入 0x前缀,否则会出现找不到窗口的情况。
相关阅读
-
世界热推荐:今晚7:00直播丨下一个突破...
今晚19:00,Cocos视频号直播马上点击【预约】啦↓↓↓在运营了三年... -
NFT周刊|Magic Eden宣布支持Polygon网...
Block-986在NFT这样的市场,每周都会有相当多项目起起伏伏。在过去... -
环球今亮点!头条观察 | DeFi的兴衰与...
在比特币得到机构关注之后,许多财务专家预测世界将因为加密货币的... -
重新审视合作,体育Crypto的可靠关系才能双赢
Block-987即使在体育Crypto领域,人们的目光仍然集中在FTX上。随着... -
简讯:前端单元测试,更进一步
前端测试@2022如果从2014年Jest的第一个版本发布开始计算,前端开发... -
焦点热讯:刘强东这波操作秀
近日,刘强东发布京东全员信,信中提到:自2023年1月1日起,逐步为...