2012-10-19 22 views
1

根據我的理解,MarshalAsAttribute(UnmanagedType.SysUInt)應該將特定於平臺的無符號整數類型(32或64字節)編組到託管類型(ulong)中, 。如何使用語義類型來編組size_t跨平臺

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

'UIntPtr'肯定是正確的類型。你爲什麼要'ulong'? –

+0

語義,它是一個公共API。 –

+0

您可以在公共API中使用size_t –

回答

2

你可以保持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類型相符。它正在檢查回報,就像參數一樣。

確實,您不能使用ulongSysUInt作爲參數,但是您可以返回......它看起來並不明智。 = \

還有什麼替代方案?

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; 
    } 
} 
+0

每種方法都有一個或多個size_t參數...大概有200個我需要公開。這會使LOC增加三倍......我可能會更好地堅持使用UIntPtr ... –