我有一个非托管DLL,可以从.NET调用预先分配的缓冲区来填充非托管DLL(根据Pass C# string to C++ and pass C++ result (string, char*.. whatever) to C#)。
我的非托管函数有以下原型:
myFunc(char* a_inBuf, int a_InLen,
char* a_outBuf, int* a_pOutLen,
char* a_errBuf, int* a_pErrLen);
因此,我在托管代码中声明了这样的方法:
public static extern int myFunc(
[In, MarshalAs(UnmanagedType.LPStr)] string inputXml, int inputLen,
[MarshalAs(UnmanagedType.LPStr)] StringBuilder outputXml, ref int outputLen,
[MarshalAs(UnmanagedType.LPStr)] StringBuilder errorXml, ref int errorLen);
在调用myFunc
之前,我创建了两个StringBuilders:
StringBuilder outputXml = new StringBuilder(100);
StringBuilder errorXml = new StringBuilder(100);
在调用myFunc
之后,我使用两个StringBuilders并使用
using (StreamWriter writer = new StreamWriter("OutputXmlFile.xml", false, Encoding.UTF8))
{
writer.Write(outputXml.ToString());
writer.Close();
}
输出应以UTF8写入,因为输入也是UTF8。但不幸的是,StringBuilder使用UTF16编码。 outputXml
和errorXml
的内容也以UTF8编码填充在非托管DLL中。不应更改此行为。在编写文件时,StringBuilders中包含的特殊字符编写不正确。
如何告诉StringBuilder内容实际上是不是 UTF16但是UTF8?
编辑: the answer provided by Polynomial表示使用xmlWriter编写文件。但实际上,写入仅用于调试输出。在正常的应用程序运行中,outputXml
和errorXml
的内容直接在程序中使用。因此,有关使用特殊XML处理类的任何提示都没有用。
实际问题是从StringBuilder中获取正确的字符串(或将它们转换为正确的字符串)。
答案 0 :(得分:3)
你无法说服pinvoke marshaller从utf8转换。它将采用utf-16或系统默认代码页,并始终转换为utf-16。
不是问题,只需自己动手。声明类型为byte []的参数。调用之前使用适当的长度创建数组,调用后使用Encoding.UTF8.GetString()进行转换。
答案 1 :(得分:2)
有一篇关于这个主题的绝对精彩的文章帮助我解决了这个问题。这是:http://www.undermyhat.org/blog/2009/08/tip-force-utf8-or-other-encoding-for-xmlwriter-with-stringbuilder/
基本上,您必须使用xmlWriter.ForceEncoding(Encoding.UTF8)
强制编码,但有一些警告。给这篇文章一个阅读,它应该有助于你理解发生了什么,为什么它首先是UTF-16以及如何绕过它。
答案 2 :(得分:1)
尝试做这样的事情(它提供了一种覆盖.NET的UTF-16默认特性的方法):
public class StringWriterWithEncoding : StringWriter
{
Encoding encoding;
public StringWriterWithEncoding (StringBuilder builder, Encoding encoding) :base(builder)
{
this.encoding = encoding;
}
public override Encoding Encoding
{
get { return encoding; }
}
}
这背后的逻辑是它提供了一种方法来覆盖.NET的StringWriters的默认UTF-16编码。然后你可以像这样调用它:
修改
StringBuilder builder = new StringBuilder();
StringWriterWithEncoding stringWriter = new StringWriterWithEncoding(builder, Encoding.UTF8)
XmlWriter writer = new XmlTextWriter( stringWriter );
return stringWriter.ToString();