最新文章 (全部类别)
.NETCore WebApi阻止接口重复调用(请求并发操作)
VS2022消除编译警告
“SymmetricAlgorithm.Create(string)”已过时:“Cryptographic factory methods accepting an algorithm name are obsolete. Use the parameterless Create factory method on the algorithm type instead
SHA256Managed/SHA512Managed已过时:Derived cryptographic types are obsolete. Use the Create method on the base type instead
MD5CryptoServiceProvider已过时:Derived cryptographic types are obsolete. Use the Create method on the base type instead
C#使用HttpClient获取IP地址位置和网络信息
判断IP是否是外网IP、内网IP
C#使用HttpClient获取公网IP
WebRequest.Create(string)已过时:WebRequest, HttpWebRequest, ServicePoint, and WebClient are obsolete. Use HttpClient instead
C#根据第三方提供的IP查询服务获取公网外网IP地址
html/dom/js/javascript开发记录
调试ASP.NETCore Web站点 - 清理IISExpress缓存数据(js,css)
EFCore+Oracle根据不同的Schema连接数据库
主程序集成CSFramework.EF 数据库框架(.NET7版本)
CSFramework.EF数据库框架简介(.NET8+EFCore)
迁移ECS服务器:导致ORACLE监听服务启动不了解决方案
SQLite数据库
VS2022编译报错:Visual Studio 容器工具需要 Docker Desktop
.NET 9 预览版+C#13新功能
EFCore禁用实体跟踪
WebApi开发框架V3.0 (.NETCore+EFCore) 增加AppSettings全局参数类
C#获取应用程序所有依赖的程序集
LINQ Expression 多条件复合条件组合(And/Or)
CSFrameworkV6客户案例 - MHR - 宁德时代制造人力资源系统
CS软件授权注册系统V3 - 发布证书
C/S软件授权注册系统V3.0(Winform+WebApi+.NET8+EFCore版本)
CS软件授权注册系统V3 - 购买方式
CS软件授权注册系统V3 - 试用版下载
CS软件授权注册系统-客户登记(制作证书)
C/S软件授权注册系统V3.0 - 管理员工具
CSFrameworkV6旗舰版开发框架 - 集成软件授权认证系统
CSFramework.Authentication 软件证书管理系统 - 制作软件客户授权证书
CSFramework.Authentication 软件证书管理系统 - MAC地址管理
CSFramework.Authentication 软件授权证书管理系统
Login/Logout接口调用dalUser的Login/Logout方法
C# Newtonsoft.Json.Linq.JObject 转对象
CSFramework.Authentication 软件授权认证系统 - 软件测试报告
C/S架构软件开发平台 - 旗舰版V6.0 - 底层框架迭代开发
C/S架构软件开发平台 - 旗舰版V6.1新功能 - 增加软件授权认证模块
C/S架构软件开发平台 - 旗舰版CSFrameworkV6 Bug修改记录
CS软件授权注册系统V3 - 开发手册 - 软件集成与用户注册
CS软件授权注册系统-模拟MES/ERP用户注册软件
CS软件授权注册系统-发布/部署WebApi服务器(IIS+.NET8+ASP.NETCore)
CS软件授权注册系统-VS2022调试WebApi接口
.NETCore Console控制台程序使用ILogger日志
CS软件授权注册系统-WebApi服务器介绍
ASP.NETCore集成Swagger添加Authorize按钮Bearer授权
CS软件授权注册系统-WebApi服务器配置
.NETCore WebApi发布到IIS服务器无法打开swagger
.NET8/ .NETCore /ASP.NETCore 部署WebApi到IIS服务器需要安装的运行环境
.net敏捷开发,创造卓越

C#.Net COM交操作性 - 强类型RCW和弱类型CCW详解


C#.Net COM交操作性 - 强类型RCW和弱类型CCW详解

RCW (Runtime Callable Wrapper) 是指.Net运行时可调用包装

贴图图片

CCW (COM Callable Wrapper) 是指COM可调用包装

贴图图片



