本文转载: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. Centos7下,Docker的安装与使用

    一.Docker Install 1.卸载旧的版本 yum remove docker \ docker-client \ docker-client-latest \ docker-common \ ...

  2. C++类对象大小问题(一)

    先看如下代码: #include<iostream> using namespace std; class Base1 { public: }; class Base2 { public: ...

  3. 基于 SSR 的预渲染首屏直出方案

    基于 SSR 的预渲染首屏直出方案 Create React Doc 是一个使用 React 的 markdown 文档站点生成工具.此前在 Create React Doc 中引入了预渲染技术来预先 ...

  4. 003Linux查看文件内容的5个命令姿势

    01 开篇 Linux 中查看文件内容常用的有如下 5 个命令: cat: more: less: tail: head. 02依次看看这些命令的使用姿势 cat 一次性将所有内容输出到屏幕上,方便查 ...

  5. python采用json.dump和json.load存储数据

    #!/usr/bin/python # -*- coding: UTF-8 -*- import json numbers = [2,3,4,7,11,13] filename = 'numbers. ...

  6. django入门 03 模板语法

    变量值从views.py传入html 基本语法 {{ abc }} 变量abc外,用双大括号包裹 {% for item in abc %} 语句外,用大括号+百分号包裹 1. 传递字符串 views ...

  7. ABC209 E Shiritori

    考虑对这个问题进行转化: 显然我们只关注每个串前三个棋子和后三个棋子,并且根据题目的特性,我们可以将任意的三个字符看作点,将一个字符串看作连接两个点的边,这样我们得到了一张点数为 \(52 ^ 3\) ...

  8. JS 基本类型的包装对象

    笔记整理自:廖雪峰老师的JS教程 目录 包装对象 不写new的作用 总结 注意 包装对象 JavaScript还提供了包装对象,熟悉Java的小伙伴肯定很清楚int和Integer这种暧昧关系. nu ...

  9. docker容器编排 (4)

    容器编排 我们的项目可能会使用了多个容器,容器多了之后管理容器的工作就会变得麻烦.如果要对多个容器进行自动配置使得容器可以相互协作甚至实现复杂的调度,这就需要进行容器编排.Docker原生对容器编排的 ...

  10. node.js 使用domain模块捕获异步回调中的异常

    和其他服务器端语言相比,貌似node.js 对于异常捕捉确实非常困难. 首先你会想到try/catch ,但是在使用过程中我们会发现并没有真正将错误控制在try/catch 语句中. 为什么? 答案是 ...