.net core com对象使用分析

com的概念:

COM对象是遵循COM规范编写、以Win32动态链接库(DLL)或可执行文件(EXE)形式发布的可执行二进制代码,能够满足对组件架构的所有需求。

com的定义

COM:The Component Object Model 组件对象模型

遵循COM的规范标准,组件与应用、组件与组件之间可以互操作,极其方便地建立可伸缩的应用系统。COM是一种技术标准

综上,可以看出,com有3种特征:1、与接口相似,有自己严格的标准规范 2、实现更偏向功能完整的组件 3、与语言无关

再来看下.net core创建com对象的方式:

1.使用.NET包装COM组件

    这是最简单的就是导入COM组件所在的DLL,让IDE生成。NET一个IL包装加到项目中,这样原来COM里面所有实现了IDispatch,Dual的COM类型及其相关类型就可以直接在。NET程序里面使用,比如以前在2003时代,想要写自己的基于IE的浏览器,就得手动加入与IWebBrowser2接口相关的DLL,这种方式是大家最常用的,也是最傻瓜化的,因此也没什么可解释的。

    但是这种方式有个至命的缺点——不是所有的C# COM对象都能用这种方式导出。正如前面所说的,只有实现了IDispatch,Dual类型的接口才支持被导出,而且面对不同版本的COM或许会生成不一样的导出DLL,比如说A机器上写代码时导入了一个Jet2.6版本的包装DLL,代码编译了拿到B机器上去运行,但是B机器上的Jet版本是2.8的,就可能会出现运行时错误。

2.用反射动态创建

    包括使用Type.GetTypeFromCLSID和Type.GetFromProgID两种方法获取COM对象的Type再创建.这种方式也好理解,就是说使用这两个方法之前,必须得知道COM对象的GUID或ProgID,好在这也不是什么难事,一般我们要使一个COM对象,多多少少都了解一些这个COM对象的GUID或ProgID信息.用这种方获取到了一个Type对象后,就可以用.NET里面通用的反射创建对象的方法来做了.

    这里给出一个创建JetEngine 的COM对象的代码实例:

Guid g=new Guid("DE88C160-FF2C-11D1-BB6F-00C04FAE22DA");
Type Typet=Type.GetTypeFromCLSID(clsid);  
if(t==null){}
else{
    Activator.CreateInstance(t);
}

    是不是觉得最后调用GetActiveXObject(g)的地方和IE里面Javascript里面用new ActiveXOjbect创建COM对象的方法很相像?

3.声明CoCreateInstance外部函数,用这个函数去创建相应的COM实例

    M$在2005里面包装的WebBrowser控件内部就是用这个函数去创建的, 使用这种方式创建COM,就跟在C++里面不什么两样了.有一点需要说明的是,一般我们在代码中引入外部方法的时候,方法的参数和返回值的类型不一定是唯一的一种,只要在逻辑上相互能转化,一般都可以使用.

[return:MarshalAs(UnmanagedType.Interface)]  
[DllImport("ole32.dll",ExactSpelling=true,PreserveSig=false)]  
public static extern object CreateObjectDelegate1([In]ref Guid clsid,  
[MarshalAs(UnmanagedType.Interface)]object punkOuter,intc ontext,[In]ref Guid iid);  
 
[DllImport("ole32.dll",ExactSpelling=true,PreserveSig=false)]  
public static extern IntPtr CreateObjectDelegate2([In]ref Guid clsid,  
IntPtr punkOuter,int context,[In]ref Guid iid);  
  
[DllImport("ole32.dll",ExactSpelling=true)]  
public static extern int CreateObjectDelegate3([In]ref Guid clsid,  
IntPtr punkOuter,int context,[In]ref Guid iid,[Out]out IntPtr pVoid);  
 
[DllImport("ole32.dll",ExactSpelling=true)]  
public static extern int CreateObjectDelegate3([In]ref Guid clsid,  
[MarshalAs(UnmanagedType.Interface)]object punkOuter,int context,  
[In]ref Guid iid,[MarshalAs(UnmanagedType.Interface),Out] out object pVoid); 

那么问题来了,com到底与系统有没有关系呢,.net core是个跨平台的框架,能否使用com的库呢?答案是:不能,至少标准com是不行的,因为是基于win32的,需要实现固定的一套接口。非标准的com,是不完全支持的。对于上面1、2方法,都是基于标准com的,所以在linux下只能考虑方法3去创建com对象

分析下问题,对于非标准com,有点类似库接口的调用,从理论上来说应该是可行的。但c#还有个内存管理的问题,com对象是通过引用计数维护的,而c#是gc,这两者从理论上还是有点冲突。可以看到方法3中的out是object,但从c++头文件可以看到,这个地方实际的签名是void**,也就是.net还有一次内部转换,对c#来说就是IntPtr->object,对应Marshal.GetUniqueObjectForIUnknown(ptr)这个方法,但这个object对应的内存区域却是非托管内存,甚至不是在c#内部创建的,可见这个映射是多么的特殊。很遗憾的是,在linux下,.net core 3.0这个转换还不被支持,猜测可能形成了逻辑闭环。大家可以试试在.net 6以上这个问题是否解决,在.net core中使用这些需要充分考虑跨平台的问题,不然运行中会出异常

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值