IDL文件和C++头文件中的defaultvalue和retval参数排序

defaultvalue and retval parameter ordering in IDL file and C++ header file

本文关键字:文件 retval 参数 排序 defaultvalue C++ IDL      更新时间:2023-10-16

我正在尝试更新现有的COM API以包含新的可选输出参数,并且遇到了在IDL文件和关联的C++头文件中强制排序参数类型的问题。

以前我有一个像这样的IDL文件(为了保护无辜者而更改了名称):

HRESULT CreateSomething(
    [in] BSTR base_uri,
    [in] ISomethingDescription* something_description,
    [out, retval] BSTR* something_uri
);

相关的C++头看起来像:

HRESULT __stdcall CreateSomething(
    /* [in] */ BSTR study_uri,
    /* [in] */ ISomethingDescription* something_description,
    /* [out, retval] */ BSTR* something_uri
);

这需要更新以添加一个可选的输出参数,该参数可以为一些客户端提供额外的错误报告信息,遵循针对内部SDK其余部分的现有模式。

为此,我计划将IDL文件更新为如下所示:

HRESULT CreateSomething(
    [in] BSTR base_uri,
    [in] ISomethingDescription* something_description,
    [out, defaultvalue(0)] ErrorCode* error_code,
    [out, retval] BSTR* something_uri
);

其中ErrorCode是在单独的IDL文件中定义的枚举。这遵循了我在网上看到的关于如何对具有defaultvalue和retval属性的参数进行排序的指导。然而,当我试图上传C++头文件时,我遇到了默认参数不在参数列表末尾的问题,即

HRESULT __stdcall CreateSomething(
    /* [in] */ BSTR study_uri,
    /* [in] */ ISomethingDescription* something_description,
    /* [out, defaultvalue(0)] */ ErrorCode* error_code = 0,   // this is clearly wrong
    /* [out, retval] */ BSTR* something_uri
);

我在MSDN上看到的文档似乎表明,可以在同一个函数定义中使用具有defaultvalue和retval属性的参数,我也看到了一些包含此类定义的IDL文件示例,但我不知道如何编写等效的C++定义。

一些客户端(以及我们自己的测试代码)直接使用MIDL生成的头文件,因此如果我从原始C++头文件中省略默认值,则MIDL生成文件中生成的函数不包含默认值条目,即它看起来像这样:

virtual HRESULT STDMETHODCALLTYPE CreateSomething( 
            /* [in] */ BSTR base_uri,
            /* [in] */ ISomethingDescription *something_description,
            /* [defaultvalue][out] */ ErrorCode *error_code,
            /* [retval][out] */ BSTR *something_uri) = 0;

我们的SDK中类似的函数包括IDL文件和C++头中的默认值,这并不是说整个方法没有问题。

如有任何帮助/建议,我们将不胜感激。

MSDN非常清楚参数:

MIDL编译器接受以下参数顺序(从左到右):

  1. 必需参数(不具有[defaultvalue]或[optional]属性的参数)
  2. 带有或不带有[defaultvalue]属性的可选参数
  3. 具有[可选]属性但不具有[默认值]属性的参数
  4. [lcid]参数(如果有的话)
  5. [retval]参数

注意,没有提到";不是可选的默认值";参数这是因为默认值仅适用于可选参数-这是有意义的,因为非可选参数总是具有显式值,而不适用默认值。

因此,您的默认值参数必须是可选的,然后新的约束才适用:;只有当参数的类型为VARIANT或VARIANT*时,[可选]属性才有效&";,这意味着您的可选枚举参数基本无效。MIDL编译器可能会接受这一点,并将相应的标志放在类型库上,但最终这并不是它最初的工作方式:默认值只适用于变体。

然后,当您从IDL生成C++头时,您会发现可选参数只是一个标记。脚本语言等开发环境可能会检测到它,以便分别更新该COM方法的语法,但在C++方面,该参数始终存在,并且基本上是强制性的。您基本上唯一拥有的是一种特殊的约定,即调用者没有可选参数的值而没有默认值,在这种情况下,在相应的变体参数中有VT_ERRORDISP_E_PARAMNOTFOUND