Вызов неуправляемой DLL с фиксированным буфером из управляемого кода (проблема с кодировкой) - PullRequest
2 голосов
/ 07 ноября 2011

У меня есть неуправляемая DLL, которая вызывается из .NET с заранее выделенными буферами для заполнения внутри неуправляемой DLL (согласно Передача строки C # в C ++ и передача результата C ++ (string, char * .. и т. Д.) на 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 я беру два StringBuilder и записываю их в файл XML (по одному для каждого StringBuilder), используя

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

Выходные данные должны быть записаны в UTF8, так как вход также UTF8. Но, к сожалению, StringBuilder использует кодировку UTF16. Содержимое outputXml и errorXml заполняется неуправляемой DLL также в кодировке UTF8. Это поведение не должно быть изменено. При записи файлов специальные символы, содержащиеся в StringBuilders, записываются неправильно.

Как мне сообщить StringBuilder, что содержимое на самом деле НЕ UTF16, но UTF8?


Редактировать: ответ, предоставленный полиномом , указывает на использование xmlWriter для записи файла. Но на самом деле, запись просто используется для отладки вывода. При обычном запуске приложения содержимое outputXml и errorXml напрямую используется в программе. Поэтому любые подсказки относительно использования специальных классов обработки XML бесполезны.

Фактическая проблема заключается в том, чтобы вывести правильные строки из StringBuilder (или преобразовать их в правильные).

Ответы [ 3 ]

3 голосов
/ 07 ноября 2011

Вы не можете убедить маршалла pinvoke конвертировать из utf8.Он будет либо принимать utf-16, либо системную кодовую страницу по умолчанию и всегда преобразовываться в utf-16.

Не проблема, просто сделайте это сами.Вместо этого объявите аргументы типа byte [].Создайте массивы перед вызовом правильной длины, после вызова используйте Encoding.UTF8.GetString () для преобразования.

2 голосов
/ 07 ноября 2011

На эту тему есть совершенно потрясающая статья, которая помогла мне решить именно эту проблему. Вот оно: http://www.undermyhat.org/blog/2009/08/tip-force-utf8-or-other-encoding-for-xmlwriter-with-stringbuilder/

По сути, вы должны использовать xmlWriter.ForceEncoding(Encoding.UTF8) для принудительного кодирования, но есть некоторые предостережения. Прочитайте статью, и она должна помочь вам понять, что происходит, почему это UTF-16, и как его обойти.

1 голос
/ 07 ноября 2011

Попробуйте сделать что-то вроде этого (это дает возможность переопределить характер по умолчанию .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; }
    }

}

Логика заключается в том, что она позволяет переопределить кодировку UTF-16 по умолчанию для .NET для StringWriters. Тогда вы можете назвать это так:

редактировать

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