我是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();
 }


这里的Clone函数将IEnumGUID作为返回值,而the function in the the original C++ interface将其作为out参数。

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


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

请对此进行一些说明,以便以后可以正确使用此方法。

最佳答案

pinvoke.net网站并不完美。它有很多错误,与任何人在其代码中使用该声明的可能性成反比。这个赔率很低,您找到的声明被严重破坏了。

这与pinvoke无关,COM互操作是.NET中的一项独特功能。将参数转换为返回值的能力高度特定于COM Automation,并且高度特定于使用[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进行比较。

关于c# - PInvoke可以将[out]参数转换为返回值吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/24077710/

10-11 01:52