2015-11-17 3 views
1

У меня есть DLL с функцией, которая возвращает символ «char **». Мне нужно передать его в MemoryStream под C#.C# Marshaling - Получить содержимое C char ** и преобразовать в байт []

Как это сделать?

Я уже пробовал

[DllImport("ctf.dll")] 
    public static extern long tts_sintetizaTexto_mm(long canal, string text, char* BuffVoice); 

Когда я пытаюсь использовать BuffVoice на MemoryStream производит ошибку компиляции ...

ТИА, Nilo - Бразилия

+2

Это не C. Удалите C тег , – Samidamaru

+0

Готово. Но я отмечен как C, потому что моя DLL написана с использованием C. –

+1

попробуйте посмотреть здесь http: // stackoverflow.com/questions/1054009/how-can-i-pass-memorystream-data-to-unmanaged-c-dll-using-p-invoke –

ответ

1

Помните, char in C на самом деле является неподписанным байтом. Это означает, что на самом деле это byte**, что само по себе может быть одной из двух вещей: либо указателем на массив (byte[]*), либо массивом массивов (byte[][]).

Указатель на массив

Этот сценарий является более вероятным.

[DllImport("ctf.dll")] 
public static extern long tts_sintetizaTexto_mm(long canal, string text, ref byte[] BuffVoice); 

Если это API Microsoft есть подавляющие шансы, что это, как это работает:

[DllImport("ctf.dll")] 
private static extern long tts_sintetizaTexto_mm(long canal, string text, ref byte[] BuffVoice); 

public byte[] SintetizaText(long canal, string text) 
{ 
    // The first call requests the size of the memory that we need to allocate. 
    byte[] buffer = null; 
    var size = tts_sintetizaTexto_mm(canal, text, ref buffer); 
    if (size <= 0) throw new Exception(); 

    // The second call actually does the work. 
    buffer = new byte[(int)size]; 
    size = tts_sintetizaTexto_mm(canal, text, ref buffer); 

    // size either holds a new size, or the result code. 
    // size: Array.Resize(ref buffer, size); 
    // result code: if (size != 0) throw new Exception(); 

    return buffer; 
} 

массив Массивы

[DllImport("ctf.dll")] 
public static extern long tts_sintetizaTexto_mm(long canal, string text, ref byte[][] BuffVoice); 
+0

То, что мне нужно. Большое спасибо! –

2

Лучший Newby статью о Interop mapping: http://www.mono-project.com/docs/advanced/pinvoke/ (пока речь идет о Mono о том же .NET, когда они совместимы). Наиболее распространенным моментом является marshall строки «in» непосредственно из System.String с атрибутом MarshallAs для точного отображения, а для строк «out» использует StringBuilder с MarshallAs и предопределенным размером.

Я сам был с некоторыми проблемами с PInvoke, что близко к вам вопрос: How to correctly send long-live buffer from C# to C++

Но ваш пример не ясно: tts_sintetizaTexto_mm (длинный канал, текстовая строка, символ * BuffVoice);

что здесь от C и что от C# - строка это System.String или std :: string, что означает char *? небезопасный указатель C# char (широкий char!) или просто C char * (подписанный!) байтовый буфер ???? - если std :: string - он несовместим с PInvoke - реализует собственную C-перегрузку с char * или wchar_t *, если это char * - помните, что это не байт [], в то время как byte [] is uchar * ... Если это C# char * - помните, что C# char имеет 16 бит, поэтому допустимый тип C будет wchar_t или ushort ... Где мы можем отправить размер буфера, чтобы предотвратить переполнение? Итак, где больше вопросов, которые вы просто попросили ...

Для моего опыте использования, хотя это не из атрибута, но более управляемым: использовать Marshall.GlobalHAlloc и IntPtr как тип (для-взаимодействия любого хххх *)

[DllImport("ctf.dll")] 
public static extern long tts_sintetizaTexto_mm(long canal, string text, IntPtr BuffVoice); //you should provide valid pointer to global memory IntPtr is compatible with any pointer type 

... 
_ptr = Marshal.AllocHGlobal(REQUIRED_BUFFER_SIZE_IN_BYTES); 
try{ 
     /* initialize it if required, for ex write ZERO char to start buffer to allow strlen and other work well */ 
    tts_sintetizaTexto_mm (/*other params*/, _ptr); //it will be valid pointer in C context 
    /* do required work with _ptr - you can work with Read method and so on */ 
}finally{ 
     Marshall.FreeHGlobal(_ptr); // we was beyond GC - remembere to clear memory 
} 

Здесь: How can I pass MemoryStream data to unmanaged C++ DLL using P/Invoke вы можете увидеть близкий образец с GCHandle, который почти такой же