本文转载:https://www.cnblogs.com/larissa-0464/p/11095203.html

写在前面:我没有开发过COM组件的经验,只是在做文献综述的时候需要了解这方面的知识,所以如果哪里说错了或者是我理解错了,还希望大家可以指出,谢谢。我不是程序员也不是计算机专业,只是课题偏了这个方向,因此很多基础概念或许有理解错,真心希望可以得到大家的指正,再次感谢。


COM object以接口的方式向客户端提供服务。一个COM component可以包含多个COM object,一个COM object可以有多个接口,其关系如图1所示。

图1 COM组件、COM对象和接口关系

在Windows OS上,COM组件以.dll或者.exe的文件形式存在。其中.dll是进程内组件(in-process component),.exe是进程外组件(out-process component)。进程内组件意味着该组件会被加载到客户端所在的进程中,而进程外组件则意味着该组件会被加载到一个新的进程中。

二进制接口是COM组件中的重要概念,正是因为存在binary interface compatibility, 组件的开发语言不受限制,不一定非得是C/C++。接口是用Microsoft Interface Definition Language (MIDL)描述的。每个接口有唯一标识,使用IID(interface identifier)命名。接口都需要继承自IUnknown接口,该接口提供了对接口的生存期控制和接口查询。下面是一个用MIDL描述的接口的例子:

interface IWithdraw : IUnknown
{
HRESULT Withdraw([in] Bank bank, [in] Integer amount, [out, retval] int* balance);
};

每个COM object也有一个唯一标识,用CLSID表示。客户端通过COM库和类厂成功创建了对象的实例后,会得到一个指向COM object某个接口的指针(pointer),该指针实际上又指向了另一个指针(interface pointer),第二个指针指向一组函数,称为接口函数表或虚函数表(virtual table pointer),如图2所示。

图2 接口结构

COM component使用前需要先注册。组件程序把它所实现的COM object的信息以及接口信息都保存在注册表中,然后COM库通过系统注册表所提供的信息进行组件的创建工作。

在组件的创建工作中,还需要用到类厂(class factory)。类厂本身也是一个COM object,它支持一个特殊的接口IClassFactory,其定义如下:

class IClassFactory : public IUnknown
{
virtual HRESULT_stdcall CreateInstance(IUnknown *pUnknownOuter, const IID&iid, void**ppv) = 0;
virtual HRESULT_stdcall LockServer(BOOL bLock) = 0;
};

其中,CreateInstance用于创建对应的COM对象。那么,客户端创建COM对象的过程就应该是:

  • 客户端调用COM库中CoCreateInstance函数或者CoGetClassObject函数
  • COM库从注册表中找到相应的DLL程序并载入到进程中
  • 调用组件程序中DllGetClassObject函数,创建类厂,并把类厂接口指针返回给CoGetClassObject函数或者CoCreateInstance函数
  • 然后创建类厂对象,进而类厂创建COM对象,类厂把COM对象返回给CoGetClassObject函数或者CoCreateInstance函数,最后客户端可以直接调用COM对象。

COM组件支持两种方式的重用,分别是包容(containment/delegation)和聚合(aggregation),如图3所示。

 a) containment  b) aggregation

图3 COM组件的两种重用方法

Containment。对象A包含在对象B中,客户端想要调用对象A中的方法时,需要通过对象B来调用。

Aggregation。对象A的接口暴露在对象B的外面。当客户端想要调用对象A中的方法时,直接调用。但是客户端并不知道对象A的存在。


.NET中使用的是程序集(assembly)这个概念。使用C#编写的程序编译后成为程序集(.dll或者.exe格式的文件)。程序集的组成如图4所示。

 图4 程序集的组成

其中,程序集列表是必须有的(assembly manifest)。程序集列表包括该程序集元数据,例如与指定程序集版本要求、安全标识所需的所有元数据,以及定义程序集范围和解析对资源和类的引用所需的所有元数据。

程序集列表中的内容包括:

assembly name、version number、culture、strong name information (这四项组成了程序集的标识)、list of all files in the assembly、type reference information、information on referenced assemblies

https://docs.microsoft.com/en-us/dotnet/framework/app-domains/assembly-manifest

程序集中无需使用IDL文件来定义组件接口的信息,取而代之的是元数据(metadata)。元数据包括程序集的一切基本信息,比如版本、类型、命名空间、依赖的其他程序集信息等。一个.dll文件中的元数据信息可以通过reflection获取(包括命名空间、类、属性、方法等)。编译器会自动地把程序中的这些相关信息封装在程序集的元数据中。因此,可以说程序集是一种自描述的组件。元数据的使用也使得程序集无需像COM组件,在使用前需要注册。详情可见:

https://docs.microsoft.com/en-us/dotnet/standard/metadata-and-self-describing-components

MSIL code是指程序集会首先被编译成一种微软中间语言(Microsoft Intermediate Language),程序无论是用C#写还是VB写,编译成IL都是等效的。.NET平台是建立在CLR(Common Language Runtime)基础上的,也就是说用C#写的程序要经历过两次译码才能在机器上运行,这与C++是不一样的。第一次译码是转换成IL,第二次才是转换成与操作系统相匹配的二进制指令。第二次是CLR负责的。这样运行在CLR基础上的被称为托管代码,而COM组件则是用非托管代码实现的。

resources就是指程序集包含的一些可用资源,这些资源在程序集运行时是可以使用的,包括字符串、图片以及特殊文件等。

因此,.NET组件(assembly)与COM组件相比具有自描述、自包含的特点。其在使用时无需注册,在创建时也无需使用COM库和类工厂,接口定义和实现也不是分开的。

