本文转载: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. Cesium中级教程7 - Geometry and Appearances 几何图形和外观

    Cesium中文网:http://cesiumcn.org/ | 国内快速访问:http://cesium.coinidea.com/ 本教程将向您介绍提供使用Primitive API的几何图形和外 ...

  2. 图文并茂理解iptables

    原文地址:http://www.zsythink.net/archives/1199 以下是转载内容: iptables详解:图文并茂理解iptables | 朱双印博客 这篇文章会尽量以通俗易懂的方 ...

  3. 学习Java第12天

    今天所做的工作: 敲代码,按照教材进度,我已经"学完了",用引号引起来. 明天工作安排: 开始学习前台技术,边复习Java基础. 今日总结:Eclipse基本使用方法 Ctrl+A ...

  4. rust实战系列 - 使用Iterator 迭代器实现斐波那契数列(Fibonacci )

    为什么是斐波那契数列 斐波那契数列十分适合用来实战rust的迭代器,算法也很简单,一目了然.这个例子可以用来学习Iterator的使用,十分适合刚学习了rust的迭代器章节后用来练练手. 代码实战 d ...

  5. Lesson1——NumPy NumPy 安装

    NumPy 教程目录 NumPy 安装 Python 官网上的发行版是不包含 NumPy 模块的.(pip list 测试一下) 我们可以使用以下几种方法来安装. 1 使用已有的发行版本 对于许多用户 ...

  6. new Date时间格式转换方法

    平时经常会使用到时间转换,组件库已经有很多组件可以自动生成时间类型了,但是底层的封装方法还是得有 获取当前时间 new Date()  或者自己拥有一个毫秒时间 方法如下 /** * title: 时 ...

  7. argc 和 argv

    转载请注明来源:https://www.cnblogs.com/hookjc/ 如果用C寫一般的命令列工具,常透過main函式的argc,argv來取得使用者所輸入的命令參數.int main(int ...

  8. Nginx中的 location 匹配和 rewrite 重写跳转

    Nginx中的location匹配和rewrite重写跳转 1.常用的Nginx正则表达式 2.location 3.rewrite 4.rewrite实例 1.常用的Nginx正则表达式: ^ :匹 ...

  9. JUC并发包学习

    1.什么是JUC java.util工具包.包.分类 业务:普通的线程代码 Thread Runable:没有返回值.效率相对于Callable相对较低. 2.线程和进程 进程:一个程序.如:QQ.e ...

  10. python——虚拟环境管理大合集

    个人常用:pipenv 安装 pip3 install pipenv 创建虚拟环境 # 默认安装在~/.local/virtualenv下 mkdir project cd project pipen ...