PInvoke可以将[out]参数转换为返回值吗?

时间:2014-06-06 08:47:06

标签: c# pinvoke

我是PInvoke的新手,我需要一些帮助。

我想使用PInvoke访问IEnumGUID,我在pinvoke.net找到了一个代码块。

 [ComImport, Guid("0002E000-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), ComVisible(false)]
 public interface IEnumGUID
 {
     int Next(int celt, [Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)]Guid[] rgelt);
     void Skip(int celt);
     void Reset();
     [return: MarshalAs(UnmanagedType.Interface)]
     IEnumGUID Clone();
 }

此处的克隆功能将IEnumGUID作为返回值,而the function in the the original C++ interface将其作为 out参数

HRESULT Clone(
  [out]  IEnumGUID **ppenum
);

我了解到PInvoke自动将HRESULT转换为COMException,但我不知道PInvoke如何将 out参数转换为返回值

请对此进行一些解释,以便我以后可以正确使用此方法。

1 个答案:

答案 0 :(得分:4)

pinvoke.net网站并不完美。它有很多错误,与任何人在代码中使用声明的可能性成反比。这个问题的概率很低,你发现的声明严重受损。

这与pinvoke没有任何关系,COM interop是.NET的一个显着特征。将参数转换为返回值的能力非常特定于COM自动化,并且高度特定于使用[out, retval]属性修饰的参数。它是[retval],它向COM客户机运行时支持库提供了一个提示,可以将该参数视为返回值。很常见,任何脚本语言都利用了这一点。任何.NET语言都是如此,除非使用[PreverseSig]属性明确禁止转换。

IEnumGUID :: Clone()的参数没有[retval]属性,因此不应声明它有一个属性。这不是唯一的错误,其他成员需要[PerserveSig]属性,因为您需要知道它们的返回值才能正确使用它们。适当的声明是:

[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("0002E000-0000-0000-C000-000000000046")]
public interface IEnumGUID
{
    [PreserveSig]
    int Next(int celt, [Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] Guid[] rgelt, out int pceltFetched);
    [PreserveSig]
    int Skip(int celt);
    [PreserveSig]
    int Reset();
    void Clone(out IEnumGUID ppenum);
}

COM IEnumXxxx接口非常常见,仅由枚举器返回的元素类型区分。其中有几个存在于.NET Framework中,例如与this one进行比较。