缘起
前段日子,遇到两个非常有意思的 MFC 对话框相关的 bug:
- 为
ComboBox控件设置了文本,但是却显示为空 - 明明已经隐藏了控件,但是控件却没有隐藏
最后发现这两个问题是同一个问题,对话框中存在相同 ID 的控件。因为这两个问题是同一个问题,本文只介绍其中一个问题的排查思路。
说明: 实际项目中的情况要复杂的多,本文用到的例子都是我准备的示例程序
初遇错误
程序会在某些情况下显式/隐藏某些特定控件,但是却发现对应的控件没有被隐藏,如下图:

对应的控制代码也非常简单,如下:
1 | CString strTitle; |
反复确认代码逻辑,没有问题。那会是什么原因呢?GetDlgItem() 获取的控件不对?还是调用 ShowWindow() 失败了?还是其它什么原因?
深入调查
通过查看 ShowWindow() 的返回值,发现对 ShowWindow() 的调用是成功的。GetDlgItem() 获取的控件句柄是 0x00020a7c,

通过 spyxx 的窗口搜索功能,在 句柄(A): 对应的位置输入 0x00020a7c,可以发现控件确实已经被隐藏了。
那么显示着的控件又是哪一个呢?再用 spyxx 的窗口搜索功能,拖动靶心到对应的窗口上,可以发现控件句柄是 00060a5e,在对应的列表项上右键,突出显式,可以确认显示着的控件句柄确实是 0x00060a5e。

难道同一个位置有两个一模一样的控件?赶紧查看一下 rc 文件。
查看 rc
果然,在 rc 文件中有重复的控件。
1 | IDD_REPEATCONTROLID_DIALOG DIALOGEX 0, 0, 272, 110 |
说明: 实际项目中,对话框中的控件数量超级多,不像示例程序这么明显,一眼就能看出来有重复控件
至此,可以结案了,因为 rc 中有重复的控件,所以导致在隐藏控件时,只隐藏了一个。另外一个 bug 也是同样的问题,不再赘述。
警示
按理说,同一个对话框中存在相同 ID 的控件,编译的时候至少会报警告。重新编译程序,观察编译警告,果然发现有提示:
1>RepeatControlId.rc(106): warning RC2182: duplicate dialog control ID 1000
一定要注意编译器的警告啊!
亲自动手
示例程序代码已经上传到了github,感兴趣的朋友可以下载体验。
总结
同一个对话框中不要存在有相同
ID的控件spyxx是查看窗口句柄的好工具,一定要善加利用务必注意编译器的警告信息!