大家在进行COM Interop编程的时候,不知道]是否会见到这样的情况。通常,我们通过TlbImp.exe把一个类型库(Type Library)转换成Interop Assembly。比如在Type Library里面有一个coclass叫做MyComObject,那么在Interop Assembly中也存在一个MyComObjectClass这样一个托管类型。用户可以直接使用这个MyComObjectClass操作 MyComObject这样一个COM对象,比如使用new创建,调用方法,等等。因为MyComObjectClass并不是MyComObject这个COM对象本身,而是像一个代理(Proxy),.NET中我们将其称为RCW (Runtime Callable Wrapper)。但是在有些情况下,在使用某些函数的时候,理论上应该返回一个MyComObjectClass,然而实际返回的却是一个System.__ComObject类型,这是什么原因呢?


事实上,RCW是存在两种类型的,一种是强类型(Strongly Typed)的RCW,另外一种是弱类型的RCW,即System.__ComObject。


所谓强类型的RCW,也就是说这种RCW具有关于这个COM对象实现了那些接口(Interface),有哪些方法等等各种信息,这些信息都在元数据(Metadata)里面,因此你一旦看到这个RCW,就知道这个RCW是何种COM对象。通常情况下,大家遇到的都是强类型的RCW,这主要是因为 TlbImp对强类型的RCW提供了良好的支持。比如上面所提到的MyComObjectClass便是TlbImp生成的一个强类型RCW。对COM编程有基本了解的朋友应该非常清楚,对于COM对象而言,你在操作COM对象的时候(除了调用CoCreateInstanc创建的时候),大部分时候都是不清楚你在和具体哪个COM对象打交道,唯一的信息只是接口。那么.NET/CLR又是如何做到这一点的呢?当然了,我们无需考虑从.NET代码中直接创建强类型RCW的情形,以及从一个托管方法返回一个强类型RCW的情形,因为这两种情况没有歧义,很显然得到的结果均是一个强类型的RCW。我们主要考虑的是,在非托管方法中返回一个接口,CLR是如何知道这个接口是何种对象的。这种情况是最复杂的。


还是举一个例子:假设MyComObject对象实现了ITest接口。然后托管代码调用某个非托管函数(可以是COM对象/接口的函数,也可以是P/Invoke)的原型如下:


ITest *GetTest();


我们首先分析一下,如果用TlbImp来Import这个函数,对应的托管函数的原型是什么。有两种情况:


1. ITest是MyComObject的缺省的接口(default interface),并且没有其他coclass把ITest作为缺省的接口使用。这种情况下,TlbImp会将ITest转变为 MyComObject接口。注意这个接口是由TlbImp生成的一个接口,而非type library本身里面所具有的,当然更不是这个MyComObject对象(MyComObject对象在TlbImp所生成的Interop Assembly中对应的类型是MyComObjectClass)。这个接口可以认为代表了这个COM对象本身,并且TlbImp会用 CoClassAttribute这个属性把两者关联起来。因此最后的结果是:


MyComObject *GetTest();


2. 否则,TlbImp不做任何改变,直接使用原有的函数原型:


ITest *GetTest();


情况#1其实是最简单的情况。原因是,MyComObject接口因为上面标有CoClassAttribute这样一个属性,CLR在做数据转换(Marshalling/Unmarshalling)的时候,知道这个接口是一个coclass interface,也就是一个直接对应一个COM对象的接口,并且可以轻松通过CoClassAttribute找到对应的 MyComObjectClass这个强类型RCW。因此,CLR可以很容易根据这个信息,创建出一个新的强类型RCW的实例(当然也可能发现这个接口的值符合一个已有的RCW,并且直接返回之),也就是MyComObjectClass的实例。


情况#2下,ITest所对应的对象可能有好几种不同情况:


1. MyComObject这个COM对象


2. 另外的非托管COM对象,实现了ITest接口


3. 托管的CCW,实现了ITest接口


CLR是如何对这几种情况作出区分的呢?关键在于IManagedObject接口和IProvideClassInfo接口。


