3

我正在为应用程序实现 COM 自动化(双接口)。自动化接口将从 VBScript 中调用。我不太清楚该方法的参数允许哪些类型。我知道基本上值必须适合 a VARIANT,但这是否意味着每个类型的参数都int必须通过 a 传递VARIANT,或者可以int直接传递?

例如,我的 MIDL 文件中有两种方法:

HRESULT SetDate([in] int Year, [in] int Month, [in] int Day);
HRESULT GetDate([out] int* pYear, [out] int* pMonth, [out] int* pDay);

SetDate从 VBScript调用有效。如图所示调用GetDate失败,也就是说,在 C++ 中的实现中,ITypeInfo::Invoke返回一个指示类型错误的代码。

我观察到,如果我使用 aVARIANT而不是 a int,如下所示,它可以工作。

HRESULT GetDate([out] VARIANT* pYear, [out] VARIANT* pMonth, [out] VARIANT* pDay);

所以int不允许参数(因为双接口),还是我做错了什么?如果int不允许,为什么会起作用 - 在这方面参数和参数SetDate之间是否存在差异?inout

此外,这对方法有效,尽管两者都使用int

[propget] HRESULT System([out, retval] int* pSystem);
[propput] HRESULT System([in] int System);

怎么会 - 允许的参数类型的规则是否与属性不同,或者参数何时声明为retval

我无法完全理解这一切 - 如果有人能澄清这一点,我将不胜感激。

4

3 回答 3

2

显然,当你通过 调用接口时IDispatch,所有的参数总是以VARIANTs 的形式传递。然而,您的实现可能会使用其他类型。鸿沟如何弥合?

ATL(假设这是您正在使用的)将为Invoke您实现,代码将参数从VARIANTs 转换为您的方法签名使用的正确类型,然后再将调用转发到实际方法。

以下是规则:

  • [in]VARIANT正如您所发现的,参数几乎可以是任何适合 a 的类型。ATL(或您正在使用的任何库)将为您处理转换参数。

  • [in, out]参数必须是VARIANT*. 如果您使用其他任何东西,则调用将不起作用或返回值将丢失(我不记得它是哪条路;您表示您在这种情况下遇到了运行时错误)。在您的方法返回时,ATL 会将参数转换为适当的参数,VARIANT以便 VBScript(或IDispatch进行调用的任何客户端)可以获取输出值。

  • [retval, out]是特例。您可以使用指向您选择的任何类型的指针,ATL 会处理它。我认为使这成为可能的原因是返回值是在DISPPARAMS机制之外提供的。

  • [out]......只是不要。它们不起作用 - VBScript 无法[out]正确使用参数。请注意,它们将“工作”,因为该方法将在没有错误的情况下执行,但 VBScript 无法区分[out]and [in, out],这意味着 VBScript 期望您的方法在您收到参数时释放参数上的任何值。如果您使用[out],则在进行方法调用之前放置在参数上的任何客户端代码都将永久泄漏。

于 2013-05-12T22:43:07.340 回答
2

VT_xxx在 Windows SDK的枚举顶部列出了您将遇到的麻烦较少的类型:

