实现双接口的好处是?IDispatch接口是为了脚本里可以访问,那么实现了IDispatch接口后,为什么还要实现IUnknown接口?能举个例子么?

解决方案 »

  1.   

    直接调用接口函数的效率高,在可能的情况下应该直接通过接口调用函数
    在vb以及一些脚本语言只能通过IDispatch调用
    但在vc中两种调用方法都可以
      

  2.   

    双接口指的是实现了IDISPATCH接口和c++的vtbl接口的接口,实现IDispatch接口正如楼上所言是为了满足多种语言的通讯用的,他提供了一种新的通讯方式,通过他组件可以向其它语言编写的客户程序提供com接口的服务。不过是以损失效率为代价的(调用invoke等函数是需要开销的)。而同时实现vtbl接口可以提供c++客户程序高效的要求。实现IUnknown接口是必须的。每个组件都需要查询接口和计数控制功能。
      

  3.   

    继承自IDispatch的接口就是双重接口。
    在ATL向导中,勾选“Custom”接口的,只能继承IUnknown接口。这样的接口,允许通过虚函数表绑定直接调用COM对象,这就要求使用C++这样的强类型语言,以便在编译时就确定要调用的方法和属性。
    如果COM组件使用了IDispatch接口,那么,你当然也能使虚函数表绑定。然而,使用双接口你无需在编译时确定要调用的方法和属性就能够调用COM组件的方法。例如,对于COM组件里的getItem()方法,我们可以指明调用IDispatch::Inoke(),在运行时再将getItem名称作为参数传入,这样,就可以在运行时确定要调用的函数。当然,这种机制对于C++语言来说,几乎没什么用途。但是,对于像VBScript之类的脚本语言却是至关重要的,原因是它们是根本不进行类型检测的,所有的变量都只有一种类型:VARIANT。这类语言就只能通过自动化接口IDispatch调用组件对象的函数。
    所以,双接口既实现了对VTable绑定的支持,又提供了对晚绑定的支持,使各种语言的COM客户都能够访问你的组件。
      

  4.   

    补充一下luohualiushui(落花流水)的观点,
    在VB中两种方式都有可能使用
    声明为Object类型的变量使用IDispatch接口,
    声明为具体的某个类的变量使用虚函数表
    例如:
    dim a as object
    set a = CreateObject("aa.bb") 'VB内部将IDispatch接口指针赋值给变量a
    a.func1(param1) '使用IDispatch提供的Invoke函数调用
    dim b as aa.bb '声明的时候使用这种类型的前提是通过添加引用方式将类型库导入到VB工程中
    set b = a '在这个赋值操作过程当中, VB内部调用QueryInterface函数得到相应额接口指针
    b.func1(param1)    '使用虚函数表调用VB能够使用虚函数完全依赖于类型库(Type Library)
    VBScript因为没有对Type Library的支持(由于VBScript是解释执行的所以向VB一样写程序的时候添加引用是不现实的), 所以只采用IDispatch接口提供的方法调用函数.在这里想要阐述的重要观点是:
    通过Type Library的支持, 可以使用虚函数表调用
    通过IDispatch的支持, 可以使用IDispatch接口调用方法
      

  5.   

    真没办法,只好大胆放言了。
        其实,双接口是为了使组件对象兼容不同客户程序而提出的。双接口就是继承于IDispatch接口的,Daul接口的虚函数表实际上包含了IUnknown接口方法、Idispatch接口的方法以及组件类所包含的方法。
        双接口允许非脚本程序员通过虚函数表绑定访问组件方法,这能够使客户端快速运行;同时,宏和脚本客户也能通过InVoke函数调用组件方法。
        例如,VB程序就可以用两种方式使用组件函数。
        方式一、声明Object类型的变量,通过Invoke方法调用组件函数。以下为示例代码:
    Dim xlSheet as object       
    Set xlSheet = New Excel.WorkSheet
        方式二、直接声明一个组件类的对象,通过虚函数表调用函数。以下为示例代码:
    Dim xlSheet as WorkSheet
    Set xlSheet = New Excel.WorkSheet
      

  6.   

    补充:    
    假设我们把“将客户程序与组件对象相关联的过程”称为“绑定”,那么绑定方式就有三种:
        一、虚函数表绑定。
        直接根据函数调用语句从虚函数表中查阅函数的地址而运行组件方法。这当然是“早绑定”,因为编译程序能“知道”被调函数的索引。这也是效率最高的一种绑定。Custom接口的组件支持这种绑定。
        二、dispID绑定。
        只有继承于IDispatch接口的组件支持这种绑定。客户程序导入组件对象的类型库,类型库则包含了组件对象的描述信息,如接口、方法、属性。对于组件方法调用源语句,编译器在编译时(而不是客户程序在运行时)通过类型库查阅dispID(它有点类似于函数在虚函数表中的索引),然后将dispID传递给Invoke方法来确定调用哪一个地址的函数代码(二进制的)。这也是在编译时期就能确定组件方法ID的一种绑定形式,也是早绑定。
        三、晚绑定。
        这种绑定,方法调用是在运行期和相关对象建立联系的(因为编译时,这种对象的变量类型还无法确定)。遇到组件函数调用语句,编译器首先让客户调用自动化接口的GetIdsOfNames函数,从而查到被调函数的dispID,然后将查到的dispID传递给IDispatch接口的Invoke方法,Invoke方法在运行时才“知道”被调用函数的地址。这样的访问效率是最低的。
      

  7.   

    呵呵~~罗嗦了大半天,还没回答楼主的另一个问题呢。自动化接口已经继承了IUnknown接口。如果一个接口实现了双接口,当然不必再去实现IUnknown接口。