变体(Variant)与Dispatch挪用(IDispatch)
当前位置:以往代写 > C/C++ 教程 >变体(Variant)与Dispatch挪用(IDispatch)
2019-06-13

变体(Variant)与Dispatch挪用(IDispatch)

变体(Variant)与Dispatch挪用(IDispatch)

副标题#e#

变体(Variant)

Variant范例理论上可以存放任何范例的数据,这也是中文许多 人称之为“变体”的原因。对付C++这种强范例语言的措施员来说,存在变体 (Variant)这样的范例是奇怪的。可是对付哪些淡化范例观念的语言(如Visual Basic等) 来说,Variant是它们默认的范例。在VB中,假如没有用As语句声明变量,那么这个变量就是 Variant范例的。对付C++措施员来说,Variant不外是一个超巨大的布局体:

typedef /* [wire_marshal] */ struct tagVARIANT VARIANT;
struct tagVARIANT
    {
    union
        {
        struct __tagVARIANT
            {
            VARTYPE vt;
            WORD wReserved1;
            WORD wReserved2;
            WORD wReserved3;
            union
                {
                LONGLONG llVal;
                LONG lVal;
                BYTE bVal;
                SHORT iVal;
                FLOAT fltVal;
                DOUBLE dblVal;
                VARIANT_BOOL boolVal;
                _VARIANT_BOOL bool;
                SCODE scode;
                CY cyVal;
                DATE date;
                BSTR bstrVal;
                IUnknown *punkVal;
                IDispatch *pdispVal;
                SAFEARRAY *parray;
                BYTE *pbVal;
                SHORT *piVal;
                LONG *plVal;
                LONGLONG *pllVal;
                FLOAT *pfltVal;
                DOUBLE *pdblVal;
                VARIANT_BOOL *pboolVal;
                _VARIANT_BOOL *pbool;
                SCODE *pscode;
                CY *pcyVal;
                DATE *pdate;
                BSTR *pbstrVal;
                IUnknown **ppunkVal;
                IDispatch **ppdispVal;
                SAFEARRAY **pparray;
                VARIANT *pvarVal;
                PVOID byref;
                CHAR cVal;
                USHORT uiVal;
                ULONG ulVal;
                ULONGLONG ullVal;
                INT intVal;
                UINT uintVal;
                DECIMAL *pdecVal;
                CHAR *pcVal;
                USHORT *puiVal;
                ULONG *pulVal;
                ULONGLONG *pullVal;
                INT *pintVal;
                UINT *puintVal;
                struct __tagBRECORD
                    {
                    PVOID pvRecord;
                    IRecordInfo *pRecInfo;
                    }     __VARIANT_NAME_4;
                }     __VARIANT_NAME_3;
            }     __VARIANT_NAME_2;
            DECIMAL decVal;
        }     __VARIANT_NAME_1;
    } ;

Variant范例在表明型语言和剧本语言中应用甚广。在Visual Basic,JavaScript等身上,随处可见其身影。可是假如没有语言本省的支持,对Variant操 作是巨大的。不幸的是,C/C++就是属于这种环境。这应该说与C++对新技能的慎重,以及是 一种非纯贸易公司节制的语言有关。其他语言如Delphi,必然要与时俱进,是必然要加 Variant的内置支持的。


#p#副标题#e#

IDispatch与双接口

#p#分页标题#e#

在我看来, Dispatch挪用 (IDispatch)的存在主要是剧本语言的需要。剧本语言大都属于表明型语言,其代码并不生 成呆板指令,而是边表明边执行(可能翻译成为中间代码后表明执行),这种语言凡是有这 样一个需求:就是要在不知道类(可能说组件)的具体规格环境下挪用类的要领。

Dispatch挪用(IDispatch)就是满意这种需求的一个技能规格。它用一个dispid或 者名字(字符串)暗示要挪用的要领(可能属性),其道理和Windows窗口的动静机制挺雷同 (你可以把窗口动静中的uMsg参数和这里的dispid对应起来)。IDispatch的实现者对dispid 举办分配,完成详细的成果挪用。有些剧本语言也许未必回收 IDispatch 作为它的挪用尺度 ,可是凡是是一种和 IDispatch 雷同的对象。

这种在不知道类(可能说组件)的详 细规格环境下挪用类的要领,我们称之为“晚绑定”。这是相对付C++这类编译型 语言中基于虚函数机制的挪用机制而言的,后者我们成为“早绑定”。对付虚函 数机制,它要求组件的接口是已知的,假如你不知道组件的接口,也就不知道又哪些要领可 用,更谈不上如何去挪用。

IDispatch的界说如下:

interface IDispatch : public IUnknown
    {
    public:
        virtual HRESULT STDMETHODCALLTYPE GetTypeInfoCount(
            /* [out] */ UINT __RPC_FAR *pctinfo) = 0;

        virtual HRESULT STDMETHODCALLTYPE GetTypeInfo(
            /* [in] */ UINT iTInfo,
            /* [in] */ LCID lcid,
            /* [out] */ ITypeInfo __RPC_FAR *__RPC_FAR *ppTInfo) = 0;

        virtual HRESULT STDMETHODCALLTYPE GetIDsOfNames(
            /* [in] */ REFIID riid,
            /* [size_is][in] */ LPOLESTR __RPC_FAR *rgszNames,
            /* [in] */ UINT cNames,
            /* [in] */ LCID lcid,
            /* [size_is][out] */ DISPID __RPC_FAR *rgDispId) = 0;

        virtual /* [local] */ HRESULT STDMETHODCALLTYPE Invoke(
            /* [in] */ DISPID dispIdMember,
            /* [in] */ REFIID riid,
            /* [in] */ LCID lcid,
            /* [in] */ WORD wFlags,
            /* [out][in] */ DISPPARAMS __RPC_FAR *pDispParams,
            /* [out] */ VARIANT __RPC_FAR *pVarResult,
            /* [out] */ EXCEPINFO __RPC_FAR *pExcepInfo,
            /* [out] */ UINT __RPC_FAR *puArgErr) = 0;

    };

最后一个问题是,什么是“双接口”? 一个误区是, 也许有人会把“双接口”和从IDispatch担任的接口等同起来。不外,这种领略有 点单方面了。

所谓“双接口”,是指哪些既实现了IDispatch接口,又实现 了基于虚表挪用的普通接口的非凡接口。双接口的长处在于它既适应了C++这种支持虚表 (vtbl)、追求高效的语言,也支持了剧本语言。在idl文法中,双接口以dual要害字暗示:

[dual]
interface IFoo : IDispatch
{
    HRESULT foo(int arg1, int arg2);
};

这里 IFoo 是一个双接口。一个双接口必然是 IDispatch 接口,可是反之 则不必然。

    关键字:

在线提交作业