COM IDL 定义中 [in, out] 和 [out, retval] 的区别

Posted

技术标签:

【中文标题】COM IDL 定义中 [in, out] 和 [out, retval] 的区别【英文标题】:Differences between [in, out] and [out, retval] in COM IDL definitions 【发布时间】:2010-12-07 05:51:20 【问题描述】:

在我使用的一些 IDL 中,我注意到在方法中标记返回值有两种约定 - [in, out][out, retval]

看来[in, out]是在有多个返回值的时候使用的,例如:

HRESULT MyMethod(
    [in] long InputParam, 
    [in, out] long* OutputParam1, 
    [in, out] long* OutputParam2
);

看来[out, retval]是在只有一个返回值的时候使用的,例如:

HRESULT MyMethod2(
    [in] long InputParam, 
    [out, retval] long* OutputParam1
);

这是一个 COM IDL 约定还是只是我正在使用的代码中的一个约定?

这两种符号生成的代码在功能上是否存在差异,或者它们完全可以互换?

【问题讨论】:

【参考方案1】:

[in, out] 表示调用方法时传递了一个有效值,当方法返回成功时,有效值存在(指针指向的位置)。 [out] 表示方法被调用时指向的值可以是任何值,但在方法返回成功时才有效。 [out][in, out] 参数都必须是指针 - 它们的值不变且有效,并且有效性要求仅适用于它们指向的变量。

[out, retval] 是一种语法糖,表示在创建本机 COM 支持包装器时,该参数应转换为返回值。例如

HRESULT MyMethod( [out] long* OutParam1, [out, retval] long* OutParam2 );

变成

long IWrappedInterface::MyMethod( long* OutParam1 );

如果你不标记它[retval],包装器将包含一个带有原始签名的方法:

HRESULT IWrappedInterface::MyMethod( long* OutParam1, long* OutParam2 );

只有最后一个[out]参数可以标记为[out, retval][in, out]参数不能标记为[retval]

【讨论】:

感谢您的有用解释。 我想补充一点,[in,out] 可能无法被所有语言正确处理(更具体地说,老式的 Visual Basic,不确定 .NET)。 我想知道 [out, retval] 是否违反了定义 COM 接口的最佳实践,因为如果执行失败则无法获取错误代码 (HRESULT)? @dave:如果执行失败,则返回适当的 HRESULT。如果您通过“原始接口”调用该方法,则签名会返回HRESULT,您可以对其进行检查。如果您正在调用返回 HRESULT 以外的其他内容的本机 COM 支持包装器,则此包装器将在其中进行检查并调用 _com_issue_error(),这将映射到引发异常的某个函数。所以这不是问题。 详细阐述@KimGräsman 的评论:Visual Basic(“经典”?)不支持[in, out][in, out] 参数将由实现该方法的 Visual Basic 代码处理,就好像它是 [out]。这意味着在调用方法时参数指向的任何值都将被丢弃并覆盖而不进行检查,这可能会导致泄漏。有时它并不重要(例如,参数指向本地 int),有时它确实(参数指向 BSTR)【参考方案2】:

另一个区别是这将如何显示在 .NET 代码的 PIA 中。

[out, ret] 将在 .NET 中显示为返回值。

[out] 将在 .NET 中显示方法的参数。

【讨论】:

以上是关于COM IDL 定义中 [in, out] 和 [out, retval] 的区别的主要内容,如果未能解决你的问题,请参考以下文章

CORBA 和 RMI 的区别

IDL_MCTK(MODIS Conversion Toolkit)

远程过程调用和 MIDL:如何实现具有 [out] 属性的功能?

使用 ATL 的 IDL 导出在 winbase.h 中定义的结构

使用大量 IDL 接口管理 COM 类型库中的定义

如何使用 C# 中使用 ref sbyte 的方法处理 COM 引用