前几天,我定下了使用GWES的UI方案,周一开始工作后,果然在两天内应用程序开发一路高歌猛进势如破竹,大家用DialogBox、Button、Static Text控件都觉得巨爽无比,总比自己从CreateWindowEx开始写,然后一步一步CODE REVIEW和TEST上来舒服多了。但是昨天傍晚的时候,工程师A遇到个问题,在对话框中加入Slider(进度条)后,该DialogBox就无法显示出来了。
工程师A郁闷了一早上,把DialogBox和Slider的属性翻来复去地改,最后索性对.rc文件直接作文本编辑,但仍然没有效果。下午工程师B也放下手里的活,协助解决这个问题,仍然没有结果。问题的答案结果实在简单到无语,是工程师A没有仔细看文档导致的,然后工程师B也顺着A的方向落入思维陷阱,我也前赴后继掉进去了,一共折腾了大概15人时才爬出来。
晚饭后,我解决的思路大致如下
1、怀疑是DlgProc在WM_INITDIALOG或WM_PAINT时的处理不善导致。所以索性在DlgProc的首行直接打印消息看是否得到的消息正确。结果:只依次得到三个消息WM_SETFONT、WM_WINDOWPOSCHANGED、WM_CLICKACTIVE。连WM_INITDIALOG都没有收到。本思路否决。
2、怀疑是控件的STYLE问题,这个思路是沿着工程师A的方向考虑的。我尝试用VC6建立了X86上的PROEJCT,在VC6里建立DIALOG和SILDER,发现运行起来显示正常。于是比较了VC6的这个RC文件和EVC里有问题的RC文件,发现WINCE支持的控件STYLE只是WINXP上的一个子集。
3、继续上一步思路,在WINCE500里找到其他带有SILDER的RC文件,找到了控制面板里的Volume音量控制。拿来和出问题无法显示的RC做文本比较,发现两份RC文件没有差异,我这份的结果仍然出不来。思路2、3否决。
4、所以是代码问题。尝试了DialogBox和CreateBox, 结果一样出不来。
5、由于昨天在WINCE模拟器上遇到的一个静态全局变量地址传递异样的问题,所以我怀疑这是模拟器导致。把尘封已久的开发板连接起来跑,发现问题仍然存在。
6、想到TCPMP和音量控制即使跑模拟器上也仍然正常显示Slider控件,于是彻底推翻第5条假设。
7、考虑是否为STANDARDSDK_500和IBMCE两个PROJECT都缺少某个支持SLIDER所需的组件导致。由于前面第6条判断,于是立刻推翻本条推理
8、目前排除RC的问题,定位为代码或系统原因。我在WINCE HELP里搜了一下关键字“slider”,搜索结果第一条就是"Createing a TrackBar", 和目录同步后,发现该页处于目录结构
Shell and User Interface -> Shell -> Shell Application Development -> Create Controls
而不是描述BUTTON控件的
Shell and User Interface -> Graphics, Windowing and Events -> GWES Reference -> Window Control Reference
看到这里就知道方向应该对了。前面我们都习惯性思维认为所有的控件都在GWES下面,所以调用方式都一样的,而实际上虽然同样有着CONTROL的名头,却分在不同目录下,其中必有文章。
9、仔细看看Create Controls那一页,开头列出了多种控件的名字,但是没有BUTTON和STATIC TEXT。我选择了表格里的Tree views和Date and time picker控件,在EVC里把这两种控件分别加入DIALOG,结果DIALOG同样也显示不出来。这就进一步肯定了思考方向已经正确。
10、就ms-help://MS.WindowsCE.500/wceshellui5/html/wce50conworkingwithcommoncontrols.htm 这页看到下面,有这个描述
Before you create or use any common controls, you must register them. You register a common control by calling the InitCommonControlsEx function, which registers a specific set of common control classes. Calling InitCommonControlsEx ensures that the common DLL is loaded.
To use most of the common controls, you must include the Commctrl.h header file in your application. To use property sheets, you must include the Prsht.h header file.
MS还特意加粗了InitCommonControlEx。那么估计就是在工程师A的代码里面,没有调用该函数把COMMON CONTROL这个DLL加载进来。我查了一下InitCommonControlEx,先填写一个结构体参数就OK了。后来试了下,不填写结构体,直接调InitCommonControl()也是可以的。OK,都显示出来了,Tree View和Date and time picker也都可以显示了。
————————————————
总结起来,这事的思维陷阱在于:认为eVC绘图面板上的所有控件,调用方式都一样。因为VC上的绘图面板上控件调用方式都一样,而且即使eVC里其他以面板来分类的功能和操作,比如调试面板、文件操作面板,同个面板上按钮使用方法也几乎一样。这和我前面因为点了绘图控件就想着立刻去点Class Wizzard关联MFC类,因此在项目早期评估时错过GWES实现方案的逻辑漏洞有相似之处。结果就是,表面上看起来同类的、十分相似的东西,它的用法却可能是不同的。对接口函数或者工具的使用,还是必须忠于文档,而不是直觉。