Bonjour à tous,
langage: C#
Framework .NET: 2.0 et sup.
O.S: Windows XP et sup.
Je dispose d'une bibliothèque dynamique (DLL) programmée en C. L'appel d'une des fonctions exportées par cette DLL me retourne une structure.
Grâce à Pinvoke, je "marshal" ma structure pour qu'elle soit compréhensible en C#. Jusque là pas de problème.
Un bout de la structure C:
Code C : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9 #pragma pack(1) typedef struct tag_TRPACKET{ long Flag; long Transition; char Provider[16]; //[...] } TRPACKET; #pragma pack()
La même en C#:
Code C# : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9 [StructLayout(LayoutKind.Sequential, Pack=1, CharSet=CharSet.Ansi)] //size: 60 public struct TRPACKET{ public int Flag; public int Transition; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16, ArraySubType= UnmanagedType.LPStr)] public byte[] Provider; // size: 16 //[...] }
N.B: Notez que le membre "Provider" est de type byte[], mais le mettre en char[] ne change rien au problème...
Problématique
La fonction C me rempli le tableau de caractère "Provider" avec une chaîne ANSI (i.e. un octet par caractère). Notez que chacun des caractères retournés dans le buffer "Provider" est obligatoirement dans l'espace imprimable ( 0x20 >= caractère <= 0x7E). Le caractère final de la chaine est toujours un '\0'
Le problème est que les appels subséquent à la fonction ne nettoie pas le buffer complètement. Ça ne pose pas de problème en C, mais en C#, cela m'en pose un. Exemples:
- 1er appel à la fonction. La fonction C me retourne "ABCDE\0" dans le buffer "Provider":
- 2eme appel, la fonction me retourne "FGH\0":Provider vaut {0x41, 0x42, 0x43, 0x44, 0x45, 0x00} soit "ABCDE\0".
Comme on le voit ci-dessus, la fonction ne nettoie pas le buffer, puisque le 0x45 ('E') de l'appel précédent est encore présent.Provider vaut {0x46, 0x47, 0x48, 0x00, 0x45, 0x00, /*... */}
Lorsque j'imprime la chaine de caractère (via console.WriteLine()) la chaîne imprimée pour le deuxième cas vaut : "FGH E", ce qui n'est pas ce que j'attends.
Notez que le conversion byte[] => string est réalisée avec: ASCIIEncoding.ASCII.GetString() ou Encoding.UTF8.GetString()
J'ai essayé pas mal de chose outre les deux méthodes ci-dessus pour qu'un '\0' exprime bien une fin de chaîne pour C# mais je n'ai rien trouvé de satisfaisant.
Du coup j'ai pondu une fonction mais ça me semble être une rustine plutôt que quelque chose d'acceptable en l'état:
Code C# : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 //search for the first '\0' and truncate the buffer at this offset static string StringFromByteArray(byte[] array) { int i; bool found = false; for (i = 0; i < array.Length; i++) if (array[i] == '\0') { found = true; break; } string str = null; if(found) str = Encoding.UTF8.GetString(array, 0, i); return str; }
Existe-t-il un moyen propre de faire une conversion de ce genre, c'est à dire que C# prenne le premier '\0' dans le buffer comme le caractère terminateur de chaine ?
Merci à vous.
Partager