如何使用C#调用U8的COM组件之 一前言
前言
我们知道,U8的大部分功能使用VB6语言开发。所以整个U8功能都是基于COM组件技术实现的。对于使用VB6语言开发来说,没有什么问题。我们可以直接使用CreateObject("类名"),动态创建我们需要的组件,然后直接调用其方法。
'创建登录对象
dim c=CrateObject("U8Login.clsLogin")
'调用登录方法
c.login()
这样的开发有点类似脚本语言,非常灵活。但有一个问题,那就是不能使用上IDE提供的类型安全和友好提示,并且如果你没有源代码的情况下,非常难知道类名对应的函数等等。
舍不得的IDE提示
如果想使用IDE的友好提示,在VB6中,我们一般会引用需要的COM组件,然后ctrl+j的时候就能自动出来函数方法了。
为了能够使用代码提示功能,且能够使用C#开发。就必须使用interop技术,技术本身这里先不多解释,就通俗的描述一下:
简单说,为了能够使用NET调用COM组件,必须引用一些DLL文件,这些文件一般都放在C:\U8Soft\Interop下面。
这些文件一般都是以Interop单词加一个点开头的文件,或者AxInterop开头的。
例如:Interop.U8Login.dll,这个文件就是COM版本的U8登录组件。
这些文件中包含了所有COM组件提供的功能类和函数,并准确的给出了具体参数规则。和普通的NET类库是完全一样的。引用之后可以直接new这些类对象,并调用对应的函数直接使用。
Interop的由来
反编译Interop
那么这些Interop文件又是怎么来的呢?当然不是手写出来,他是通过命令行工具得到的,或者你在VS中引用COM组件后,VS会自动帮你做出来这些文件。具体的操作可以百度,这里不展开。
Interop文件如果进行反编译,你会发现她就是NET语言开发的,只是没有具体的实现代码,函数体都是空的,并且都是一些类的声明,其中每个接口类上面,会有一些GUID的属性。这些其实就是COM组件的编码了,或者咱们叫唯一Id,主键等等啦。window就是通过这个id,然后到注册表这个大数据库里面去select一下,看看这个Id对应的dll文件到底在哪里,然后自动根据注册表的文件地址,去初始化我们的类。
所以说Interop就是一个提供类型安全和GUID对应的类库文件。有了类型安全,就有了IDE自动提示,有了GUID就能让windows找到COM,微软提供的这个技术还是蛮不错的,但是也存在着不完美的问题。
Interop存在的问题
问题一,拖家带口的Interop生成过程
如果你使用百度提供的方法去生成Interop文件后,你会发现一个很奇怪的事情,就是本来我想生成一个COM组件的Interop文件,结果生成出来的Interop文件好多个。
比如我想自己生成一个U8login.dll的Interop文件,结果搞出来一看,居然还有Interop.msxml2.dll和adodb.dll文件。那么这是怎么回事呢?
其实这里需要换一个角度理解问题。因为在NET里面,类库都是包装在DLL里面的,所以一个DLL就提供一套类库功能,比如log4net.dll,就提供日志功能。
以此类推,每一个COM组件,微软都认为应该有一个独立的DLL文件,所以U8login.dll封装以后,就会理所应当的变成Interop.U8Login.dll,其中也只包含了Login组件的类和函数。
可是,当COM组件引用了其他的COM组件,或者说,如果U8login中某个函数的返回值或者参数居然是另一个COM组件时怎么办呢?比如ado组件中的cn和rs都是我们最常用的参数类型。如果U8Login的某个函数需要返回cn。这时候cn对应的类功能,应该放在哪个文件里面呢?
微软在这个时候就显示出来他的可怕智慧,他就会非常智能(傻逼)地给你把需要的COM组件,逐一,自动地生成对应的Interop文件,然后让Interop.U8Login.dll去引用这些Interop.XXX.dll。注意这句话里面的引用这个动词。
比如,我们先Interop一下U8login.dll,然后得到Interop.U8Login.dll文件,随后需要Interop另个一COM组件,假设是VoucherCO_SA.dll,这是一个销售模块最核心的保存类组件,API就是直接调用他去保存单据的。当我们把他Interop一下后,会发现,居然又是一大堆Interop文件,其中可能还有Interop.U8Login.dll!这个时候就非常尴尬了,因为从引用的角度考虑,我们希望自己的Interop新文件最好去引用之前已经生成好的劳动成果,而不是每次都拖家带口的搞出来一大家子DLL。
问题二,强命名Interop文件后的DLL陷阱
如果我们翻看C:\U8soft\interop文件夹下的文件,你会发现,其中的Interop.U8Login.dll是有强命名的,而密匙文件snk也没有给咱们,同时目录下面还有一个叫做ADODB.dll的文件,居然也有强命名。
连带着问题一,就会发现,如果我们去生成VoucherCo_SA.dll,由于拖家带口,此时你就会得到两个Interop.U8Login.dll文件,一个是没有强命名的微软自动生出来的,一个是总部标准提供的,而Interop.VoucherCo_SA.dll引用的,是无强命名的那个文件。
这时候,就会发现整个环境已经混乱了,我们进入了Dll陷阱中,即同名文件,同类库,不同强命名。
问题三,该死的WIN7和该死的ADODB
如果你使用的是WIN7系列的操作系统,那么恭喜你了,在Interop生成这个环节,你会非常非常郁闷,因为只要遇到引用了ADODB.dll的COM组件,你根本Interop不出来文件,包括Window2008系列的系统。
核心原因是ADODB这个组件在win7时代被改过,具体这里不展开说了,简单说,在这种系统下编译VB6组件程序,不能在XP下使用,InteropADODB相关组件,会直接失败。加之拖家带口问题,你基本就没有几个COM组件能搞出来了。
这个问题在Win2003下和Win10下都不存在,微软后来吸取教训修改了Win10系统中的ADODB组件。所以如果开发的话,必须准备两个环境,一个Win10虚拟机,一个Win2008R2虚拟机,我一般使用08R2虚拟机进行程序开发,Win10就测试发版和COMInterop用。
本章完,请看第二章