自动化的可变元参数及类型库

来源:互联网 发布:怎样下载itunes软件 编辑:程序博客网 时间:2024/06/09 22:37

一、关于 IDL 中 retval 的使用:

retval
描述:
指定该参数用于接收该成员的返回值

适用:
用于描述方法或者 propget 属性获取的接口成员

注释:
该特性仅被用于最后一个参数成员。该参数必须为 out 输出的,且必须为指针类型。
具有该特性的参数将不显示在用户导向的浏览器。

示例:
[
    object,
    uuid(...),
    helpstring("IX Interface"),
    pointer_default(unique),
    dual,
    oleautomation
]
interface IX : IDispatch
{
    HRESULT StringInX([in]BSTR bstrIn);
    HRESULT StringOutX([out, retval]BSTR* pbstrOut);
}

其中 StringOutX 在用户导向的浏览器中将明确被标识为返回值。

二、VARIANT 可变元类型的使用
1)VariantInit(VARIANT*)
将 VARIANT 的类型重置为 VT_EMPTY 且不清除内容。适用于初始化新申请的 VARIANT 类型值。

而后 VARIANT::vt 被指定了特定类型如 VT_BSTR,并在相应的联合类型中设置值:

VARIANT var;
::VariantInit(&var);
var.vt = VT_BSTR;
BSTR bstrSomWrd = ::SysAllocString(L"Some words");
var.bstrVal = bstrSomWrd;
...
::SysFreeString(bstrSomWrd);

2)动态类型识别
自动化的目的是避免 C++ 的强类型特征,宏语言需要获得灵活性与简单性,因此类似 Visual Basic 等语言并不具有头文件等类似类型定义形式,仅知道当获得一个对象时,可通过其调度方法获得调度接口,并传递可变元类型,由调度接口实现负责解析并决定是否进行必要的类型转换,或者在无法或者拒绝进行类型转换时返回错误信息及不正确的参数索引。

3)通过类型库可在运行时获得与语言无关的接口参数类型描述信息。

4)类型转换
当有
[propput]
HRESULT Tilte([in]BSTR bstrTitle);
方法时,可能有自动化控制器用户试图向其设置如下:

cmpnt.Title = 100;

自动化控制器可能将其解释为 long 类型,而传递指定 vt 为 VT_I4 的 VARIANT 类型。

为此,调度接口实现应当完成有关的类型转换,以增强该接口的易用性,有关的转换可能是实现各不相同的,为此,自动化提供了通用的 VariantChangeType 可变元类型转换函数。

HRESULT VariantChangeType(
VARIANTARG * pvargDest,
VARIANTARG * pvarSrc,
unsigned short wFlags,
VARTYPE vt             
);

wFlags 可指定附加规则:
VARIANT_NOVALUEPROP
阻止该转换函数尝试通过取得值属性以将对象转换到基本类型。仅当必要时设置该标识,否则将引起与其他应用程序的不一致的行为。

VARIANT_ALPHABOOL
从 VT_BOOL 类型到 "True", "False" 字符串值的转换。

VARIANT_NOUSEROVERRIDE
执行 VT_BSTR 相关转换时,设置 LOCALE_NOUSEROVERRIDE 为 LCID 以略过用户本地化设置。

VARIANT_LOCALBOOL
执行 VT_BOOL 与 VT_BSTR 之间的转换,使用当前系统的语言特定本地化信息。

示例:
VARIANT var;
::VariantInit(&var);
::VariantChangeType(&var, &varSrc, 0, VT_R8);
double r8Var = var.dblVal;

5)可选参数
VARIANT 支持 SCODE 类型,相应标识为 VT_ERROR,可为 SCODE scode 联合成员设置 DISP_E_PARAMNOTFOUND,相应的调度接口实现则作为可选参数处理,并提供缺省值。

三、BSTR 数据类型

BSTR 存储宽字符数组,但并不按照 C 字符串的格式存储,它具有以下特征:
1)开始处包含字符串长度
2)可具有多个 /0' 空字符
3)应总是通过 SysAllocString, SysFreeString 管理存储

BSTR SysAllocString(
const OLECHAR * sz
);

VOID SysFreeString(
BSTR bstr
);

四、SAFEARRAY 类型
SAFEARRAY 是具有自描述能力的安全数组。

typedef struct tagSAFEARRAY {
    USHORT cDims; // 维数
    USHORT fFeatures; // 特征
    ULONG cbElements; // 每个元素的大小
    ULONG cLocks; // 锁
    PVOID pvData; // 数据存储
    SAFEARRAYBOUND rgsabound[]; // 每个维度的边界
} SAFEARRAY;

typedef struct tagSAFEARRAYBOUND {
   unsigned long cElements; // 当前维度元素数
   long lLbound; // 下限
} SAFEARRAYBOUND;

SAFEARRAY::fFeatures 指出了该数组的元素类型及特征。可影响其释放存储的行为:

