Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
Byte-Array direkt in ein struct "kopieren"
Regenwurm
myCSharp.de - Member



Dabei seit:
Beiträge: 295
Herkunft: Zentralschweiz

Themenstarter:

Byte-Array direkt in ein struct "kopieren"

beantworten | zitieren | melden

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 = =)
private Nachricht | Beiträge des Benutzers
markus111
myCSharp.de - Member

Avatar #avatar-3108.png


Dabei seit:
Beiträge: 479
Herkunft: Henstedt-Ulzburg

beantworten | zitieren | melden

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
private Nachricht | Beiträge des Benutzers
MarzAttak
myCSharp.de - Member



Dabei seit:
Beiträge: 18
Herkunft: Brandenburg

beantworten | zitieren | melden

Hi,

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

Weiß aber nicht, ob's weiterhilft.

Liebe Grüße
Marz
private Nachricht | Beiträge des Benutzers
Scavanger
myCSharp.de - Member

Avatar #avatar-3209.jpg


Dabei seit:
Beiträge: 309

beantworten | zitieren | melden

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));}}
private Nachricht | Beiträge des Benutzers
Regenwurm
myCSharp.de - Member



Dabei seit:
Beiträge: 295
Herkunft: Zentralschweiz

Themenstarter:

beantworten | zitieren | melden

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 = =)
private Nachricht | Beiträge des Benutzers
Spook
myCSharp.de - Member



Dabei seit:
Beiträge: 247
Herkunft: Esslingen a.N.

beantworten | zitieren | melden

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
private Nachricht | Beiträge des Benutzers
Regenwurm
myCSharp.de - Member



Dabei seit:
Beiträge: 295
Herkunft: Zentralschweiz

Themenstarter:

beantworten | zitieren | melden

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 = =)
private Nachricht | Beiträge des Benutzers
Spook
myCSharp.de - Member



Dabei seit:
Beiträge: 247
Herkunft: Esslingen a.N.

beantworten | zitieren | melden

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
private Nachricht | Beiträge des Benutzers