工作需要,同一个物理设备需要向上层模拟成两个逻辑设备,即CIM与CDM,为便于后期扩展,为两个逻辑设备开发了两个进程外com组件(使用VC6中的MFC exe,dialog类型),因上层是使用js脚本编写,为便于调用,分别为每个进程外com组件(out-of-process component)分别提供了对应的ocx控件,ocx会创建对应的exe控件,使用CreateDispatch方式,如下图:
上图所示的m_CIM为ocx(客户端)中导入的exe(服务端)代理类,在vc6开发工具中,只需要在ocx工程中添加class时选择从typelib创建类,找到exe的tlb文件即可。
问题出现了,假若我生成的exe和ocx文件如下:
CDM.exe
CDM.ocx
CIM.exe
CIM.ocx
当执行第一次双击执行cdm.exe时正常,第二次双击执行cdm.exe时,报如下图所示错误:
使用ActiveX Control Test测试工具,分别调用两个ocx控件时,第一个调用成功,第二个调用总是失败,使用dbgview工具查看输出,发现报如下错误:
下面是分析过程:
1)怀疑是程序内部报的上图所示的487错误,经查找未找到
2)怀疑是由于win7上的短文件名导致,因为在公司另外一个win8上没有出现这个问题,将此exe组件依赖的所有可能导致长文件名的更换成短文件名后,问题依然没有解决
3)查看代码,发现在exe工程的App类的InitInstance方法中存在删除同名进程的部分,当时主要是因为在上层应用关闭时,尤其是从进程管理器中关闭时,此exe经常性的关闭不了,这会导致下次打开应用时出现错误; 但在实际使用中发现此方法不靠谱,因此又用了另外一个更有效的方法; 在此将此部分屏蔽后,问题有所减轻
4)发现将此exe依赖的一些dll放到了与此exe同级目录下,问题消失,因此怀疑是否是因为exe对mfc依赖库的链接方式错误导致,将链接方式更改成静态连接后,有效果
5)为便于中间设备状态的记录等,为这两个exe开发了一个atl的dll,将其从工程依赖中去掉,有效果
6)cim和cdm依赖的外部库全部一样,但从depends中看两个依赖的库顺序不相同,在工程文件中对顺序进行了调整,使之相同,问题算是彻底消失了
总结,更改后有效果的地方如下:
1) 在exe组件的APP类的initInstance方法中,尽量不要做过多的动作,建议只做基本简单,例如记个日志什么的
2) mfc的依赖库,对于像浏览器调用的这种,建议最好静态链接
3)ATL组件与简单的dll还是有区别的,ATL组件在某些情况下不能当做简单的dll来使用
4)相关联组件的依赖库顺序,建议设置成一样的
以上即是这次遇到的问题,做个记录!