C#用C#编写1个经过外的COM组件示例代码讲解

 

代码的链接在《用C#编写2个历程外的COM组件》,小技巧:即便您要同时看示例代码和讲课的话,能够用浏览器分别打开示例代码和那篇文章,然后采纳Windows提供的纵向平铺窗口成效就可同时看两篇小说了。

 

TestComVisibleClass.cs里面定义了大家要发表给COM客户程序的.NET对象,由于大家的.NET进度外组件须要调用多少个COM库的API,因而在ComHelperClass里面定义这一个API在.NET里面包车型地铁宣示格局,正确地声称P/Invoke函数的原型10分难堪,须求程序员对Win3二,COM和托管代码都很纯熟才足以做,所以自身写了其余一篇作品《利用Signature Tool自动生成P/Invoke调用Windows API的C#函数证明》简化P/Invoke函数申明的步子。

 

ComHelperClass类里面CoRegisterClassObject函数的原型相比好玩,注意rclsid参数前边的[MarshalAs(UnmanagedType.LPStruct)]天性,那本性格告诉.NET,在从.NET1端传递rclsid参数值到非托管代码1端时,不要采取暗中认可的列集(马尔斯hal)规则,在P/Invoke里面,NET私下认可将结构体对象完整复制到非托管的内部存款和储蓄器里,使用UnmanagedType.LPStruct告诉NET将Guid对象的指针传递给非托管函数,就节省了在调用的时候添加ref关键字的劳动,UnmanagedType.LPStruct会有其余1篇小说来诠释它,它稍微尤其。.NET暗中认可将类实例对象列集成VA福睿斯IANT拷贝到非托管的内部存储器里,由此第二个参数我用[MarshalAs(UnmanagedType.IUnknown)]通告.NET须求将那么些指标实例列集成IUnknow
*指针。

 

大家的.NET进程外组件有望被部分C++编写的客户端调用到,对于C++程序来说,使用前绑定(即透过接口指针调用接口成员函数)的方法会尤其有利于一些,不然使用延缓绑定技术(通过IDispatch接口调用接口成员函数)的办法C++代码会相比较复杂一些。因而将TestComVisibleClass的有的主意和性质提取成3个接口,并且分别给ITestComVisible接口和TestComVisibleClass类分配了三个GUID,在COM世界里,前者正是大家熟识的IID,后者则是CLSID。

 

并且,为了有利于VB程序使用.NET进程外组件,作者还特意给ITestComVisible接口的习性和函数钦命了DispID,因为在OLE规范里,DispID为0,-一等多少个特殊值的函数有分外的意义,这点作者将会在末端的篇章里讲到。

C#, 

鉴于大家不可能用mscoree.dll自个儿提供的类激活策略来在COM中激活我们的.NET对象,mscoree.dll私下认可提供的激活策略也会在后面包车型大巴文章里讲到,我们只可以显示地提供类厂,并且将大家的类厂在COM运转Curry面注册一下。类厂(ClassFactory)的连锁接口同样须要定义七个C#款式的原型,一个相比取巧的主意就是应用tlbimp生成三个dll,大概尽管看看System.Runtime.Interop瑟维斯s.ComTypes命名空间里面是还是不是业已有定义好了的项目?IClassFactory最重视的两个函数就是CreateInstance,我们的落到实处正是探望客户端需求哪些样子的接口,借使是IUnknown只怕是我们发布的ITestComVisible(拾二行到10柒行),不然就在十九行的职分上抛出3个很是(蒙受错误就抛分外的习惯在COM世界里不是3个温馨的办法,小编的代码为了简单就动用了抛十分的点子,越来越好的做法是回到错误码,由COM客户端决定哪些处理这么些错误。)

 

