2008-08-05 19 views
65

C/C++構造体のデータがあったバイト[]配列からC#構造体を埋める最も良い方法は何でしょうか? Cの構造体は、この(私のCは非常にさびている)のようなものになります。バイト配列からC#でC/C++データ構造を読み取る

typedef OldStuff { 
    CHAR Name[8]; 
    UInt32 User; 
    CHAR Location[8]; 
    UInt32 TimeStamp; 
    UInt32 Sequence; 
    CHAR Tracking[16]; 
    CHAR Filler[12]; 
} 

をそして、このような何かを埋めるでしょう:

[StructLayout(LayoutKind.Explicit, Size = 56, Pack = 1)] 
public struct NewStuff 
{ 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8)] 
    [FieldOffset(0)] 
    public string Name; 

    [MarshalAs(UnmanagedType.U4)] 
    [FieldOffset(8)] 
    public uint User; 

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8)] 
    [FieldOffset(12)] 
    public string Location; 

    [MarshalAs(UnmanagedType.U4)] 
    [FieldOffset(20)] 
    public uint TimeStamp; 

    [MarshalAs(UnmanagedType.U4)] 
    [FieldOffset(24)] 
    public uint Sequence; 

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)] 
    [FieldOffset(28)] 
    public string Tracking; 
} 

OldStuffであった場合、NewStuffOldStuffをコピーするための最良の方法は何ですがbyte []配列として渡されましたか?

私は現在次のようなことをしていますが、それは一種の気がします。

GCHandle handle; 
NewStuff MyStuff; 

int BufferSize = Marshal.SizeOf(typeof(NewStuff)); 
byte[] buff = new byte[BufferSize]; 

Array.Copy(SomeByteArray, 0, buff, 0, BufferSize); 

handle = GCHandle.Alloc(buff, GCHandleType.Pinned); 

MyStuff = (NewStuff)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(NewStuff)); 

handle.Free(); 

これを行うには良い方法はありますか?


BinaryReaderクラスがメモリを固定し、Marshal.PtrStructureを使用しての上に任意のパフォーマンス向上を提供します使用して?

+1

、 。 – KPexEA

+1

構造体のレベルでそれをどう処理することができますか?つまり、構造体の各値のバイトを個別に逆にする必要はありませんか? – Pat

答えて

87

この文脈でわかるように、SomeByteArrayをバッファにコピーする必要はありません。あなたは単にSomeByteArrayからハンドルを取得し、それを固定し、PtrToStructureを使用してIntPtrのデータをコピーしてから放します。コピーは必要ありません。

NewStuff ByteArrayToNewStuff(byte[] bytes) 
{ 
    GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned); 
    try 
    { 
     NewStuff stuff = (NewStuff)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(NewStuff)); 
    } 
    finally 
    { 
     handle.Free(); 
    } 
    return stuff; 
} 

ジェネリック版:だろう

unsafe T ByteArrayToStructure<T>(byte[] bytes) where T : struct 
{ 
    fixed (byte* ptr = &bytes[0]) 
    { 
     return (T)Marshal.PtrToStructure((IntPtr)ptr, typeof(T)); 
    } 
} 
+0

CS0411 \tメソッド 'ByteArrayToStructure (byte []、int)'の型引数は、その使用から推論できません。型引数を明示的に指定してみてください。 (バイト配列のintインデックスを追加しました)。 – SSpoke

+0

例外が発生した場合にメモリがリークします。より安全なバージョンについては、http://stackoverflow.com/a/41836532/184528を参照してください。 – cdiggins

+0

4.5から。1、PtrToStructureのジェネリック版があるので、上記のジェネリック版の2行目は次のようになります。 '' 'var stuff = Marshal.PtrToStructure (handle.AddrOfPinnedObject());' ' – RobinHood70

0

byte []がある場合は、BinaryReaderクラスを使用して、利用可能なReadXメソッドを使用してNewStuffに値を設定できる必要があります。

4

は、梱包の問題に気をつけろ:

T ByteArrayToStructure<T>(byte[] bytes) where T: struct 
{ 
    GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned); 
    try 
    { 
     T stuff = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T)); 
    } 
    finally 
    { 
     handle.Free(); 
    } 
    return stuff; 
} 

簡単なバージョンは、(unsafeスイッチが必要)。この例ではすべてが4バイトの境界上にあるためすべてのフィールドが明白なオフセットになっていますが、これは必ずしも当てはまるわけではありません。 Visual C++はデフォルトで8バイト境界にパックされます。

+0

" Visual C++デフォルトでは** 8バイト**の境界にパックされています。これは私の問題を解決しました。ありがとうございました! –

3
object ByteArrayToStructure(byte[] bytearray, object structureObj, int position) 
{ 
    int length = Marshal.SizeOf(structureObj); 
    IntPtr ptr = Marshal.AllocHGlobal(length); 
    Marshal.Copy(bytearray, 0, ptr, length); 
    structureObj = Marshal.PtrToStructure(Marshal.UnsafeAddrOfPinnedArrayElement(bytearray, position), structureObj.GetType()); 
    Marshal.FreeHGlobal(ptr); 
    return structureObj; 
} 

ここでは、この

4

accepted answerの例外安全なバージョンである持っている:あなたのプログラムは、あなたがビッグエンディアン対リトルを処理する必要がある場合がありますさまざまなマシン上で実行されている場合FYI

public static T ByteArrayToStructure<T>(byte[] bytes) where T : struct 
{ 
    var handle = GCHandle.Alloc(bytes, GCHandleType.Pinned); 
    try { 
     return (T) Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T)); 
    } 
    finally { 
     handle.Free(); 
    } 
} 
関連する問題