我有一个C DLL,其函数返回" char **"。我需要将它传递给C#下的MemoryStream。
如何编组?
我已经尝试了
[DllImport("ctf.dll")]
public static extern long tts_sintetizaTexto_mm(long canal, string text, char* BuffVoice);
当我尝试在MemoryStream上使用BuffVoice时,会产生编译错误......
TIA, Nilo - 巴西
答案 0 :(得分:2)
关于互操作映射的最佳新文章:http://www.mono-project.com/docs/advanced/pinvoke/(虽然它是关于单声道的,但它们是兼容的同时关于.NET)。 最常见的一点是马萨诸塞州" 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(宽字符!)指针或只是C char *(signed!)字节缓冲区???? - 如果std :: string - 它与PInvoke不兼容 - 用char *或wchar_t *实现自己的C重载,如果它是char * - 记住,它不是byte []而byte []是uchar * ...如果它是C#char * - 记住C#char是16bit,那么有效的C类型将是wchar_t或ushort ...我们可以发送缓冲区大小以防止溢出?那么你刚问的问题在哪里呢?
我的到期虽然它不是来自属性,但更可控:使用Marshall.GlobalHAlloc和IntPtr作为互操作类型(对于任何xxxx *)
[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几乎相同的近似样本
答案 1 :(得分:1)
记住C中的char
实际上是一个无符号字节。这意味着它实际上是byte**
- 它本身可以是两件事之一:指向数组的指针(byte[]*
)或数组数组(byte[][]
)。
这种情况更有可能。
[DllImport("ctf.dll")]
public static extern long tts_sintetizaTexto_mm(long canal, string text, ref byte[] BuffVoice);
如果这是一个Microsoft API,那么它的工作原理绝非易事:
[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);