根据我的理解,MarshalAsAttribute(UnmanagedType.SysUInt)应该将特定于平台的无符号整数类型(32或64字节)编组到托管类型(ulong)中。
/// Return Type: size_t->unsigned int
///bgr: uint8_t*
///width: int
///height: int
///stride: int
///output: uint8_t**
[DllImportAttribute("libwebp.dll", EntryPoint = "WebPEncodeLosslessBGR")]
[return: MarshalAsAttribute(UnmanagedType.SysUInt)]
public static extern ulong WebPEncodeLosslessBGR([InAttribute()] IntPtr bgr, int width, int height, int stride, ref IntPtr output);
但它不起作用 - 我收到此错误:
Cannot marshal 'return value': Invalid managed/unmanaged type combination (Int64/UInt64 must be paired with I8 or U8).
我知道I can switch the return type to IntPtr,但对于使用我的API的人来说,这是非常不直观的。
为什么SysUInt不起作用?
答案 0 :(得分:4)
您可以将PInvoke方法与UIntPtr
保持私有,并使用您的首选签名实现另一种方法,即调用PInvoke正确映射所有内容,并且这一方法将公开:
/// Return Type: size_t->unsigned int
///bgr: uint8_t*
///width: int
///height: int
///stride: int
///output: uint8_t**
public static ulong WebPEncodeLosslessBGR([InAttribute()] IntPtr bgr, int width, int height, int stride, ref IntPtr output)
{
return (ulong)_WebPEncodeLosslessBGR(bgr, width, height, stride, ref output);
}
[DllImportAttribute("libwebp.dll", EntryPoint = "WebPEncodeLosslessBGR")]
[return: MarshalAsAttribute(UnmanagedType.SysUInt)]
private static extern UIntPtr _WebPEncodeLosslessBGR([InAttribute()] IntPtr bgr, int width, int height, int stride, ref IntPtr output);
当框架难以处理时......就是不要使用它们。编组是一种痛苦,我倾向于只使用我已经知道的东西......其他一切,我只是四处走动。
修改强>
它无效,因为封送程序不够智能,无法看到每个SysUInt
类型都适合ulong
类型。它正在检查返回,与参数相同。
确实,您不能使用ulong
和SysUInt
作为参数,但您可以返回......看到差异并不明智。 = \
有哪些替代方案?
UIntPtr
似乎是最佳选择......但还有其他选择:使用界面ICustomMarshaler
实现自定义封送程序...并使用UnmanagedType.CustomMarshaler
:
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(CustomMarshalerType))]
ICustomMarshaler实施
通过ICustomMarshaler的这种实现,您可以做到你想要的。我没有测试它,因为我没有非托管库来进行测试,但它很简单,而且非常简单......所以我认为它可以正常工作,没有任何变化。如果没有,只需发表评论,我就会对其进行修改。
public class CustomMarshalerType : ICustomMarshaler
{
public object MarshalNativeToManaged(IntPtr pNativeData)
{
return (ulong)Marshal.ReadIntPtr(pNativeData).ToInt64();
}
public IntPtr MarshalManagedToNative(object ManagedObj)
{
throw new InvalidOperationException();
}
public void CleanUpNativeData(IntPtr pNativeData)
{
}
public void CleanUpManagedData(object ManagedObj)
{
}
public int GetNativeDataSize()
{
return IntPtr.Size;
}
}