`
javatoyou
  • 浏览: 1012917 次
  • 性别: Icon_minigender_2
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

自动化(Automation)基础概念:变体(Variant)与Dispatch调用(IDispatch)

阅读更多

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

许式伟 (版权声明)
2007-3-14

在上一篇,我们解释了COM技术基础:COM组件(Component)与接口(Interface)。这里我们聊聊COM技术中的经常会遇到的两个概念:变体(Variant)和IDispatch接口。

变体(Variant)

Variant类型理论上可以存放任何类型的数据,这也是中文很多人称之为“变体”的原因。对于C++这种强类型语言的程序员来说,存在变体(Variant)这样的类型是奇怪的。但是对于哪些淡化类型概念的语言(如Visual Basic等)来说,Variant是它们默认的类型。在VB中,如果没有用As语句声明变量,那么这个变量就是Variant类型的。对于C++程序员来说,Variant不过是一个超复杂的结构体:

typedef/*[wire_marshal]*/structtagVARIANTVARIANT;

structtagVARIANT
{
union
{
struct__tagVARIANT
{
VARTYPEvt;
WORDwReserved1;
WORDwReserved2;
WORDwReserved3;
union
{
LONGLONGllVal;
LONGlVal;
BYTEbVal;
SHORTiVal;
FLOATfltVal;
DOUBLEdblVal;
VARIANT_BOOLboolVal;
_VARIANT_BOOL
bool;
SCODEscode;
CYcyVal;
DATEdate;
BSTRbstrVal;
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;
PVOIDbyref;
CHARcVal;
USHORTuiVal;
ULONGulVal;
ULONGLONGullVal;
INTintVal;
UINTuintVal;
DECIMAL
*pdecVal;
CHAR
*pcVal;
USHORT
*puiVal;
ULONG
*pulVal;
ULONGLONG
*pullVal;
INT
*pintVal;
UINT
*puintVal;
struct__tagBRECORD
{
PVOIDpvRecord;
IRecordInfo
*pRecInfo;
}__VARIANT_NAME_4;
}__VARIANT_NAME_3;
}__VARIANT_NAME_2;
DECIMALdecVal;
}__VARIANT_NAME_1;
};

Variant类型在解释型语言和脚本语言中应用甚广。在Visual Basic,JavaScript等身上,处处可见其身影。但是如果没有语言本省的支持,对Variant操作是复杂的。不幸的是,C/C++就是属于这种情况。这应该说与C++对新技术的慎重,以及是一种非纯商业公司控制的语言有关。其他语言如Delphi,一定要与时俱进,是一定要加Variant的内置支持的。

IDispatch与双接口

在我看来,Dispatch调用(IDispatch)的存在主要是脚本语言的需要。脚本语言多数属于解释型语言,其代码并不生成机器指令,而是边解释边执行(或者翻译成为中间代码后解释执行),这种语言通常有这样一个需求:就是要在不知道类(或者说组件)的详细规格情况下调用类的方法

Dispatch调用(IDispatch)就是满足这种需求的一个技术规格。它用一个dispid或者名字(字符串)表示要调用的方法(或者属性),其原理和Windows窗口的消息机制挺类似(你可以把窗口消息中的uMsg参数和这里的dispid对应起来)。IDispatch的实现者对dispid进行分派,完成具体的功能调用。有些脚本语言也许未必采用 IDispatch 作为它的调用标准,但是通常是一种和 IDispatch 类似的东西。

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

IDispatch的定义如下:

interfaceIDispatch:publicIUnknown
{
public:
virtualHRESULTSTDMETHODCALLTYPEGetTypeInfoCount(
/*[out]*/UINT__RPC_FAR*pctinfo)=0;

virtualHRESULTSTDMETHODCALLTYPEGetTypeInfo(
/*[in]*/UINTiTInfo,
/*[in]*/LCIDlcid,
/*[out]*/ITypeInfo__RPC_FAR*__RPC_FAR*ppTInfo)=0;

virtualHRESULTSTDMETHODCALLTYPEGetIDsOfNames(
/*[in]*/REFIIDriid,
/*[size_is][in]*/LPOLESTR__RPC_FAR*rgszNames,
/*[in]*/UINTcNames,
/*[in]*/LCIDlcid,
/*[size_is][out]*/DISPID__RPC_FAR*rgDispId)=0;

virtual/*[local]*/HRESULTSTDMETHODCALLTYPEInvoke(
/*[in]*/DISPIDdispIdMember,
/*[in]*/REFIIDriid,
/*[in]*/LCIDlcid,
/*[in]*/WORDwFlags,
/*[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]
interfaceIFoo:IDispatch
{
HRESULTfoo(
intarg1,intarg2);
};

这里 IFoo 是一个双接口。一个双接口一定是 IDispatch 接口,但是反之则不一定。

分享到:
评论

相关推荐

    c++ 17 ' std::variant ' for c++ 11/14/17

    MPark.VariantC++17 std::variant for C++11/14/17IntroductionMPark.Variant is an implementation of C++17 std::variant for C++11/14/17.Based on Continuously tested against libc++'s std::variant test ...

    variant:Postgres的变体数据类型,允许存储任何其他类型

    变体 变体是Postgres数据类型,它可以保存任何其他类型的数据,并记住原始类型。 例如: SELECT 'some text'::text::variant.variant; variant -------------------- (text,"some text") (1 row) SELECT 42::...

    delphi-变体类型(variant)的介绍(流与变体类型的相互转换变体类型常用的函数

    delphi-变体类型(variant)的介绍(流与变体类型的相互转换变体类型常用的函数

    VariantWorks:基于深度学习的变体调用工具包-https

    VariantWorks是一个框架,可用于开发基于深度学习的基因组读取处理任务,例如变体调用,共识调用等。它提供了通常适用于读取处理的数据编码和解析功能库,以及一种简单的插入方法进入深度学习管道。 对于深度学习...

    variant:具有“不致电我们,我们会致电给您”功能的带类型安全标记的联合

    变体 类型安全标记的联合(变体) 小而简单(250行以下C ++代码) 需要C ++ 14(decltype(auto)) 访问成员函数,lambda和函数指针使用完善的转发参数进行访问变体可以为空,也可以重新输入堆栈分配没有依赖项...

    SegeX SgxVariant:VC封装支持多维数组的变体类型(VRIANT 、SafeArray)(免费免积分)

    VRIANT变体类型是Com技术中的一种标准数据类型,Vb中的变体也是这种类型,在针对Com编程过程中,比如AutoCAD、Surfer、Excel、Word中使用自动化Automation(OLE)功能时,经常遇到VARIANT数组的情况,在VC中使用...

    MIPVAR:MIP VARiant 调用工具-开源

    用于在短时间内分析分子倒置探针测序数据的 Java 应用程序。 运行管道需要事先安装三个通用工具:BWA、GATK 和 Bedtools。 输入:要运行管道,您需要指定 3 个参数。 下面给出了该命令的示例。 这两个输入文件对于...

    git_2.14.1(ubuntu 64位)

    git_2.14.1(ubuntu 64位),windows不可以用,可以解决2.16.1及以后 “fatal: ssh variant 'simple' does not support setting port”的问题, 需要配合git-man一起用

    named_variant:使ActiveStorage的变体命名和可配置

    使ActiveStorage的变体命名和可配置。 通常的过程是 class User < ActiveRecord :: Base has_one_attached :avatar end 和视图。 = image_tag ( user . avatar . variant ( resize : "100x100" , monochrome...

    Tiny模板库:变体

    有关如何实现和使用变体的文章。 Variant可用于创建异构容器等。

    DELPHI Variant变量的使用技巧

    还有许多操作variant 变量的函数,你可以用它们进行特定的类型转换,或通过它们获取variant变量的类型信息(例如VarType 函数),当你用variant变量写表达式时,Delphi会自动调用这些类型转换和赋值函数。...

    浅析C++中boost.variant的几种访问方法

    Boost.Variant Variant库包含一个不同于union的泛型类,用于在存储和操作来自于不同类型的对象。这个库的一个特点是支持类型安全...Boost.Variant 库与 Boost.Any 有许多共同之外,但在功能上也有不同的考虑。在每天的

    SplicingVariants_Beta:拼接Variant_Beta

    什么是“剪接变体”(Splice-Altering Variant)? 在遗传变异的解释中,同义突变被认为是良性的。 同样,错义诱变就其有害性而言也处于栅栏上,而停止增益/损失,残基转移和剪接位点(GT / AG断裂)突变被认

    Variant.zip_c++变体实现_variant cpp

    C++ 变体类实现类及资料包含source code

    deepvariant:Google的DeepVariant变体调用方作为Nextflow管道

    可以同时对多个BAM文件执行变体调用,并且由于Nextflow的内部并行化,不会浪费资源。 Nextflow对Docker的支持允许通过在Docker容器内部运行每个步骤,以一种可计算的,可重复的和干净的方式生成结果。 有关Google ...

    variant-calling-pipeline:使用freebayes和bcftools对排序的bam文件进行变体调用的管道

    这是一个管道的存储库,该管道是为对的降采样数据集进行变体调用而编写的。 下采样的数据集由仅映射到20号染色体的读段组成。 管道使用两个工具调用变量,稍后将比较它们的最终输出: bcftools FreeBayes 两种...

    标准MFC WinSock ActiveX控件开发实例

    主要介绍如何开发一个ActiveX控件,提供接口,与相应事件挂钩。文中涉及到VARIANT,SAFEARRAY,BSTR的详细使用方法。 另外还提供了WinSock的详细开发步骤,以及如何响应网络超时,网络断开的事件方法以及在VC,VB...

    C++ XMind关于std::string总结

    在任何编程语言中,字符串都是重中之重。通过使用XMind总结C++ XMind中的字符串,了解并熟练掌握string对象的构造和初始化,插入删除替换,查找和比较,把所有相关的操作整合在一个页面上,提高工作效率

    网页数据提取功能 C++类

    CDownloader处理IE事件的主要方法有两个:一个是OnBeforeNavigate2(VARIANT_BOOL *pCancel, VARIANT *pVarURL, IDispatch *pDispBrowser),用于处理DISPID_BEFORENAVIGATE2事件;另一个是OnDocumentComplete(VARIANT...

Global site tag (gtag.js) - Google Analytics