在先后运行的时候,我们将本身完毕的类厂注册在COM运转Curry面(Program.cs的4八行到5三行),记得保留CoRegisterClassObject重临给我们的注册ID(第六3行)。Program.cs里面包车型大巴35行到4四行可选,它们的目标是做一些安检,确认保证唯有1些有权力的用户才能调用你的C#
Dcom组件,借使您对安全性不关心的话,能够去除它们。在程序退出的时候(Program.cs的二陆行到2玖行)扫除一些破绽,释放部分财富。

 

那怎么大家还要四个注册表文件呢?这是因为在前绑定调用方式里,我们需求将指针在经过间传递,比如在客户端C++代码的第11行,实际上CoCreateInstanceEx须要运维咱们的.NET进度(也正是进度外COM服务器),调用我们在Program.cs的第陆三行注册过了的IClassFactory接口来创立.NET对象实例,然后将实例的ITestComVisible接口指针从.NET进度传回C++客户端进程里来。恐怕有人会说,能够一贯将指针的地方到C++客户端进度去呗?这是老大的,因为Windows操作系统将经过与其他进度独立开来,简单说,1个经过之中的虚拟内部存款和储蓄器地址在此外2个历程之中大概指向2个杂质,原理请参见操作系统书籍里面关于虚拟内部存款和储蓄器的叙述。

 

为了在经过间传递ITestComVisible接口指针,COM库供给领会什么列集ITestComVisible指针,壹般境况下,程序员需求提供别的两个DLL,那一个DLL蕴涵了列集ITestComVisible指针的代码。为啥要提供代码来列集指针的原故是,不一致的接口包涵不相同的函数,例如在客户端C++代码的第二五行和第三陆行,COM库必要列集远程函数调用(科雷傲PC),也正是亟需八个办法将TestMethod和Release的调用区分开来。1般那几个DLL,可以通过用msidl.exe分析IDL文件来生成列集函数的源代码编写翻译生成。可是,那种办法相比较劳累,因此微软提供了OLEAUT3贰.dll,里面有贰个通用的接口列集函数(可是那个函数不可能列集全部的接口,能够列集的接口供给依据1些平整,这一个后边有时间再讲),可以透过分析TLB文件来列集指针,因为TLB文件也等于.NET Assembly里面包车型大巴元数据,oleaut3贰.dll能够驾驭你的com组件里面有哪些接口,各样接口的申明又是何等的,函数的参数类型是何等等等。不过oleaut3二.dll供给查询注册表才能清楚接口存在的Tlb文件的职位:

1.         由此注册表代码里面包车型大巴第二行到第3陆行在注册表里面保存了类型库的寄放路径,注意,在COM世界里,tlb文件也是用GUID来唯壹标识的,你能够用oleview.exe打开regasm.exe可能tlbexp.exe生成的tlb文件,找到[custom(9903F14C-12CE-4c99-9986-2EE3D7D588A8)…]那壹段文字来找到Tlb文件的GUID。

2.         注册表代码里面包车型客车第二八行到第1捌行,在注册表里面保存了列集ITestComVisible接口的新闻,例如ProxyStubClsid指的是行使oleaut32.dll提供的通用接口列集函数,并且保留了该函数所使用tlb文件的新闻(第一陆行到2捌行)。若是注册表里面未有列集接口的新闻,CoCreateInstanceEx函数会重返E_NOINTEENVISIONFACE(不补助此接口)错误—3个令人稀里糊涂的错误代码。

3.         最后注册表代码里面包车型地铁第叁0行到第伍一行向全世界表明(不好意思,不是中华夏族民共和国全体公民从此站起来了的那种注明):大家的.NET对象不供给通过mscoree来在COM端激活,自身能够成功激活操作,因而我们删掉了由re瓦斯m.exe插入的InprocServer3二键值,而是添加了LocalServer3二键值。

 

附,上边注册表代码里面包车型大巴第壹行到第3捌行能够用RegisterTypeLib函数来形成,而RegisterTypeLib所供给的ptlib参数能够经过LoadTypeLib函数来得到。

相关文章