根据我的理解,元帅(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).
我知道我可以将返回类型切换到INTPTR,但这对使用我的API的人来说是非常直觉的。
为什么sysuint不起作用?
您可以将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;
}
}