我是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参数转换为返回值。
请对此进行一些解释,以便我以后可以正确使用此方法。
答案 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进行比较。