enum VARENUM
    {   VT_EMPTY    = 0,
    VT_NULL = 1,
    VT_I2   = 2,
    VT_I4   = 3,
    VT_R4   = 4,
    VT_R8   = 5,
    VT_CY   = 6,
    VT_DATE = 7,
    VT_BSTR = 8,
    VT_DISPATCH = 9,
    VT_ERROR    = 10,
    VT_BOOL = 11,
    VT_VARIANT  = 12,
    VT_UNKNOWN  = 13,
    VT_DECIMAL  = 14,
    VT_I1   = 16,
    VT_UI1  = 17,

你没有看到INT那里,是吗?LONG相反(即VT_I4)会很好地工作并且在任何地方都得到很好的支持。

对于脚本环境,您最好使用VARIANTs ,如果这使您在 C++ 方面的生活更轻松 - 使用上面提到的简单类型。如果你需要一个数组,VARIANT它也是一个很好的持有者。

一个不错的表格还暗示了类型的兼容性:

/*
 * VARENUM usage key,
 *
 * * [V] - may appear in a VARIANT
 * * [T] - may appear in a TYPEDESC
 * * [P] - may appear in an OLE property set
 * * [S] - may appear in a Safe Array
 *
 *
 *  VT_EMPTY            [V]   [P]     nothing
 *  VT_NULL             [V]   [P]     SQL style Null
 *  VT_I2               [V][T][P][S]  2 byte signed int
 *  VT_I4               [V][T][P][S]  4 byte signed int
 *  VT_R4               [V][T][P][S]  4 byte real
 *  VT_R8               [V][T][P][S]  8 byte real
 *  VT_CY               [V][T][P][S]  currency
 *  VT_DATE             [V][T][P][S]  date
 *  VT_BSTR             [V][T][P][S]  OLE Automation string
 *  VT_DISPATCH         [V][T]   [S]  IDispatch *
 *  VT_ERROR            [V][T][P][S]  SCODE
 *  VT_BOOL             [V][T][P][S]  True=-1, False=0
 *  VT_VARIANT          [V][T][P][S]  VARIANT *
 *  VT_UNKNOWN          [V][T]   [S]  IUnknown *
 *  VT_DECIMAL          [V][T]   [S]  16 byte fixed point
 *  VT_RECORD           [V]   [P][S]  user defined type
 *  VT_I1               [V][T][P][s]  signed char
 *  VT_UI1              [V][T][P][S]  unsigned char
 *  VT_UI2              [V][T][P][S]  unsigned short
 *  VT_UI4              [V][T][P][S]  unsigned long
 *  VT_I8                  [T][P]     signed 64-bit int
 *  VT_UI8                 [T][P]     unsigned 64-bit int
 *  VT_INT              [V][T][P][S]  signed machine int
 *  VT_UINT             [V][T]   [S]  unsigned machine int
 *  VT_INT_PTR             [T]        signed machine register size width
 *  VT_UINT_PTR            [T]        unsigned machine register size width
 *  VT_VOID                [T]        C style void
 *  VT_HRESULT             [T]        Standard return type
 *  VT_PTR                 [T]        pointer type
 *  VT_SAFEARRAY           [T]        (use VT_ARRAY in VARIANT)
 *  VT_CARRAY              [T]        C style array
 *  VT_USERDEFINED         [T]        user defined type
 *  VT_LPSTR               [T][P]     null terminated string
 *  VT_LPWSTR              [T][P]     wide null terminated string
 *  VT_FILETIME               [P]     FILETIME
 *  VT_BLOB                   [P]     Length prefixed bytes
 *  VT_STREAM                 [P]     Name of the stream follows
 *  VT_STORAGE                [P]     Name of the storage follows
 *  VT_STREAMED_OBJECT        [P]     Stream contains an object
 *  VT_STORED_OBJECT          [P]     Storage contains an object
 *  VT_VERSIONED_STREAM       [P]     Stream with a GUID version
 *  VT_BLOB_OBJECT            [P]     Blob contains an object 
 *  VT_CF                     [P]     Clipboard format
 *  VT_CLSID                  [P]     A Class ID
 *  VT_VECTOR                 [P]     simple counted array
 *  VT_ARRAY            [V]           SAFEARRAY*
 *  VT_BYREF            [V]           void* for local use
 *  VT_BSTR_BLOB                      Reserved for system use
 */
于 2013-05-13T09:37:44.823 回答
1

您的问题涉及两种不同的技术:

  • COM 自动化,围绕IDispatch接口和朋友发展(尤其是不需要特定编组代码的受限类型系统,因为 OLEAUT 在获得 TLB 时会自动完成这项工作)
  • VBScript,它是一种特定的 COM 自动化客户端。

不是 VARIANT 的 out 或 in/out 参数通常适用于 COM 自动化,但不适用于 VBScript,因为 VBScript 基本上只知道 VARIANT。

你会在这里找到关于 Eric Lippert 的 blob 的最终解释:In, Out, In-Out, Make Up Your Mind Already

于 2013-05-13T08:35:47.813 回答