实现双接口的好处是?IDispatch接口是为了脚本里可以访问,那么实现了IDispatch接口后,为什么还要实现IUnknown接口?能举个例子么?
解决方案 »
- 注册窗口类中的hInstance不知道干什么用的
- MFC编译有误
- 在类成员函数中调用全局sdk函数前面显示加上::是不是好的程序风格啊?
- 四个角了,再散分
- 数据库已经联接上,而且txtSQL已经在SQL中运行是正确,但为何这样执行总是返回FALSE.请大侠赐教!
- 不使用AfxThrowUserException函数,throw不允许抛出CUserException 异常。
- 高分求救Web Browser控件问题!!!
- 为什么Release版本无法显示主窗体,在线等待!!!
- _rmdir函数在WIN2000下失效,返回-1,请问怎么办?
- CTabCtrl怎么隐藏掉某一个tab页面
- WSASend 函数参数的问题。
- ADO连接SQL SERVER
在vb以及一些脚本语言只能通过IDispatch调用
但在vc中两种调用方法都可以
在ATL向导中,勾选“Custom”接口的,只能继承IUnknown接口。这样的接口,允许通过虚函数表绑定直接调用COM对象,这就要求使用C++这样的强类型语言,以便在编译时就确定要调用的方法和属性。
如果COM组件使用了IDispatch接口,那么,你当然也能使虚函数表绑定。然而,使用双接口你无需在编译时确定要调用的方法和属性就能够调用COM组件的方法。例如,对于COM组件里的getItem()方法,我们可以指明调用IDispatch::Inoke(),在运行时再将getItem名称作为参数传入,这样,就可以在运行时确定要调用的函数。当然,这种机制对于C++语言来说,几乎没什么用途。但是,对于像VBScript之类的脚本语言却是至关重要的,原因是它们是根本不进行类型检测的,所有的变量都只有一种类型:VARIANT。这类语言就只能通过自动化接口IDispatch调用组件对象的函数。
所以,双接口既实现了对VTable绑定的支持,又提供了对晚绑定的支持,使各种语言的COM客户都能够访问你的组件。
在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接口调用方法
其实,双接口是为了使组件对象兼容不同客户程序而提出的。双接口就是继承于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
假设我们把“将客户程序与组件对象相关联的过程”称为“绑定”,那么绑定方式就有三种:
一、虚函数表绑定。
直接根据函数调用语句从虚函数表中查阅函数的地址而运行组件方法。这当然是“早绑定”,因为编译程序能“知道”被调函数的索引。这也是效率最高的一种绑定。Custom接口的组件支持这种绑定。
二、dispID绑定。
只有继承于IDispatch接口的组件支持这种绑定。客户程序导入组件对象的类型库,类型库则包含了组件对象的描述信息,如接口、方法、属性。对于组件方法调用源语句,编译器在编译时(而不是客户程序在运行时)通过类型库查阅dispID(它有点类似于函数在虚函数表中的索引),然后将dispID传递给Invoke方法来确定调用哪一个地址的函数代码(二进制的)。这也是在编译时期就能确定组件方法ID的一种绑定形式,也是早绑定。
三、晚绑定。
这种绑定,方法调用是在运行期和相关对象建立联系的(因为编译时,这种对象的变量类型还无法确定)。遇到组件函数调用语句,编译器首先让客户调用自动化接口的GetIdsOfNames函数,从而查到被调函数的dispID,然后将查到的dispID传递给IDispatch接口的Invoke方法,Invoke方法在运行时才“知道”被调用函数的地址。这样的访问效率是最低的。