2015-11-19 3 views
1

Я получил C DLL, где одна из функций имеет следующую подпись:C# P/Invoke метод C возвращает байт *

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

мне нужно п/вызвать этот метод и попытался следующее:

[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. Но с информацией, которую мы имеем, мы не можем точно сказать, как ее освободить.