什么时候需要/合适使用InAttribute和OutAttribute用于COM互操作?

本文关键字:OutAttribute 用于 COM 互操作 InAttribute 什么时候 | 更新日期: 2023-09-27 18:18:36

我正试图梳理我们分散在不同项目中的COM互操作定义的混乱,并将它们收集到一个已知的良好位置,以便整个开发团队从中受益。这项工作的一部分涉及清理多年来积累的定义。

其中一些是从其他源代码借来的,一些是从pinvoke.net逐字复制的,还有一些看起来是从SDK头文件直接翻译过来的。我注意到的一件事是,关于何时使用各种封送属性没有一致性(即使在pinvoke.net示例中,这也是相当偶然的)。部分问题是,我认为这里的任何人(包括我自己)都不完全理解什么时候需要或不需要各种属性,或者它们实际上是做什么的。到目前为止,要使这些正确似乎是猜测和随机更改的结合,直到comexception停止发生,但我更希望翻译是正确的,因为有人实际上看过它们并声明它们是正确的。

我从[In][Out]开始。我知道这两个属性在概念上的作用:它们通知编组程序数据必须去往哪个方向。例如,我假设编组程序不会麻烦地将[In]数据复制回调用方,或者知道[Out]数据可能需要在调用方释放,等等。我不知道的是:

  1. 何时必须使用这些属性?也就是说,默认的编组行为什么时候是错误的,以至于属性使其正确?
  2. 何时使用这些属性是安全的?也就是说,指定默认行为是否会改变编组程序的工作方式?
  3. 何时使用这些属性是危险的我假设显式地标记输出参数[In]是不好的,但是标记输入参数[In, Out]实际上会破坏任何东西吗?

那么,给定一个假设的COM接口方法,其IDL看起来像这样:

HRESULT Foo(
    [in] ULONG a,
    [out] ULONG * b
    [in, out] ULONG * c);

我可能会看到它被翻译成以下任何一种:

void Foo(
  uint cb,
  out uint b,
  ref uint c);
void Foo(
  uint cb,
  [Out] out uint b,
  [In, Out] ref uint c);
void Foo(
  [In] uint cb,
  [Out] out uint b,
  [In, Out] ref uint c);

这三者在功能上有什么区别吗?除了技术上的正确性之外,他们中的任何一个被认为比其他的"更好"吗?

什么时候需要/合适使用InAttribute和OutAttribute用于COM互操作?

不,在您自己的代码中并不一定要应用这些属性。它们都是可选的,并且根据参数的类型自动应用到你的代码中。

从本质上讲,它们具有以下c#关键字等效:
  • 默认为[In]
  • ref关键字得到[In, Out]
  • out关键字得到[Out]

所有的记录都在这里的一个漂亮的表中。

只有当您想要更改那些隐含的语义或更改封送处理程序的默认行为时才需要使用它们。例如,您可以将声明为ref的参数标记为[In]属性,仅用于抑制封送处理的"out"部分。

也就是说,我发现自己使用它们是因为它们是使代码自文档化的一种非常简单的方法。