2009-09-09 3 views
1

J'essaye de désérialiser une structure, et je reçois une exception AV dans PtrToStructure. La seule ride est que c'est une structure de longueur variable, donc j'ai besoin d'ajuster la longueur avant de désérialiser. Voici mon code, y a-t-il quelque chose qui cloche? La structure ne contient que des tableaux entiers/courts/octets, rien d'extraordinaire.Violation d'accès dans Marshal.PtrToStructure

les données entrantes sont 374 octets, et j'ai besoin de l'ajuster pour correspondre à la structure de données de 576 octets. Fondamentalement, le paquet entrant a un dernier champ plus court que le maximum possible, ce qui est normal.

public static ... FromByteArray(byte[] receivedData) 
    { 
     int rawsize = Marshal.SizeOf(typeof(MyPacket)); 
    // allocate a new buffer of the maximum size, to help deserialization 
    byte[] newBuffer = new byte[rawsize]; 
    Array.Copy(receivedData, newBuffer, receivedData.Length); 

    IntPtr buffer = Marshal.AllocHGlobal(rawsize); 
    Marshal.Copy(newBuffer, 0, buffer, rawsize); 

/// CRASHES ON NEXT LINE 
    MyPacketDefinition def = (MyPacketDefinition) Marshal.PtrToStructure(buffer, typeof(MyPacketDefinition)); 
    Marshal.FreeHGlobal(buffer); 

    //... 
} 

Ma structure ressemble à ceci:

[StructLayout (LayoutKind.Explicit, Pack=1, Size=576, CharSet=CharSet.Ansi)] 
public struct MyPacket 
    { 

    [FieldOffset(0)] 
    public System.Byte Type; 

    . 
    . // a few more INT/SHORT fields 
    . 

     [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] 
     [FieldOffset(28)] public System.Byte[] Address; 


     [MarshalAs(UnmanagedType.LPStr, SizeConst=64)] 
     [FieldOffset(44)] public System.String Name; 


     [MarshalAs(UnmanagedType.LPStr, SizeConst = 128)] 
     [FieldOffset(108)] public System.String SystemData; 


     [MarshalAs(UnmanagedType.ByValArray, SizeConst = 340)] 
     [FieldOffset(236)] public System.Byte[] Options; 

} 

Avec le dernier paramètre (option) est un champ de longueur variable maximale de 340 octets (normalement plus courtes)

+0

C'est probablement une faute de frappe, mais ne devriez-vous pas utiliser MyPacket au lieu de MyData lorsque vous appelez Marshal.PtrToStructure? –

+0

Pourquoi ne pas simplement utiliser BinaryReader, puisque vous connaissez tous les décalages? Vous êtes en train de copier la mémoire et de passer de la mémoire gérée à la mémoire non gérée juste pour convertir le tableau d'octets receivedData à la structure qui, à en juger par le code ici, n'est pas utilisée par le code non managé. – liggett78

+0

Oui, c'était une faute de frappe que j'ai introduite lors de la simplification du code pour publication. Désolé pour ça! Je l'ai corrigé. Je vais essayer le BinaryReader, mais j'aimerais quand même savoir ce que je fais de mal ci-dessus. :) –

Répondre

0

J'ai pu obtenir Pour travailler avec cette méthode, comme suggéré par Franci dans les commentaires (même si je ne suis pas sûr si c'est ce qu'il voulait dire).

Je ne sais pas pourquoi l'autre façon soulevait un AV, j'ai déjà utilisé cette méthode sans problème.

byte[] mem = new byte[sizeof(typeof(MyPacketDefinition))]; 
    Array.Copy(mem, receivedData, receivedData.Length); 
    using (MemoryStream ms = new MemoryStream(mem)) 
    { 
     using (BinaryReader br = new BinaryReader(ms)) 
     { 
      byte[] buff = br.ReadBytes(Marshal.SizeOf(typeof(MyPacketDefinition))); 

      GCHandle handle = GCHandle.Alloc(buff, GCHandleType.Pinned); 
      try 
      { 
       MyPacketDefinition s = (MyPacketDefinition)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(MyPacketDefinition)); 
      } 
      finally 
      { 
       handle.Free(); 
      } 

     } 
    } 
+0

Ce code n'a pas de sens. Vous utilisez l'opérateur sizeof sur un type qui n'est pas autorisé (je suppose que vous vouliez dire Marshal.SizeOf à la place). Et vous avez inversé les arguments de Array.Copy afin que vous mettiez à zéro les données reçues. Même si vous fixez que le contenu de buff sera toujours identique à celui de mem. Je crois que le problème avec votre code d'origine était incorrectement en utilisant LPStr où il aurait dû être ByValTStr. –

Questions connexes