2010-08-08 7 views
3

Tenir compte de la struct suivante à envoyer sur TCP à un dll non géréPassage des chaînes non terminées par null au code non managé

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] 
public struct FooMessage 
{ 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 42)] 
    public string foo; 

    //More fields... 
} 

En utilisant la fonction suivante (crédit Cheeso):

public byte[] RawSerialize(T item) 
{ 
    int rawSize = Marshal.SizeOf(typeof(T)); 
    IntPtr buffer = Marshal.AllocHGlobal(rawSize); 
    Marshal.StructureToPtr(item, buffer, false); 
    byte[] rawData = new byte[ rawSize ]; 
    Marshal.Copy(buffer, rawData, 0, rawSize); 
    Marshal.FreeHGlobal(buffer); 
    return rawData; 
} 

problème : Le marshaller suppose que foo est une chaîne terminée par zéro, alors que la DLL non gérée ne le fait pas - et utilise en fait le dernier char (qui sort toujours nul du marshaller).

Des idées? Je ne peux pas simplement changer le SizeConst en 43, parce que je dois maintenir la taille totale du message, aussi bien que la position des champs suivant dans la structure (selon un ICD existant)

+0

L'utilisation d'un caractère [] est en effet le moyen de le faire. –

Répondre

2

Comme aucune autre réponse a été postée, voici le workaround que j'ai trouvé

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] 
public struct FooMessage 
{ 
    // use this for non-null-terminated strings 
    // use default encoder to convert to and from string 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst=42)] 
    public char[] foo; 

    //More fields... 
} 

également une solution similar par l'expert TCP Stephen Cleary

+0

Il me semble vraiment étrange qu'il n'y ait aucun attribut Marshalling qui puisse aider à marshaling chaînes non-terminées par zéro ... – pauloya

+0

Nous avons fini par cacher (privé) le champ char [] et définir une propriété publique sur la structure avec getter et setter cela convertit le char [] en chaîne et vice-versa. Il applique également Trim et Pad si nécessaire. – pauloya

0

Vous avez deux, et seulement deux choix:

  1. faire les dll comprendre au sujet des chaînes NUL à terminaison; ou
  2. envoyer un nombre de caractères avec le message et faire comprendre à la DLL ce compte.

L'un ou l'autre, faites votre choix.

- b

+0

La DLL est hors de mon contrôle. J'ai effectivement trouvé une solution de contournement, voir OP. Je me demandais simplement s'il y avait un meilleur moyen, bien que j'en doute. –

1

Vous pouvez utiliser StructLayout (LayoutKind.Explicit ...) et marquez chaque champ avec [FieldOffset (n)]. Cela vous permettra d'augmenter la valeur SizeConst à 43, et toujours marquez le champ suivant en commençant à offset 42. Le marshaller va marshaler la chaîne de 42 caractères et ignorer le 43ème octet en ajoutant un null-terminator à la place.

Questions connexes