• 互操作


    1.1、元数据
    在COM中,组件的所有信息都存储在类型库内。例如,类型库包含接口的名称和ID、方法及其参数等信息。而在.net中,这些信息都可以在程序集自身中找到。COM的问题在于类型库很难扩展。c++使用IDL文件描述接口和方法。但是一些IDL修饰符在类库中是找不到的,因为Visual Basic(类型库有Visual Basic团队负责)不能使用这些IDL修饰符。在.net中则不存在这个问题,因为.net元数据可以通过自定义特性扩展。
    由于存在上述行为,一些COM组件有类型库,一些COM组件没有。没有类型库使用时,可以使用一个描述了接口和方法的c++头文件。在.net中使用有类型库的COM组件比较容易,但也可以使用没有类型库的COM组件,只不过此时必须使用C#代码重新定义COM接口。
    1.2、释放内存
    在.net中,通过垃圾回收器来释放内存,这与依赖引用计数的COM完全不同。每个COM对象都必须实现IUnkown接口,它提供了3个方法,其中两个与引用计数有关:AddRef和Release。客户端在需要一个接口指针时,必须调用AddRef方法,它会增加引用计数,调用Release方法会减小引用计数,如果得到的引用计数为0,对象就销毁自身以释放内存。
    1.3、接口
    接口是COM的核心,他们把客户端与对象之间的契约和这种契约的具体实现区分开。接口(契约)定义了组件提供的方法和客户端可以使用的方法。在.net中,接口也扮演着一个重要的角色。COM中有三种不同类型的角色:自定义(custom)接口、调度(dispatch)接口和双重(dual)接口。
    1.3.1、自定义接口
    自定义接口派生自IUnknown接口。它在一个虚拟表(vtable)中定义了各个方法的顺序,使客户端能够直接访问接口的方法。因为把vtable绑定到方法的操作是使用内存地址实现的,所以这也意味着客户端在开发时需要知道vtable。因此,脚本客户端不能使用自定义接口。
    1.3.2、调度接口
    因为脚本客户端不支持自定义接口,所以还需要一种不同的接口类型。客户端能够使用的接口总是调度接口IDispatch,IDispatch接口派生自IUknown接口,除了IUknown方法以外,还提供了4个方法,其中最重要的方法是GetIDsOfNames和Invoke。当客户端调用组件中的某个方法时,会首先调用GetIDsOfNames方法,并传入想要调用的方法的名称。GetIDsOfNames方法会在名称-ID映射表中查找并返回其调度ID。客户端使用这个ID来调用Invoke方法。
    1.3.3、双重接口
    一方面,调度接口比自定义接口慢很多,但另一方面,脚本客户端是不能使用自定义接口的。使用双重接口能够解决这个两难的问题。
    1.3.4、强制转换和QueryInterface
    如果.net类实现了多个接口,可以将其强制转换为其中的某个接口。在COM中,IUknown接口通过QueryInterface方法实现了类似的机制。
    1.4方法绑定
    术语早起绑定和后期绑定定义了客户端映射到方法的方式。后期绑定是指在运行期间才查找要调用的方法。.net使用System.Reflection名称空间来实现后期绑定,COM则使用前面讨论过得IDspatch接口来实现后期绑定。后期绑定只对调度接口和双重接口有效。在COM中,有两个不同的选项可以实现早期绑定。早期绑定的一种方式是直接使用vtable,所以也叫做vtable绑定,这种方式只能用于自定义接口和双重接口。早期绑定的另一种方式叫做ID绑定。使用这种方法时,调度ID存储在客户端代码内,所以运行期间只需要调用一次Invoke。GetIdsOfNames是在设计期间调用的。对于这类客户端,一定要记住不能改变调度ID.
    1.5数据类型
    对于双重接口和调度接口,在COM中能使用的数据类型仅限于一组自动兼容的数据类型。IDispatch接口的Invoke方法接受VARIANT类型的一个数组作为参数。VARIANT是许多不同数据类型的联合,例如:BYTE、SHORT、LONG、DOUBLE、BSTR、IUknown、IDispatch等。在visual basic 中使用VARIANT很容易,但是在C++中使用它们就很复杂了。.net用Object类代替了VARIANT数据类型。对于自定义接口,在c++中能够使用的所有数据类型,在COM中也都能够使用。但是,这对使用此组件的客户端的编程语言会有所限制。
    1.6 注册
    .net区分私有和共享程序集。而在COM中,通过注册表配置,所有组件都是全局可用的。所有的COM对象都有一个128位唯一标识符,叫做类ID(CLSID)。用于创建COM对象的COMAPI调用是CoCreateInstance,它会在注册表中查找CLSID和DLL或EXE的路径,以加载DLL或启动EXE,以及初始化组件。因为这种包含128个位的数字很难记住,所以许多COM对象还有一个ProgID。ProgID是一个很容易记住的名称。COM对象不只有CLSID,对于每个接口和类型库,也都有一个唯一标识符,分别叫做IID和typelib ID。
    1.7线程
    COM使用单元模型来为程序员处理线程问题。但是,这也增加了一些复杂程度。操作系统的不同版本增加了不同的单元类型。
    1.7.1、单线程单元
    单线程单元(STA)是在Windows NT 3.51中引入的。在STA中只有一个线程能够访问组件,但是,一个进程中可以有多个STA。在STA中,不需要考虑如何防止实例变量被多线程访问,因为COM设施提供了这种保护,保证只能有一个线程访问组件。在编写时明确不考虑线程安全性的COM对象会在注册表中将注册表项ThreadingModel设为Apartment,表示需要使用STA.
    1.7.2、多线程单元
    Windows NT4.0引入了多线程单元(MTA)的概念。在MTA中,多个线程可以同时访问组件。在编写时明确不考虑线程安全性的COM对象会在注册表中将注册表项ThreadingModel设为Free,表示需要使用MTA,对于不明确是否考虑单元类型的线程安全的COM对象,将注册表项ThreadingModel设为Both。

  • 相关阅读:
    面试题6:用两个栈实现队列
    cygrunsrv: Error starting a service: QueryServiceStatus: Win32 error 1062: 解决办法
    支付系统的对账处理与设计--转
    centos 6.7下安装rabbitmq 3.6.6过程
    Can't access RabbitMQ web management interface after fresh install
    Spring Cloud Netflix Eureka client源码分析
    spring cloud config配置中心源码分析之注解@EnableConfigServer
    量化派基于Hadoop、Spark、Storm的大数据风控架构--转
    Inversion of Control Containers and the Dependency Injection pattern--Martin Fowler
    spark groupByKey 也是可以filter的
  • 原文地址:https://www.cnblogs.com/caozhengze/p/10134171.html
Copyright © 2020-2023  润新知