先谈IManagedObject接口。这个接口是.NET定义的,一旦某个对象实现了IManagedObject接口,说明此对象是托管对象,这也正是这个接口命名的由来。除此之外,IManagedObject在.NET Remoting中也起到了相当重要的作用,用于在服务器端获得序列化的缓冲区,然后在客户端反序列化得到原始对象的拷贝或者Proxy,因为与本文关系不大,因此这里从略。CLR在将非托管的接口指针转换成托管对象的时候,首先要做的就是做一个 QueryInterface(IID_IManagedObject)调用,检查该COM对象是否是一个托管对象,如果是,则直接通过 IManagedObject接口定义的GetObjectIdentity函数直接获得CCW的指针,返回之(这个CCW并非是原始托管对象,而是 CLR的内部实现细节,要得到原始的托管对象,还需要做一系列的操作,这里从略)。顺便说一句,托管对象的CCW缺省实现了 IManagedObject,并提供了IManagedObject接口中的函数实现,这个实现是所有CCW都共享的。同样的还有许多常用接口,如 IUnknown,IMarshal,IConnectionPointContainer等等。


反之,如果这个COM对象没有实现 IManagedObject接口,说明COM对象是非托管对象。这种情况下,我们必须要用到IProvideClassInfo接口。 IProvideClassInfo,正如其名,是用来返回该COM对象所对应的信息的。IProvideClassInfo只有一个函数 GetClassInfo,返回一个ITypeInfo指针。ITypeInfo也是一个COM接口,简单来说就是提供了COM对象的类型信息,类似.NET中的Type对象(但并不是Type对象)。通过ITypeInfo,可以拿到COM对象的CLSID,CLR然后根据这个CLSID来获得对应的托管类型。CLR会查找当前AppDomain中有那个类型是对应这个CLSID。如果没有找到,则回到注册表去查找CLSID所对应的COM注册表项(其实Manifest也可以,这是Registration-Free Com Interop)。一旦CLSID所对应的注册表中指定了对应托管类型和Assembly的名称,CLR便可以通过这个信息加载Assembly并找到对应的类型。这也正是Type.GetTypeFromCLSID所作的事情。一旦这个步骤成功,CLR便知道了这个接口所对应的COM对象的对应托管对象,从而可以通过这个接口指针创建一个强类型RCW。


当然了,这个步骤需要COM对象本身实现IProvideClassInfo接口。因此,当在设计一个非托管COM组件并希望这个COM组件能够比较容易的被.NET使用的话,推荐让这个非托管COM对象实现 IProvideClassInfo接口。反之,如果这个COM对象没有实现这个接口(事实上很少COM对象实现这个接口),或者虽然COM对象实现了 IProvideClassInfo接口,但是CLR无法通过CLSID成功找到对应的托管类型,CLR便别无选择,只能返回一个 System.__ComObject作为弱类型的RCW。


本质上来讲,弱类型的RCW和强类型的RCW并没有太大的区别,只是强类型的RCW具有更多类型信息,比较容易调试。而在实际的编程中,使用方法是完全一致的,只是System.__ComObject必须要先转换到相应的接口,再调用。另外一个非常有趣的事情是,强类型RCW事实上是继承自System.__ComObject的,虽然从Metadata上面是无法看出来,但是在CLR内部这个继承关系确实存在。从本质上来讲,弱类型的RCW更接近非托管的COM编程方法(比如C++),因为用C++进行COM编程的时候,通常都是直接和接口打交道。而并不知道COM对象是什么。对于一个COM对象而言,使用接口来进行操作也是最符合COM本质的做法,我们也不希望在.NET中鼓励大家针对COM对象编程而不是针对COM接口编程。因此,CLR在将来有可能会渐渐减少对强类型RCW的支持,而转而建议使用弱类型 RCW。当然,目前来讲由于工具的支持(主要是TlbImp),大部分情况下还是以强类型RCW为主。一旦大家遇到了弱类型的RCW,也无需惊慌,因为使用方法和强类型RCW并无太大区别。如果希望程序中不要出现弱类型的RCW,那么最好的方法还是使这个COM对象实现IProvideClassInfo 接口。


作者:张羿(ATField)
原文:http://blog.csdn.net/ATField/article/details/2551242


