zoukankan      html  css  js  c++  java
  • 互操作

    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。

  • 相关阅读:
    Spring@Profile注解
    day 32 子进程的开启 及其用法
    day 31 udp 协议SOCK_DGRAM
    day 30 客户端获取cmd 命令的步骤
    day 29 socket 理论
    day 29 socket 初级版
    有关 组合 继承
    day 27 多态 接口 类方法 静态方法 hashlib 摘要算法模块
    新式类和经典类的区别
    day 28 hasattr getattr serattr delattr 和带__内置__ 类的内置方法
  • 原文地址:https://www.cnblogs.com/caozhengze/p/10134171.html
Copyright © 2011-2022 走看看