Frage

Was wäre der beste Weg, eine C#-Struktur aus einem Byte[]-Array zu füllen, in dem die Daten aus einer C/C++-Struktur stammen?Die C-Struktur würde etwa so aussehen (mein C ist sehr eingerostet):

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

Und würde so etwas füllen:

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

Wie kopiert man am besten? OldStuff Zu NewStuff, Wenn OldStuff wurde als Byte[]-Array übergeben?

Ich mache gerade so etwas wie das Folgende, aber es fühlt sich irgendwie umständlich an.

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

Gibt es einen besseren Weg, dies zu erreichen?


Würde mit dem BinaryReader Klasse bieten keine Leistungssteigerungen gegenüber dem Anheften und Verwenden des Speichers Marshal.PtrStructure?

War es hilfreich?

Lösung

Soweit ich das sehe, ist es nicht nötig, etwas zu kopieren SomeByteArray in einen Puffer.Sie müssen lediglich den Griff abholen SomeByteArray, pinnen Sie es an, kopieren Sie das IntPtr Daten verwenden PtrToStructure und dann loslassen.Eine Kopie ist nicht erforderlich.

Das wäre:

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

Generische Version:

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

Einfachere Version (erfordert unsafe schalten):

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

Andere Tipps

Hier ist eine ausnahmesichere Version von akzeptierte Antwort:

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

Achten Sie auf Verpackungsprobleme.In dem von Ihnen angegebenen Beispiel befinden sich alle Felder an den offensichtlichen Offsets, da alles an 4-Byte-Grenzen liegt, aber das wird nicht immer der Fall sein.Visual C++ nutzt standardmäßig 8-Byte-Grenzen.

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

Nimm das

Wenn Sie ein Byte[] haben, sollten Sie in der Lage sein, die BinaryReader-Klasse zu verwenden und mithilfe der verfügbaren ReadX-Methoden Werte für NewStuff festzulegen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top