COM组件的二进制兼容性是通过使用接口指针和虚函数表实现的,而.NET组件的二进制兼容性是通过使用元数据实现的。

.NET组件 vs. COM组件的更多相关文章

  1. 谈谈我对前端组件化中“组件”的理解,顺带写个Vue与React的demo

    前言 前端已经过了单兵作战的时代了,现在一个稍微复杂一点的项目都需要几个人协同开发,一个战略级别的APP的话分工会更细,比如携程: 携程app = 机票频道 + 酒店频道 + 旅游频道 + ..... ...

  2. BenUtils组件和DbUtils组件

    BenUtils组件和DbUtils组件 [TOC] 1.BenUtils组件 1.1.简介 程序中对javabean的操作很频繁,所有Apache提供了一套开源api,方便javabean的操作!即 ...

  3. JS组件系列——Bootstrap组件福利篇:几款好用的组件推荐(二)

    前言:上篇 JS组件系列——Bootstrap组件福利篇:几款好用的组件推荐 分享了几个项目中比较常用的组件,引起了许多园友的关注.这篇还是继续,因为博主觉得还有几个非常简单.实用的组件,实在不愿自己 ...

  4. JS组件系列——表格组件神器:bootstrap table

    前言:之前一直在忙着各种什么效果,殊不知最基础的Bootstrap Table用法都没有涉及,罪过,罪过.今天补起来吧.上午博主由零开始自己从头到尾使用了一遍Bootstrap Table ,遇到不少 ...

  5. JS组件系列——表格组件神器:bootstrap table(二:父子表和行列调序)

    前言:上篇 JS组件系列——表格组件神器:bootstrap table 简单介绍了下Bootstrap Table的基础用法,没想到讨论还挺热烈的.有园友在评论中提到了父子表的用法,今天就结合Boo ...

  6. JS组件系列——表格组件神器:bootstrap table(三:终结篇,最后的干货福利)

    前言:前面介绍了两篇关于bootstrap table的基础用法,这章我们继续来看看它比较常用的一些功能,来个终结篇吧,毛爷爷告诉我们做事要有始有终~~bootstrap table这东西要想所有功能 ...

  7. WPF中实例化Com组件,调用组件的方法时报System.Windows.Forms.AxHost+InvalidActiveXStateException的异常

    WPF中实例化Com组件,调用组件的方法时报System.Windows.Forms.AxHost+InvalidActiveXStateException的异常 在wpf中封装Com组件时,调用组件 ...

  8. react native 之子组件和父组件之间的通信

    react native开发中,为了封装性经常需要自定义组件,这样就会出现父组件和子组件,那么怎么在父组件和子组件之间相互通信呢,也就是怎么在各自界面push和pop.传值. 父组件传递给子组件: 父 ...

  9. vuejs动态组件给子组件传递数据

    vuejs动态组件给子组件传递数据 通过子组件定义时候的props可以支持父组件给子组件传递数据,这些定义的props在子组件的标签中使用绑定属性即可,但是如果使用的是<component> ...

  10. [js开源组件开发]query组件,获取url参数和form表单json格式

    query组件,获取url参数和form表单json格式 距离上次的组件[js开源组件开发]ajax分页组件一转眼过去了近二十天,或许我一周一组件的承诺有了质疑声,但其实我一直在做,只是没人看到……, ...

随机推荐

  1. WebGPU 中消失的 VAO

    1 VAO 是 OpenGL 技术中提出来的 参考: 外链 其中有一段文字记录了 VAO 是什么: A Vertex Array Object (VAO) is an object which con ...

  2. iOS14新功能一览

    这是转载的6月份的一篇文章,但是和今天发布的 ios14 正式版基本一致,可以大概参考一下. 23 号凌晨的 WWDC ,小狐也是恪尽职守啊!从开场到收尾,小狐一点也没落下,整场大会围绕着 Apple ...

  3. Ldap主从复制搭建

    LDAP是轻量目录访问协议(Lightweight Directory Access Protocol)的缩写, LDAP协议的特点 读取速度远高于写入速度. 对查询做了优化,读取速度优于普通关系数据 ...

  4. python07day

    回顾 id == is: ==: 数值是否相同 is: 内存地址是否相同 id: 获取对象的内存地址 代码块: 一个文件.交互式命令一行都是一个代码块 同一代码块下缓存机制(字符串驻留机制) 所有数字 ...

  5. plsql 带参数的游标

    -- 带参数的游标 -- cursor c(no emp.deptno%type) is select * from emp where deptno=no; 参数的起名 不要和表中的列名相同! -- ...

  6. [论文笔记][半监督语义分割]Universal Semi-Supervised Semantic Segmentation

    论文原文原文地址 Motivations 传统的训练方式需要针对不同 domain 的数据分别设计模型,十分繁琐(deploy costs) 语义分割数据集标注十分昂贵,费时费力 Contributi ...

  7. Android下数据库操作——增删改查

    Android下数据库第一种方式增删改查     1.创建一个帮助类的对象,调用getReadableDatabase方法,返回一个SqliteDatebase对象     2.使用SqliteDat ...

  8. linux_18

    简述keepalived工作原理 编译安装haproxy 总结haproxy各调度算法的实现方式及其应用场景 使用haproxy的ACL实现基于文件后缀名的动静分离

  9. Spark算子 - reduce

    释义 reduce将partition内所有记录最终计算成1个记录,结果类型与reduce 时数据类型一致 方法签名如下: def reduce(f: (T, T) => T): T = wit ...

  10. day1 -- Python变量、注释、格式化输出字符串、input、if、while、for

    1.python变量 不需要声明类型,直接 变量名 = 变量值,如 : name = "hahaha" 2.注释: 单行注释,前面加 #,如  # print(info) 多行注释 ...