C#Marshaling - 获取C char **的内容并转换为byte []

时间:2015-11-17 13:51:06

标签: c# .net marshalling

我有一个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 - 巴西

2 个答案:

答案 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);