Laden...

Byte-Array direkt in ein struct "kopieren"

Erstellt von Regenwurm vor 12 Jahren Letzter Beitrag vor 12 Jahren 9.751 Views
R
Regenwurm Themenstarter:in
295 Beiträge seit 2008
vor 12 Jahren
Byte-Array direkt in ein struct "kopieren"

Hallo zusammen,

Ich bekomme von einem Server ein byte-array gesendet, dass ich direkt in ein struct kopieren möchte (ohne die einzelnen Bytes, Words, etc auszulesen).

Ist dies mit irgend einem cast o.ä. möglich? Ich habe im Hinterkopf dass da das Keyword "fixed" eine Rolle spielt.

Gruess,
Regenwurm

ServiceStack & Angular = =)

479 Beiträge seit 2008
vor 12 Jahren

Hallo Regenwurm,

da gibt es mehrere Möglichkeiten, das wurde hier auch sicher schön öfter besprochen. Googeln hilft 😉
Schau dir mal die Marshal Klasse an, dort findest du Methoden wie PtrStructure. Beispiel: from byte[] to structure

mfg.
markus111

[Follow me on Twitter](http://twitter.com/blendingsky)
M
18 Beiträge seit 2008
vor 12 Jahren

Hi,

habe auch was gegoogelt:
Codesnippet: Byte-Array in Struktur kopieren

Weiß aber nicht, ob's weiterhilft.

Liebe Grüße
Marz

309 Beiträge seit 2008
vor 12 Jahren

Hallo,

das o.g. Snippet ist von mir, sollte das sein was du suchst, allerdings ist die Version nicht mehr ganz aktuell, hier die aktuelle Version:


/// <summary>
/// Kopiert Daten aus einem Byte-Array in eine entsprechende Strukture (struct). Die Struktur muss ein sequenzeilles Layout besitzen. ( [StructLayout(LayoutKind.Sequential)] 
/// </summary>
/// <param name="array">Das Byte-Array das die daten enthält</param>
/// <param name="offset">Offset ab dem die Daten in die Struktur kopiert werden sollen.</param>
/// <param name="structType">System.Type der Struktur</param>
/// <returns></returns>
static object ByteArrayToStruct(byte[] array, int offset, Type structType)
{
    if (structType.StructLayoutAttribute.Value != LayoutKind.Sequential)
        throw new ArgumentException("structType ist keine Struktur oder nicht Sequentiell.");

    int size = Marshal.SizeOf(structType);
           

    byte[] tmp = new byte[size];

    if (offset > 0)
        Array.Copy(array, offset, tmp, 0, size);
    else
        tmp = array;

    GCHandle structHandle = GCHandle.Alloc(tmp, GCHandleType.Pinned);
    object structure = Marshal.PtrToStructure(structHandle.AddrOfPinnedObject(), structType);
    structHandle.Free();

    return structure;
}

Verwendung:


[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
struct MyStruct
{
    int foo1;
    int foo2;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
    String str;
}

byte[] array = // ...

MyStruct structure = (MyStruct)ByteArrayToStruct(array, 0, typeof(MyStruct));


Das Prüfen der korrekten Arraylgröße ist raus geflogenen weil u.U. das Array kleiner sein kann als die dazugehörige Struktur! Dafür wird das u.U. unnötige Kopieren des Arrays vermieden.

Zu der Arraygröße:

Folgende Struktur hat die Größe 10:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
struct MyStruct
{
       [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
       String str;
}

Klar, 10 ANSI Zeichen sind 10 Bytes groß.

Aber diese Struktur ist 16(!) Bytes groß:


[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
struct MyStruct
{
     int foo;
     [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
     String str;
}

Int (32 bit) 4 Bytes + 10 Bytes = 16?

Das liegt am am Byte-Alignment, d.h. diese Struktur wird in 4Byte-Blöcke eingeteilt, die Größe ist ein Vielfaches von 4, es sind also "Lücken" in der Struktur
Das Array das in diese Struktur gemarshalt wird muss dennoch die Daten lückenlos enthalten, Marshal.PtrToStructure kopiert die Daten unter Berücksichtigung des Byte-Alignments.

Also Achtung bei solchen Aktionen, u.U. fehlen einfach Daten nachher in der Struktur.

using System;class H{static string z(char[]c){string r="";for(int x=0;x<(677%666);x++)r+=c[
x];return r;}static void Main(){int[]c={798,218,229,592,232,274,813,585,229,842,275};char[]
b=new char[11];for(int p=0;p<((59%12));p++)b[p]=(char)(c[p]%121);Console.WriteLine(z(b));}}

R
Regenwurm Themenstarter:in
295 Beiträge seit 2008
vor 12 Jahren

Hallo zusammen,

sorry für die späte Antwort aber das Ganze ging irgendwie total an mir vorbei. 😃
Die oben genannten Methoden funktionieren perfekt wenn es sich um ein normales Struct handelt.

Doch wie sieht es bei einem C++ struct aus, welches noch ein Union beinhaltet ?.

    struct ANAeventRecT{
        unsigned short int ANAIndex;
        union event{
            unsigned short int ANAwsAcuvConveyorEmpty;
            unsigned short int ANAwsAcuvConveyorOk;
            unsigned short int errorCode;
        } myevent;
    };

In C# muss ich dann ja bei einem struct als LayoutKind das Attribut 'Explicit' angeben (Is there a kind of union structure in C Sharp?).
Dann funktioniert die oberhalb genannte Methode leider nichtmehr.

Gruess

ServiceStack & Angular = =)

S
248 Beiträge seit 2008
vor 12 Jahren

Hallo Regenwurm,

diese Version sollte funktionieren:


static object ByteArrayToStruct(byte[] array, int offset, Type structType)
{
    if (array == null)
        throw new ArgumentNullException("array");

    if (!structType.IsValueType)
        throw new ArgumentException("structType");

    int size = Marshal.SizeOf(structType);

    if ((offset < 0) || (offset + size > array.Length))
        throw new ArgumentOutOfRangeException("offset");

    object structure;
    GCHandle structHandle = GCHandle.Alloc(array, GCHandleType.Pinned);
    try
    {
        IntPtr ptr = structHandle.AddrOfPinnedObject();
        ptr += offset;
        structure = Marshal.PtrToStructure(structHandle.AddrOfPinnedObject(), structType);
    }
    finally
    {
        structHandle.Free();
    }
    return structure;
}

spooky

R
Regenwurm Themenstarter:in
295 Beiträge seit 2008
vor 12 Jahren

Hi,

danke vielmals 😃
Geht das auch in die andere Richtung (Struct -> Byte Array)?
Oder kann mir da jemand einen Hinweis für den richtigen Weg geben?

grüess

ServiceStack & Angular = =)

S
248 Beiträge seit 2008
vor 12 Jahren

Hallo,

dieses Snippet sollte funktionieren (kleiner fix incl):

public static object ByteArrayToStruct(byte[] array, int offset, Type structType)
{
    if (array == null)
        throw new ArgumentNullException("array");

    if (structType == null)
        throw new ArgumentNullException("structType");

    if (!structType.IsValueType)
        throw new ArgumentException("structType");

    int size = Marshal.SizeOf(structType);

    if (array.Length < size)
        throw new ArgumentException("array");

    if ((offset < 0) || (offset + size > array.Length))
        throw new ArgumentOutOfRangeException("offset");

    object structure;
    GCHandle arrayHandle = GCHandle.Alloc(array, GCHandleType.Pinned);
    try
    {
        IntPtr ptr = arrayHandle.AddrOfPinnedObject();
        ptr += offset;
        structure = Marshal.PtrToStructure(arrayHandle.AddrOfPinnedObject(), structType);
    }
    finally
    {
        arrayHandle.Free();
    }
    return structure;
}

public static byte[] StructToByteArray(object structure)
{
    if (structure == null)
        throw new ArgumentNullException("structure");

    Type structType = structure.GetType();

    if (!structType.IsValueType)
        throw new ArgumentException("structure");

    int size = Marshal.SizeOf(structType);

    byte[] array = new byte[size];
    GCHandle arrayHandle = GCHandle.Alloc(array, GCHandleType.Pinned);
    try
    {
        IntPtr ptr = arrayHandle.AddrOfPinnedObject();
        Marshal.StructureToPtr(structure, ptr, false);
    }
    finally
    {
        arrayHandle.Free();
    }
    return array;
}

Grüße

spooky