2011-11-07 1 views
2

J'ai une DLL non managée qui est appelée à partir de .NET avec des tampons pré-alloués pour être rempli dans la DLL non managée (selon Pass C# string to C++ and pass C++ result (string, char*.. whatever) to C#).Appel DLL non géré avec tampon fixe à partir du code managé (problème de codage)

Ma fonction non managée a le prototype suivant:

myFunc(char* a_inBuf, int a_InLen, 
     char* a_outBuf, int* a_pOutLen, 
     char* a_errBuf, int* a_pErrLen); 

Alors, je déclare la méthode dans le code managé comme ceci:

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

Avant d'appeler myFunc, je crée les deux StringBuilders:

StringBuilder outputXml = new StringBuilder(100); 
StringBuilder errorXml = new StringBuilder(100); 

Après avoir appelé myFunc, je prends le tw o StringBuilders et les écrire dans un fichier XML (un pour chaque StringBuilder) en utilisant

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

La sortie doit être écrit en UTF8 depuis l'entrée est également UTF8. Mais malheureusement, StringBuilder utilise le codage UTF16. Le contenu de outputXml et errorXml est rempli dans la DLL non managée également dans le codage UTF8. Ce comportement ne doit pas être modifié. Lors de l'écriture des fichiers, les caractères spéciaux contenus dans StringBuilders ne sont pas écrits correctement.

Comment puis-je dire à StringBuilder que le contenu est réellement NON UTF16 mais UTF8?


Edit:the answer provided by Polynomial indique à utiliser xmlwriter pour écrire le fichier. Mais en réalité, l'écriture est juste utilisée pour la sortie de débogage. En cours d'exécution normale, le contenu de outputXml et errorXml est directement utilisé dans le programme. Par conséquent, toute indication concernant l'utilisation de classes de gestion XML spéciales n'est pas utile.

Le problème réel consiste à extraire les chaînes correctes de StringBuilder (ou à les convertir pour qu'elles soient correctes).

Répondre

3

Vous ne pouvez pas convaincre le placier de PInvoke convertir UTF8.Il supposera utf-16 ou la page de code par défaut du système et convertira toujours en utf-16.

Pas de problème, faites-le vous-même. Déclarez les arguments de type byte [] à la place. Créez les tableaux avant l'appel avec la longueur appropriée, après l'appel, utilisez Encoding.UTF8.GetString() pour convertir.

+0

belle, propre et solution de travail. Merci! – eckes

2

Il ya un article absolument génial sur ce sujet qui m'a aidé à résoudre exactement ce problème. La voici: http://www.undermyhat.org/blog/2009/08/tip-force-utf8-or-other-encoding-for-xmlwriter-with-stringbuilder/

Essentiellement, vous devez utiliser xmlWriter.ForceEncoding(Encoding.UTF8) pour forcer le codage, mais il y a quelques avertissements. Donnez lecture de l'article et il devrait vous aider à comprendre ce qui se passe, pourquoi c'est UTF-16 en premier lieu et comment le contourner.

+0

merci pour la réponse. J'ai déjà lu l'article avant, mais il ne couvre pas réellement mon problème: l'écriture des fichiers xml est juste pour le débogage. En utilisation normale, le contenu de 'outputXml' et' errorXml' est directement utilisé dans l'application sans l'écrire dans un fichier ... – eckes

1

Essayez de faire quelque chose comme ça (il donne un moyen de passer outre la nature par défaut de UTF-16 .NET):

public class StringWriterWithEncoding : StringWriter 
{ 
    Encoding encoding; 

    public StringWriterWithEncoding (StringBuilder builder, Encoding encoding) :base(builder) 
    { 
     this.encoding = encoding; 
    } 

    public override Encoding Encoding 
    { 
     get { return encoding; } 
    } 

}

La logique sous-jacente est qu'il donne un moyen de passer outre L'encodage UTF-16 par défaut de .NET pour StringWriters. Ensuite, vous pouvez le cal comme ceci:

modifier

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

Comment obtenir le contenu de 'writer'? – eckes

Questions connexes