FADF 可理解为:Features or Attributes Describe Flags

FADF_AUTO 0x0001 An array that is allocated on the stack.

在堆栈中执行的分配

FADF_STATIC 0x0002 An array that is statically allocated.

静态分配

FADF_EMBEDDED 0x0004 An array that is embedded in a structure.

嵌入在结构中

FADF_FIXEDSIZE 0x0010 An array that may not be resized or reallocated.

不可重分配

FADF_RECORD 0x0020 An array containing records. When set there will be a pointer to the IRecordinfo interface at negative offset 4 in the array descriptor.

具有指向 IRecodeinfo 的指针,存储于数组描述符之前的 4 个字节

FADF_HAVEIID 0x0040 An array that has an IID identifying interface. When set there will be a guid at negative offset 16 in the safearray descriptor. Flag is set only when FADF_DISPATCH or FADF_UNKNOWN is also set.

存储接口指针,则数组描述符之前 16 个字节将被用于存储 GUID。必须同时包含 FADF_DISPATCH 或 FADF_UNKNOWN

FADF_HAVEVARTYPE 0x0080 An array that has a VT type. When set there will be a VT tag at negative offset 4 in the array descriptor that specifies the element type.

存储可变元类型,数组描述符之前 4 个字节将被用于存储 VT_type 以指出元素类型

FADF_BSTR 0x0100 An array of BSTRs.

FADF_UNKNOWN 0x0200 An array of IUnknown*.

FADF_DISPATCH 0x0400 An array of IDispatch*.

FADF_VARIANT 0x0800 An array of VARIANTs.

FADF_RESERVED 0xF0E8 Bits reserved for future use.

OLE 自动化中包含一组以 SafeArray 开头的操作 SAFEARRAY 结构的函数:

SafeArrayAccessData
SafeArrayAllocData
SafeArrayAllocDescriptor
SafeArrayAllocDescriptorEx
SafeArrayCopy
SafeArrayCopyData
SafeArrayCreate
SafeArrayCreateEx
SafeArrayCreateVector
SafeArrayCreateVectorEx
SafeArrayDestroy
SafeArrayDestroyData
SafeArrayDestroyDescriptor
SafeArrayGetDim
SafeArrayGetElement
SafeArrayGetElemsize
SafeArrayGetIID
SafeArrayGetLBound
SafeArrayGetUBound
SafeArrayGetRecordInfo
SafeArrayGetVartype
SafeArrayLock
SafeArrayPtrOfIndex
SafeArrayPutElement
SafeArrayRedim
SafeArraySetIID
SafeArraySetRecordInfo
SafeArrayUnaccessData
SafeArrayUnlock

五、类型库

类型库提供了一种语言无关的类型信息登记。将提供有关组件、接口、方法、属性、参数以及结构的类型信息。

类型库是什么:
* 类型库中的内容同 C++ 头文件中的内容是相同的。
* 是 IDL 文件的一个编译版本,且可用编程的方法来访问。
* 类型库是一个二进制文件,而不是需要被解析的文本文件。自动化库提供标准的组件以便查询类型库信息。

1)类型库的建立

自动化库函数 CreateTypeLib 帮助创建类型库,并返回支持信息写入的 ICreateTypeLib 接口。

更为常用的,使用 IDL 接口描述语言来编译类型库。

2)IDL 语言中的 library 关键字

library 声明包含了 MIDL 用于创建类型库的所有信息。

[
    uuid(12345678-1234-1234-1234-123456789ABC),
    helpstring("Hello 2.0 Type Library"),
    lcid(0x0409),
    version(2.0)
]
library Hello
{
    /* Library definition statements */
}

类型库可指定不同的 lcid 标识以对应不同本地化实现。在加载类型库时可以指定所请求的 lcid 标识。

位于 library 类型库声明块的声明可以使用在 library 块内部或者外部声明的元素。library 声明可以使用的元素包含:基本类型,从其他元素派生,或者仅仅引用外部声明,如:

interface MyFace
{
    ...
};

[
    // library attributes
]
library
{
    interface MyFace;
    ...
};

3)lcid 本地化标识

+-----------------------+-------------------------+
|     Sublanguage ID    |   Primary Language ID   |
+-----------------------+-------------------------+
15                   10 9                       0   bit

+-------------+---------+-------------------------+
|    Reserved | Sort ID |      Language ID        |
+-------------+---------+-------------------------+
31         20 19     16 15                      0   bit

上面列出了 LANGID 以及 LCID 的位编制。为 IDL 指定的本地化标识可通过 MSDN Library 中任意提供本地化语言列表的页面中查询。

4)importlib 已编译类型库导入

library BrowseHelper
{
    importlib("stdole32.tlb");
    importlib("mydisp.tlb");
    //Remainder of library definition
}

5)coclass

该声明描述了组件的 GUID 以及支持的接口。并同时帮助定义有关组件的 CLSID。最主要的是,它限定了引用/声明的接口在 library 中的分组