版权声明:本文为开发框架文库发布内容,转载请附上原文出处连接
C/S框架网
上一篇:RegSvr32注册DLL,OCX提示“找不到指定的模块”
下一篇:C#.Net 调用Delphi 编译的ActiveX COM组件(原)
评论列表

发表评论

评论内容
昵称:
关联文章

C#.Net COM操作性 - 类型RCW类型CCW详解
C#.Net 调用Delphi 编译的ActiveX COM组件(原)
尝试释放正在使用的RCW,活动线程或其他线程上正在使用该RCW
C#.Net类型引用类型区别
C#.NET WebApi开发框架成功案例-物流行业系统对接|满帮集团|中兴路|福佑卡车
什么是COM组件,COM对象,COM标准?
C#.Net 静态构造器使用详解
C#.Net反射(Reflaction)技术实例详解
将SQLServer数据类型转换为C#.Net类型
C#.NET GC.Collect垃圾回收机制详解
.NET RichTextBox控件使用详解
手动自动生成业务单据号码UpdateKeyMode详解(1)
C#.NET RESTFul API详解
Delphi程序调用C#.Net编译的DLL并打开窗体(详解)
C# WebService代理类详解
C#.NET理解Taskasync await原理
C#调用C++编译的DLL详解
C#.NET数据类型(Type)与DbType的对应关系
DbType与C#.NET数据类型(Type)对应关系
.NET 6 优先队列 PriorityQueue 详解

热门标签
软件著作权登记证书 .NET .NET Reactor .NET5 .NET6 .NET7 .NET8 .NET9 .NETFramework APP AspNetCore AuthV3 Auth-软件授权注册系统 Axios B/S B/S开发框架 B/S框架 BSFramework Bug Bug记录 C#加密解密 C#源码 C/S CHATGPT CMS系统 CodeGenerator CSFramework.DB CSFramework.EF CSFramework.License CSFrameworkV1学习版 CSFrameworkV2标准版 CSFrameworkV3高级版 CSFrameworkV4企业版 CSFrameworkV5旗舰版 CSFrameworkV6.0 CSFrameworkV6.1 CSFrameworkV6旗舰版 DAL数据访问层 Database datalock DbFramework Demo教学 Demo实例 Demo下载 DevExpress教程 Docker Desktop DOM ECS服务器 EFCore EF框架 Element-UI EntityFramework ERP ES6 Excel FastReport GIT HR IDatabase IIS JavaScript LINQ MES MiniFramework MIS MySql NavBarControl NETCore Node.JS NPM OMS Oracle资料 ORM PaaS POS Promise API PSD RedGet Redis RSA SAP Schema SEO SEO文章 SQL SQLConnector SQLite SqlServer Swagger TMS系统 Token令牌 VS2022 VSCode VS升级 VUE WCF WebApi WebApi NETCore WebApi框架 WEB开发框架 Windows服务 Winform 开发框架 Winform 开发平台 WinFramework Workflow工作流 Workflow流程引擎 XtraReport 安装环境 版本区别 报表 备份还原 踩坑日记 操作手册 达梦数据库 代码生成器 迭代开发记录 功能介绍 国际化 基础资料窗体 架构设计 角色权限 开发sce 开发工具 开发技巧 开发教程 开发框架 开发平台 开发指南 客户案例 快速搭站系统 快速开发平台 框架升级 毛衫行业ERP 秘钥 密钥 权限设计 软件报价 软件测试报告 软件加壳 软件简介 软件开发框架 软件开发平台 软件开发文档 软件授权 软件授权注册系统 软件体系架构 软件下载 软件著作权登记证书 软著证书 三层架构 设计模式 生成代码 实用小技巧 视频下载 收钱音箱 数据锁 数据同步 微信小程序 未解决问题 文档下载 喜鹊ERP 喜鹊软件 系统对接 详细设计说明书 新功能 信创 行政区域数据库 需求分析 疑难杂症 蝇量级框架 蝇量框架 用户管理 用户开发手册 用户控件 在线支付 纸箱ERP 智能语音收款机 自定义窗体 自定义组件 自动升级程序
联系我们
联系电话:13923396219(微信同号)
电子邮箱:23404761@qq.com
站长微信二维码
微信二维码