2009-09-09 34 views
1

構造体を逆シリアル化しようとしていますが、PtrToStructureでAV例外が発生します。唯一のシワはこれが可変長構造だから、デシリアライズする前に長さを調整する必要があります。ここに私のコードはありますが、明らかに何か間違っていますか?この構造体には、整数/短い/バイト配列のみが含まれています。Marshal.PtrToStructureのアクセス違反

入力データは374バイトで、576バイトのデータ構造に一致するように調整する必要があります。基本的に、着信パケットは可能な最大値よりも短い最終フィールドを持ちます。これは正常です。最後のパラメータ(オプション)付き

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

} 

(通常は短い)340最大バイトの可変長フィールド

+0

これはおそらくタイプミスですが、Marshal.PtrToStructureを呼び出すときにMyDataの代わりにMyPacketを使用しないでください。 –

+0

すべてのオフセットを知っているので、なぜBinaryReaderを使用しないのですか?あなたは基本的にメモリをコピーして、マネージドメモリから非マネージドメモリへと変換するだけで、受信データバイト配列を、ここのコードで判断する構造体に変換するだけです(あなたがFreeHGlobalをPtrToStructureの直後に使っているため)。 – liggett78

+0

はい、投稿用のコードを簡素化するときに私が導入したタイプミスでした。それについて申し訳ありません!それを私が直した。 私はBinaryReaderを試しますが、私はまだ私が間違っていることを知りたいと思います。 :) –

答えて

0

私は得ることができたという。

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

    //... 
} 

私の構造は次のようになりますFranciがコメントで提案したように、この方法を使って作業することができます(ただし、これが彼の意図したものかどうかはわかりませんが)。

なぜ私はAVを上げていたのか分かりませんが、以前はその方法を使っていませんでした。

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

そのコードは意味をなさない。 Typeofでtypeof演算子を使用しています(代わりにMarshal.SizeOfを意味すると思います)。また、Array.Copyへの引数を逆にして、基本的にreceivedDataをゼロにします。あなたがbuffの内容がmemの内容と常に同じであることを修正したとしても。元のコードの問題が、ByValTStrになっていたはずのLPStrを使用していると誤解しています。 –