转自:http://ajxfxb.blog.163.com/blog/static/56675086200911181118562/此问题以前一直没有碰到过,因为VB建立的COM和ActiveX的工程,都是超级智能,什么都封装好了,连组件注册都帮你弄好了,而且VB没有提供入口来修改这些属性。
以前用VB建立这类工程,不需要关心这些细节,也没碰到过什么问题,因为的确,CLSID都是自动生成,不需要人为干涉。直到今天去上海大平洋保险出差,遇到金蝶OA系统的一个问题:编设出来的组件CLSID和已经布署的系统的CLSID不一样!
这下就出问题了,因为在完成测试新编译出来的组件之前,我们不能把新改的组件布署上去(反正原因很复杂……)。最后是没办法,只好研究一下VB中是如何设置组件的CLSID的。
第一感觉就是VB建立工程的时候,用随机算法算出一组CLSID,然后存在某个地方,因为只有这样,每次编译时,才能保证同一组CLSID。但是把工程目录搜索了一遍,包括ASCII和二进制搜索,都搜不出来,挨个挨个文件看也看不出。
只好研究VB的工程相关设置,也没发现,最后觉得有点令人怀疑的地方是所谓的VersionCompatiblity(“版本兼容”)。研究后终于搞清楚了其中来龙去脉。
VB的兼容卡中有三个设置:(工程属性--部件--版本兼容)
1、NoCompatibility:不兼容,此设置下,每次编译出的CoClass和Interface的CLSID都会不一样。
2、ProjectCompatibility:工程兼容,此设置下,每次编译出的CoClass的CLSID一样,但Interface的CLSID不一样。
3、BinaryCompatibility:二进制兼容,此设置下,保证每次编译出的CoClass和Interface的CLSID都一样。
当选择2和3时,还要在下面的Edit输入框中输入欲与其兼容的ocx文件。也就是说,要保证2和3,工程移动时必须把dll/ocx都要一起拷过来。否则编译出来的COM对象CLSID就不一样了。
如果丢失原来的ocx文件,就会弹出“Unalbe to set the version compatiblecomponent:XXXX”错误信息,你只能强制改为选项1不兼容,但此时你编译出来的组件CLSID会重新生成,也就是说和原来的就不一样了。
当然,因为类型库本来就以资源形式挂在dll/ocx中,所以你也可以直接修改二进制文件。需要注意的是,资源文件中是以二进制来存的,不是以ASCII码来存的。
利用这些原理,也可以写一个方便的插件来实现在VB中对组件CLSID的设置,有空写一个:)。
另外,基于这种原因,如果使用VB编写组件,使用方尽量使用ProgID,因为ProgID即VB中的子类名(.cls),也就是说,是可以很容易设定的。