我是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/