2

私の理解によると、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).

戻り値の型を IntPtr に切り替えることができることはわかっていますが、API を使用している人にとっては直感的ではありません。

SysUInt が機能しないのはなぜですか?

4

1 に答える 1

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引数にandを使用できないのは事実ですが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;
    }
}
于 2012-10-19T02:05:03.567 に答える