2011-11-07 45 views
2

我有一個非託管的DLL,從.NET調用預分配的緩衝區以滿足非託管DLL(根據Pass C# string to C++ and pass C++ result (string, char*.. whatever) to C#)。從託管代碼調用非託管DLL與固定緩衝區(編碼問題)

我的非託管函數的原型如下:

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後,我把tw ÒStringBuilders,並寫入到使用

using (StreamWriter writer = new StreamWriter("OutputXmlFile.xml", false, Encoding.UTF8)) 
{ 
    writer.Write(outputXml.ToString()); 
    writer.Close(); 
} 

輸出的XML文件(每個StringBuilder的)應被寫在UTF8由於輸入也是UTF8。但不幸的是,StringBuilder使用UTF16編碼。 outputXmlerrorXml的內容也以UTF8編碼填充到非託管DLL中。這種行爲不應該改變。寫入文件時,StringBuilders中包含的特殊字符不能正確寫入。

如何告訴StringBuilder該內容實際上是而不是 UTF16但是UTF8?


編輯:the answer provided by Polynomial指示要使用的XmlWriter寫入文件。但實際上,寫作只是用於調試輸出。在正常的應用程序運行中,程序中直接使用outputXmlerrorXml的內容。因此,關於使用特殊的XML處理類的任何提示都沒有用。

實際的問題是從StringBuilder中獲取正確的字符串(或將它們轉換爲正確的)。

回答

3

你無法說服的PInvoke編組從UTF8轉換。它將採用utf-16或系統默認代碼頁並始終轉換爲utf-16。

沒問題,只是自己動手。相反,聲明類型爲byte []的參數。在調用之前使用Encoding.UTF8.GetString()進行轉換,然後在調用之前創建數組。

+0

漂亮,乾淨和工作的解決方案。謝謝! – eckes

2

在這個主題上有一篇絕對精彩的文章,幫助我解決了這個問題。這裏是:http://www.undermyhat.org/blog/2009/08/tip-force-utf8-or-other-encoding-for-xmlwriter-with-stringbuilder/

本質上,你必須使用xmlWriter.ForceEncoding(Encoding.UTF8)強制編碼,但有一些注意事項。給文章一個閱讀,它應該有助於你理解發生了什麼,爲什麼它首先是UTF-16以及如何繞過它。

+0

感謝您的回答。我之前已經閱讀過這篇文章,但它並沒有真正涵蓋我的問題:xml文件的編寫僅用於調試。在正常的應用程序使用中,'outputXml'和'errorXml'的內容直接在應用程序中使用,無需將其寫入文件中。 – eckes

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編碼。然後,你可以CAL像這樣:

編輯

StringBuilder builder = new StringBuilder(); 
StringWriterWithEncoding stringWriter = new StringWriterWithEncoding(builder, Encoding.UTF8) 
XmlWriter writer = new XmlTextWriter(stringWriter); 
return stringWriter.ToString(); 
+0

如何獲得'writer'的內容? – eckes