IDispatch接口

如果是编译型语言,那么我们可以让编译器在编译的时候装载类型库,也就是装载接口的描述。在第七回文章当中,我们分别使用了 #include 方法和 #import 方法来实现的。装载了类型库后,编译器就知道应该如何编译接口函数的调用了---这叫前绑定。但是,如果想在脚本语言中使用组件,问题就大了,因为脚本语言是解释执行的,它执行的时候不会知道具体的函数地址,怎么办?自动化接口就为此诞生了---“后绑定
    自动化组件,其实就是实现了 IDispatch 接口的组件。IDispatch 接口有4个函数,解释语言的执行器就通过这仅有的4个函数来执行组件所提供的功能。IDispatch 接口用 IDL 形式说明如下:

[

    object,

    uuid(00020400-0000-0000-C000-000000000046), // IDispatch 接口的 IID = IID_IDispatch

    pointer_default(unique)

]

interface IDispatch : IUnknown

{

    typedef [unique] IDispatch * LPDISPATCH; // 转定义 IDispatch * 为 LPDISPATCH

    HRESULT GetTypeInfoCount([out] UINT * pctinfo); // 有关类型库的这两个函数,咱们以后再说

    HRESULT GetTypeInfo([in] UINT iTInfo,[in] LCID lcid,[out] ITypeInfo ** ppTInfo);

    HRESULT GetIDsOfNames( // 根据函数名字,取得函数序号(DISPID)

                [in] REFIID riid,

                [in, size_is(cNames)] LPOLESTR * rgszNames,

                [in] UINT cNames,

                [in] LCID lcid,

                [out, size_is(cNames)] DISPID * rgDispId

            );

    [local] // 本地版函数

    HRESULT Invoke( // 根据函数序号,解释执行函数功能

                [in] DISPID dispIdMember,

                [in] REFIID riid,

                [in] LCID lcid,

                [in] WORD wFlags,

                [in, out] DISPPARAMS * pDispParams,

                [out] VARIANT * pVarResult,

                [out] EXCEPINFO * pExcepInfo,

                [out] UINT * puArgErr

            );

    [call_as(Invoke)] // 远程版函数

    HRESULT RemoteInvoke(

                [in] DISPID dispIdMember,

                [in] REFIID riid,

                [in] LCID lcid,

                [in] DWORD dwFlags,

                [in] DISPPARAMS * pDispParams,

                [out] VARIANT * pVarResult,

                [out] EXCEPINFO * pExcepInfo,

                [out] UINT * pArgErr,

                [in] UINT cVarRef,

                [in, size_is(cVarRef)] UINT * rgVarRefIdx, 

                [in, out, size_is(cVarRef)] VARIANTARG * rgVarRef

            );

}

使用MFC建立COM组件实现IDispatch:(自动化要勾上)


ATL实现双接口组件:(双重的勾要勾上)

 

当然,这里设计组件的时候不需要亲自去写IDispatch接口的实现,VC已经帮我们完成了。但是在调用该组件的时候,还是需要通过IDispatch:(这里说了5种方式)

示例程序

自动化组件的使用方式

简要说明

示例0

在脚本中调用

第九回/第十回中,已经做了介绍

示例1

使用 API 方式调用

揭示IDispatch 的调用原理,但傻子才去这么使用那,会累死了

示例2

使用CComDispatchDriver 的智能指针包装类

比直接使用 API 方式要简单多啦,这个不错!

示例3

使用 MFC 装载类型库的包装方式

简单!好用!常用!但它本质上是使用IDispatch 接口,所以执行效率稍差

示例4

使用#import 方式加载类型库方式

#import 方式使用组件,咱们在第七回中讲过啦。常用!对双接口组件,直接调用自定义接口函数,不再经过IDispatch,因此执行效率最高啦

示例x

vbjavac#bcbdelphi.......

反正我不会,自己去请教高人去吧:-(