2015-11-19 16 views
1

我有一個C DLL,其中的功能之一以下簽名返回一個字節:C#P /調用C法*

DLLExport byte* DecodeData(CDecoderApp* decoderApp, HWND handle, byte* data, int length, int* frameLength, int* waveDataLength, int* decodedFrameSize, int* channels, int* frequency) 

我需要的P/Invoke這種方法試過如下:

[DllImport("Decoder.dll", CallingConvention = CallingConvention.Cdecl)] 
public static extern byte[] DecodeData(IntPtr decoderApp, IntPtr handle, byte[] data, int length, out int frameLength, out int waveDataLength, out int decodedFrameSize, out int channels, out int frequency); 

這不工作,因爲我猜c#不知道字節數組的大小。

我應該如何解決這個問題,以便我可以得到返回的字節數組?

+5

您必須改用IntPtr,然後使用Marshal.Copy()將其放入托管數組中。要小心,存在嚴重的內存管理問題,有人將不得不釋放返回的非託管數組,而有人不能成爲你。 –

+0

@HansPassant可以請你展示一個關於如何做的代碼示例? – user1005448

+0

你只需要調用['Marshal.Copy'](https://msdn.microsoft.com/en-us/library/ms146631.aspx)。我不認爲它背後還有其他魔法。即分配一個正確大小的字節數組,調用你的外部函數,將指針傳遞給'Marshal.Copy'來獲取數據到你的字節數組中,最後調用一些其他外部函數來再次釋放該內存。 – poke

回答

1

編組器不能像你懷疑的那樣編組返回值byte[]。你需要自己進行編組。改變返回值是IntPtr類型:

[DllImport("Decoder.dll", CallingConvention = CallingConvention.Cdecl)] 
public static extern IntPtr DecodeData(
    IntPtr decoderApp, 
    IntPtr handle, 
    byte[] data, 
    int length, 
    out int frameLength, 
    out int waveDataLength, 
    out int decodedFrameSize, 
    out int channels, 
    out int frequency 
); 

這樣調用該函數:

IntPtr decodedDataPtr = DecodeData(...); 

檢查錯誤:

if (decodedDataPtr == IntPtr.Zero) 
    // handle error 

的參數大概一個,也許waveDataLength包含返回的字節數組的長度:

byte[] decodedData = new byte[waveDataLength]; 
Marshal.Copy(decodedDataPtr, decodedData, 0, waveDataLength); 

當然,現在你只剩下一個指向非託管代碼分配的內存的指針。您將需要找到一種方法來釋放該內存。也許內存分配在共享堆上。也許非託管代碼導出deallocator。但根據我們所掌握的信息,我們無法準確告訴您如何取消分配。