IDispatch接口的作用

网上说法1:

IDispatch 接口是COM中比较常用的接口。

如果某个COM对象继承了IDispatch接口,那么这个COM对象所有的方法和属性都可以以它们的名称为参数,通过调用IDispatch接口的Invoke()方法来间接调用这些方法和属性。

在ATL中,如果想使某个COM对象支持IDispatch接口,那么必须在这个COM对象的属性中指定DUAL,即具有双重接口属性。在支持IDispatch接口的COM对象中,每个属性和方法都有一个唯一的DispID(这可以通过一个宏来获得),客户端可以以方法的名称为参数调用IDispatch接口的GetIDsOfNames()来获得这个DispID,然后以这个DispID为参数调用IDispatch接口的Invoke()函数来间接调用COM对象中方法,并获得返回结果。有意思的是,COM对象中DispID为0的方法是默认的方法,即客户调用IDispatch接口的Invoke()时如果没有给出DispID参数,则默认调用的是这个方法。

 我猜测在COM子系统内部是这样支持通过名字调用COM对象方法的:首先调用IDispatch接口的GetIDsOfNames()获得该方法的DispID,这实际上是一个查表的操作,然后调用IDispatch接口的Invoke()函数来间接调用这个方法,这同样要先通过DispID来查表获得相应的方法入口地址,然后执行这个方法,获得可能的返回结果,再将这个结果传递到客户端。

 

设计IDispatch接口的本意是为了在VB和VBScript中使用COM,因为这样的语言不支持指针,所以不能像C++那样直接通过指向对象的指针来获得COM对象方法的入口,只能通过COM子系统来调用COM对象中的方法。实际上,在VB中调用COM对象的方法时,COM子系统会自动根据VB给出的函数名,调用该COM对象IDispatch接口的Invoke()方法来间接调用该方法,并将结果返回VB。当然这个过程对程序员来将是透明的,所以给人的感觉就像是由VB调用了COM对象的方法一样。

 尽管在客户端看不出IDispatch接口的作用,可是在设计COM对象时却要考虑是否要支持IDispatch接口这个问题,如果支持则可以扩大该COM对象的使用范围,但对COM的性能会有一定的影响,如果这个COM对象规模比较大的话,通过IDispatch接口调用该对象的方法会耗费更多的时间,效率会损失10%-100%,原因是IDispatch接口通过方法名来查找它的DispID会需要较多的时间。

在ATL中同样也有一个IDispatch接口指针的封装类:CComDispatchDriver。你可以用一个IDispatch接口指针来初始化一个CComDispatchDriver对象,这个对象提供了一组方法来帮助你使用IDispatch接口指针。

网上说法2:

支持自动化。
用户只要有COM库,不需要任何说明, 便可知道该库所有对象及对象的方法属性,及方法、属性的参数、返回值 类型,及其ID。利用IDispatch,用户不需要获得COM
组件的方法实际指针。因为IDispatch::Invoke 提供了一切方法。这就是为什么叫做 dispatch(分发)接口的原因。如果没有IDispatch开发者必须提供 该COM虚类的原形。现在的大多数公用COM都被设计为支持IDispatch接口

网上说法3:

有实现IDispatch的接口组件才能够被脚本语言这种需要迟绑定使用COM组件使用,因为脚本语言和VB某种情况下是解释的方式使用组件的,称为迟绑定。而向VC这些语言使用COM组件时,对组件的调用方式是在编译期间决定的,称为早绑定。不管怎么样,反正各种开发COM组件的环境都支持直接实现Idispatch而不需要你做一点多余的工作,何乐而不为呢?

网上说法4:

Automation was built based on COM. A automation server is a COM component with IDispatch in fact, and A automation controler is a COM Client communated to automation server by IDispath. In a word, IDispatch will accept a name of function and execute it.

GetIDsOfNames & Invoke are the most interest function of IDispatch. GetIDsOfNames will read a name of function and return it's DISPID.then Automation will transfer the DISPID to Invoke. Invoke regard DISPID as the index of function ptr array and loop the function to execute it.

See the defination by IDL(Microsoft):
interface IDispatch : IUnknown
{
......

HRESULT GetIDsOfNames(
[in] const IID& riid,
[in, size_is(cNames)] LPOLESTR* rgszNames,
[in] UINT cNames,
[in] LCID lcid,
[out, size_is(cNames)] DISPID* rgDispd);

HRESULT Invoke(
[in] DISPID dispIdMember,
[in] const IID& riid,
[in] LCID lcid,
[in] WORD wFlags,
[in,out] DISPPARAMS* pDispParams,
[out] VARIANT* pVarResult,
[out] EXCEPINFO* pExcepInfo,
[out] UINT* puArgErr);
......
}

网上说法5:

我的理解是:IDispatch接口又称为分发接口,任何从该接口派生的接口,可以利用IDispatch的成员函数来实现:1、ID绑定,即假设你知道你的接口方法的绑定号(dispID),则可以直接调用从IDispatch接口继承的函数Invoke(dispID,...)来调用你的方法。注意,此时你的接口的许多方法间接通过Invoke函数来分发实现,而在你的接口中,则不用实现该函数声明及实现。
2、迟绑定,假定你连方法的dispID都不知道,此时可以通过方法名来调用方法,过程如下,实现调用从IDispatch接口继承的函数GetIDsOfName(...)来查询特定方法名对应的dispID值,接着调用Invoke函数来调用该方法即可。
与风分发接口对应的是VTable接口,即前绑定,在编译时刻就根据接口的Vtbale地址实现绑定,虽然这样效率比其他绑定方式要高,但缺乏灵活性,尤其在Vb、vbscrip以及java这样的语言环境中,由于数据类型的差异,很难调用前绑定方式实现的组件接口。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值