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

rou*_*ude 5 c++ com idl

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

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

HRESULT CreateSomething(
    [in] BSTR base_uri,
    [in] ISomethingDescription* something_description,
    [out, retval] BSTR* something_uri
);
Run Code Online (Sandbox Code Playgroud)

和相关的C++标题看起来像:

HRESULT __stdcall CreateSomething(
    /* [in] */ BSTR study_uri,
    /* [in] */ ISomethingDescription* something_description,
    /* [out, retval] */ BSTR* something_uri
);
Run Code Online (Sandbox Code Playgroud)

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

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

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

其中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
);
Run Code Online (Sandbox Code Playgroud)

我在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;
Run Code Online (Sandbox Code Playgroud)

我们SDK中的类似函数包括IDL文件和C++标题中的默认值 - 并不是说​​整个方法都不值得怀疑.

任何有关此的帮助/建议将不胜感激.

Rom*_* R. 3

MSDN 对参数说得很清楚

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

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

请注意,没有提及“非可选默认值”参数。这是因为默认值仅适用于可选 - 这是有道理的,因为不可选的参数始终具有显式值,没有适用的默认值。

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

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