MarshalAs(UnmanagedType.LPStr) – 如何将utf-8字符串转换为char *

问题标题基本上是我想问的问题:

[MarshalAs(UnmanagedType.LPStr)] – 如何将utf-8字符串转换为char *?

当我尝试在c#和c ++ dll之间进行通信时,我使用上面的行; 更具体地说,介于:

somefunction(char * string)[c ++ dll]

somefunction([MarshalAs(UnmanagedType.LPStr)字符串文本)[c#]

当我通过c#发送我的utf-8文本(scintilla.Text)并进入我的c ++ dll时,我在VS 10调试器中显示:

  1. c#字符串已成功转换为char *

  2. 生成的char *在观察窗口中正确反映了相应的utf-8字符(包括韩语中的位)。

这是一个截图(更多细节):

SS

如您所见,initialScriptText [0]返回单字节(char):’B’,并且在VS监视窗口中正确显示char * initialScriptText的内容(包括朝鲜语)。

通过char指针,似乎英语被保存为每个字符一个字节,而韩语似乎被保存为每个字符两个字节。 (截图中的韩文单词是3个字母,因此保存为6个字节)

这似乎表明每个“字母”不会保存在相同大小的容器中,但会因语言而异。 (可能提示类型?)

我试图在纯c ++中实现相同的结果:读取utf-8文件并将结果保存为char *。

这是我尝试读取utf-8文件并在c ++中转换为char *的示例:

SS2

意见:

  1. 从wchar_t *转换为char *时视觉损失
  2. 从结果开始,s8正确显示字符串,我知道我已经将wchar_t *中的utf-8文件内容成功转换为char *
  3. 因为’result’保留了我直接从文件中获取的字节,但是我得到的结果与我通过c#获得的结果不同(我使用了相同的文件),我得出的结论是c#marshal已经把文件内容通过其他一些程序进一步将文本变为char *。

(截图还显示了我使用wcstombs的可怕失败)

注意:我正在使用( http://utfcpp.sourceforge.net/ )的utf8标题

如果我的代码/观察中有任何错误,请纠正我。

我希望能够模仿我通过c#marshal获得的结果,并且在经历了所有这些之后我意识到我完全陷入困境。 有任何想法吗?

[MarshalAs(UnmanagedType.LPStr)] – 如何将utf-8字符串转换为char *?

它没有。 在托管代码中没有“utf-8字符串”这样的东西,字符串总是以utf-16编码。 使用默认系统代码页完成从LPStr到LPStr的编组。 除非您使用代码页949,否则在调试器中看到韩语字形会非常值得注意。

如果与utf-8互操作是一项硬性要求,那么你需要在pinvoke声明中使用byte []。 并使用System.Text.Encoding.UTF8自行转换。 使用其GetString()方法将byte []转换为字符串,使用其GetBytes()方法将字符串转换为byte []。 如果可能的话,通过在本机代码中使用wchar_t []来避免所有这些。

如果你需要编组UTF-8字符串,请手动完成。

使用IntPtr而不是字符串定义函数:

somefunction(IntPtr text) 

然后将文本转换为以零结尾的UTF8字节数组并将它们写入IntPtr:

 byte[] retArray = Encoding.UTF8.GetBytes(text); byte[] retArrayZ = new byte[retArray.Length + 1]; Array.Copy(retArray, retArrayZ, retArray.Length); retArrayZ[retArrayZ.Length - 1] = 0; IntPtr retPtr = AllocHGlobal(retArrayZ.Length); Marshal.Copy(retArrayZ, 0, retPtr, retArrayZ.Length); somefunction(retPtr); 

虽然其他答案是正确的,但.NET 4.7已经取得了重大进展。 现在有一个选项可以完全满足UTF-8的需求: UnmanagedType.LPUTF8Str 。 我尝试了它,它的工作方式就像一个瑞士计时器,完全听起来像它。

实际上,我甚至在一个参数中使用了MarshalAs(UnmanagedType.LPUTF8Str)在另一个参数中使用了MarshalAs(UnmanagedType.LPUTF8Str) 。 也有效。 这是我的方法(接受字符串参数并通过参数返回一个字符串):

[DllImport("mylib.dll", ExactSpelling = true, CallingConvention = CallingConvention.StdCall)] public static extern void ProcessContent([MarshalAs(UnmanagedType.LPUTF8Str)]string content, [MarshalAs(UnmanagedType.LPUTF8Str), Out]StringBuilder outputBuffer,[MarshalAs(UnmanagedType.LPStr)]string settings);

谢谢,微软! 另一个麻烦消失了。