问题
测试同学反馈了一个持续几个版本都没解决的bug,程序带的内嵌播放器的截取与转码功能不能正常工作。
定位
日志上看到是CreateWindowEx失败了,当时就有点奇怪,一般比较少会创建窗口失败啊,再说这个功能之前也是正常的。
打开代码一看,找到CreateWindowEx的调用之处,前后左右都检查了下,没发现代码有什么异常的地方,这更让人纳闷了。
因为问题是必现的,所以直接debug模式开断点跑到问题所在之处,发现有更奇怪的地方,CreateWindowEx失败之后,GetLastError返回是0。
赶紧打开MSDN,仔细查看了这个函数的说明之后,还是没察觉到什么。
接着网上再找找这个问题,发现有个老外写了篇文章,专门总结了CreateWindowEx调用失败的原因,里面提到CreateWindowEx在创建了窗口之后,是会发送WM_NCCREATE, WM_NCCALCSIZE,WM_CREATE这三个消息给窗口的,如果在WM_CREATE的消息处理中,返回-1的话,窗口出来的窗口会被销毁,然后函数返回NULL。这下有点端倪了。
再回过头看看代码,这里创建的是一个ATL的窗口(窗口类名是ATLAXWIN_CLASS宏),难道是这个地方出了问题?
CreateWindowEx(WS_EX_TOOLWINDOW, _T(ATLAXWIN_CLASS), szProgid,
WS_CHILD|WS_CLIPCHILDREN|WS_CLIPSIBLINGS, GetDesktopWindow(),
NULL,_AtlBaseModule.m_hInst, NULL);
继续开启断点调试,从AtlAxWinInit => AtlAxWindowProc => AtlAxCreateControlLic => AtlAxCreateControlLicEx => CreateControlLicEx => CreateNormalizedObject 一步步跟踪下来,终于发现失败的原因了:CoCreateInstance创建控件对象失败,最终使得WM_CREATE消息处理返回-1,从而终止窗口创建。
呼~~~,接下来就好办了,检查了下控件的注册表信息,是完整的,但是InProcServer32里的路径对应的文件不存在了,再打开对应的目录一看,恍然大悟。
原来这个控件对应的dll名字有带版本号,升级的时候应该是注册表信息没处理好,结果旧文件删除了,新文件也放上去了,但是注册表信息没更新,最终使得CoCreateInstance无法把控件创建出来。
把这个问题反馈给了控件的作者,等他修复了。
网友评论