.NET 声明COM接口

来源:互联网 发布:pps网络电视播放器apk 编辑:程序博客网 时间:2024/06/05 21:57
(本人业余程序员一枚,本文内容均为个人观点,有不恰当的地方欢迎随时指正,不欢迎喷粪,谢谢!)

.NET中,接口(Interface)是一种特殊的类型。使用接口可以规范不同类方法的调用,更好的实现程序的模块化。.NET Framework功能强大,支持COM组件的编写。使用VB.NET或C#等语言,开发者即可快速开发高质量的COM组件。

编写COM组件,需要给COM组件类实现相应的COM接口。但是绝大多数的COM接口并未在.NET Framework当中定义,所以需要开发者自己来实现。

COM(C++)实际上并不支持接口,众所周知,在C++中所谓的接口实际上是结构体(struct)当中定义了一系列虚函数,指定需要实现此“接口”的类需要挨个实现这些虚函数才完成这个接口的实现。因此,C++中所有有关接口的概念全都是模拟出来的,包括接口的继承。也就是说,COM接口的继承关系是模拟出来的,只是在C++代码中看起来像是继承了。而实际上,COM接口之间感觉上是相互独立的,每一个接口都是完整的结构。这么说话似乎并不容易懂,下面我上代码。

<Guid("0000010C-0000-0000-C000-000000000046")><InterfaceType(ComInterfaceType.InterfaceIsIUnknown)><ComImport>Public Interface IPersist    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)>    Sub GetClassID(ByRef pClassID As Guid)End Interface

上面是IPersist接口在.NET中的定义。三个附加特性(Attribute)分别表明了接口IID、接口类型和表明此接口是事先在COM当中定义好的。接口中有1个方法,实现就行了。

下面情况更复杂了,成员增多,也有了继承关系。

<Guid("00000109-0000-0000-C000-000000000046")><InterfaceType(ComInterfaceType.InterfaceIsIUnknown)><ComImport>Public Interface IPersistStream    Inherits IPersist    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)>    Shadows Sub GetClassID(ByRef pClassID As Guid)    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)>    Sub IsDirty()    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)>    Sub Load(<MarshalAs(UnmanagedType.[Interface]), [In]> pstm As IStream)    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)>    Sub Save(<MarshalAs(UnmanagedType.[Interface]), [In]> pstm As IStream, <[In]> fClearDirty As Integer)    <MethodImpl(MethodImplOptions.InternalCall, MethodCodeType:=MethodCodeType.Runtime)>    Sub GetSizeMax(pcbSize As ULong)End Interface

注意了,继承来的成员需要按顺序重新定义,否则COM将不能识别。这是因为.NET中Interface是真继承,而COM中是假继承。COM接口继承是直接将继承的成员原封不动的放在自己成员的前面,和自己的成员一起可访问;而.NET接口继承则不是这样,使用Type.GetMembers你找不到继承自的成员。所以,我们需要重新定义成员函数来占位,这样才能让COM接口在执行时正确的“对号入座”。

说白了,COM接口实际上就是一个函数指针数组(void**),保证数量、顺序和参数一一对应即可,函数名称、参数名称甚至接口名称都不是重点,接口有IID来识别。

本文参考来自Code Project的文章,洋文6的朋友可以看看这里。

另外神站pinvoke.net也是不可多得的臂助,给不知道的小白们介绍下。