解决 VS2010(Framework 4.0) 无法引用 vb6 自定义控件的 workaround 方法
前段时间同事遇到了一个问题:无法在 VS2010(Framework 4.0) 下引用 vb6 开发的自定义 Windows 控件,但是在 .Net Framework 3.5 却没有问题。
当在 Framework4.0下引用 vb6的自定义控件时,报错信息为“Failed to import the ActiveX control. Please ensure it is properly registered.”。
当时我们都非常奇怪,微软竟然没有做到向下兼容?或者是 Visual Studio 2010 IDE 的问题?把这个问题咨询了一个从微软过来的同事后没有得到答案,但是他给了我一些思路:就是在 IDE 里引用 ActiveX 或 COM 组件时,IDE 其实是调用了一些外部的工具程序执行了一系列的操作,但是这些外部的工具程序在被 IDE 调用的时候从 IDE 获取了一些默认的参数,而这些默认的参数可能会导致执行结果达不到期望的目标。
通过对比,发现在 Framework4.0的时候,项目引用的程序集中有一个程序集不能定位,这个程序集的显示名称格式为 “Ax” + 被引用 ActiveX 控件dll名称,对应的程序集名称格式为 “AxInterop.” + 被引用 ActiveX 控件dll名称.dll。在 Framework3.5下,这个程序的位置在项目目录的“obj\x86\Debug ”目录下,但是 Framework4.0的对应目录下没有这个文件。
难道源头就是这个文件?
是不是可以欺骗VS2010一把呢?
我们就把 Framework4.0项目下缺少的程序集从 Framework3.5项目下复制过来,放到“obj\x86\Debug”目录下,再尝试往界面上添加控件。
哦,看来有进步,因为报告的错误信息变成了“Failed to create component 'AxHost'”,具体的异常类型为“TypeLoadException”。
看来这个异常是因为新复制过来的程序集导致的。因为刚才复制过来的只有一个程序集,而项目在添加 ActiveX 控件时会自动产生4个程序集,而这4个程序集之间应该存在依赖关系,而分别在Framework3.5和Framework4.0下产生的程序集之间不能直接混用。
于是就继续从 Framework3.5 项目下把剩余的3个程序集也一起复制到 Framework4.0的项目下覆盖原来已经存在的程序集。
但是,结果仍然是不能用,重新创建项目测试了2遍,还是不行。
我们不想在“为什么仍然不能使用”上多花时间,继续关注如何能够在Framework4.0下使用控件。
既然VS2010(Framework4.0)自动生成AxInterop.*.dll程序集失败,那么我们就来手动生成程序集,然后提供给项目引用好了。
这里就使用AxImp.exe这个工具来产生我们期望的程序集。
于是在命令行下运行命令“aximp Test.ocx /out:AxInterop.Test.dll”,等待几秒钟后,产生了4个文件:AxInterop.Test.dll、Test.dll、MSComCtl2.dll、VBRUN.dll。如果命令行不指定参数“out”,则就产生AxTest.dll和其他3个文件。
这4个文件中,只有AxInterop.*.dll 是我们想要的,其他3个VS2010能够生成出来,所以仅复制AxInterop.Test.dll到项目引用路径中。
切换到窗体设计界面,尝试往界面上添加控件,成功!
添加控件完成之后,运行程序,继续报错!
原来是程序集的名称不对,手动产生的程序集引用了那些没有“Interop”前缀的程序集,而VS2010自动生成的程序集都有“Interop”前缀。
于是动用 ildasm 和 ilasm 工具把手动产生的程序集进行了内部调整之后,终于成功。