我正在尝试更新现有的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 ++标题中的默认值 - 并不是说整个方法都不值得怀疑。
对此有任何帮助/建议将不胜感激。
答案 0 :(得分:3)
MSDN is pretty clear about the parameters:
MIDL编译器接受以下参数排序(从左到右):
- 必需参数(没有[defaultvalue]或[optional]属性的参数),
- 带或不带[defaultvalue]属性的可选参数
- 具有[optional]属性且没有[defaultvalue]属性的参数
- [lcid]参数,如果有的话,
- [retval]参数
醇>
请注意,没有提及“not optional default value”参数。这是因为默认值仅适用于可选 - 这是有意义的,因为非可选参数始终具有显式值,没有适用的默认值。
因此,您的默认值参数必须是可选的,然后新约束适用:"The [optional] attribute is valid only if the parameter is of type VARIANT or VARIANT *.",这意味着您的可选枚举参数基本上无效。可能会发生这种情况,MIDL编译器会接受这个并将相应的标志放在类型库上,但最终这并不是预期它在第一位工作的方式:默认值仅适用于变体。
然后,当您从IDL生成C ++标头时,您会发现可选参数只是一个标记。诸如脚本语言之类的开发环境可能会检测它以分别更新此COM方法的语法,但在C ++端,参数始终存在且基本上是必需的。您基本上只有一个特殊约定,即看到调用者没有默认值的可选参数的值,在这种情况下,您在相应的变量参数中有VT_ERROR
,DISP_E_PARAMNOTFOUND
。