Autor Beitrag
Codeexplorer
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 39



BeitragVerfasst: Mo 19.11.07 16:02 
Hallo zusammen,

ich würde gerne Binärdaten serialisieren, sprich ein byte[] in eine passende Struktur übertragen.
Ich habe mich jetzt schon ganz schwindelig gegoogelt. Vielleicht kann mir jemand von Euch was dazu sagen.
Hier mein momentaner Stand:

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
 
        static public void setTelStructureByArray<T>(byte[] arr, ref T data)
        {
            data=(T)RawDeserialize(arr, typeof(T));
        }

        private static object RawDeserialize(byte[] rawdatas, Type anytype)
        {
            int rawsize = Marshal.SizeOf(anytype);
            if (rawsize > rawdatas.Length)
                return null;
            GCHandle handle = GCHandle.Alloc(rawdatas, GCHandleType.Pinned);
            IntPtr buffer = handle.AddrOfPinnedObject();
            object retobj = Marshal.PtrToStructure(buffer, anytype);
            handle.Free();
            return retobj;
        }


Mein Problem ist nun: wenn in der Struktur ein Array mit flexibler Größe enthalten
ist, wird RawDeserialize nicht komplett ausgeführt, da hier die Bedingung
(rawsize > rawdatas.Length) zuschlägt.
Hat jemand eine Idee, wie man das Array behandeln kann ? Wie man vielleicht oben
schon sehen kann, suche ich hier nach einer generischen Lösung, die mit verschiedenen
structs, teils mit, teils ohne Array arbeiten kann.

Vielen Dank für alle Hinweise !

Ach ja, ich sag's gleich dazu: RawDeserialize ist nicht von mir, sie tut aber bis auf
den oben genannten Fall ziemlich genau das was ich brauche ...


Moderiert von user profile iconChristian S.: Topic aus Sonstiges (C# / .NET) verschoben am Mo 19.11.2007 um 15:20
Christian S.
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 20451
Erhaltene Danke: 2264

Win 10
C# (VS 2019)
BeitragVerfasst: Mo 19.11.07 16:19 
Hi!

Schau Dir mal die BinaryFormatter-Klasse an, die sollte Dir die Arbeit abnehmen.

Grüße
Christian

_________________
Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".
Codeexplorer Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 39



BeitragVerfasst: Mo 19.11.07 18:20 
Vielen Dank für den Tipp, BinaryFormatter hört sich sehr vielversprechend an. Leider habe ich noch ein paar Problemchen mit der Umsetzung. Hier erstmal der Quellcode:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
      static public void setTelStructureByArray<T>(byte[] arr, ref T data)
        {
            using (MemoryStream memStream = new MemoryStream(arr.Length))
            {
                memStream.Write(arr, 0, arr.Length);

                BinaryFormatter formatter = new BinaryFormatter();
                try
                {
                    data = (T)formatter.Deserialize(memStream);
                }
                catch (SerializationException e)
                {
                    Console.WriteLine("Failed to serialize. Reason: " + e.Message);
                    throw;
                }
                finally
                {
                    memStream.Close();
                }
            }
        }

Ich bekomme immer die Fehlermeldung "Das Streamende wurde erreicht, bevor die Verarbeitung abgeschlossen wurde.".
Vermutlich habe ich hier wieder ein Problem mit der dynamischen Arraygröße. Meine Struktur sieht ungefähr so aus:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
    [Serializable]
    public struct TelInitResponseData 
    {
        public ushort encodedLength;
        //...
        public byte[] versNums;
    }


Ich habe auch schon mit der BinaryFormatter.Binder-Property experimentiert, allerdings noch ohne Erfolg. Was mache ich hier falsch ?? :gruebel:
Oliver
Kha
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: Mo 19.11.07 18:37 
Was genau hast du denn vor? Es gibt ziemlich viele Arten von Serialisierung und ich bin mir nicht sicher, welche du brauchst.
Codeexplorer Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 39



BeitragVerfasst: Mo 19.11.07 18:59 
Was ich vorhabe: Mein Programm versendet und empfängt Daten an und von einem externen Gerät via USB. Die möglichen Formate der hereinkommenden Daten habe ich als structs hinterlegt. Am ersten übertragenen Byte erkenne ich, in welches Format
die hereinkommenden Daten umgewandelt werden müssen. Beim Versenden der Daten gehe im umgekehrt vor, ich fülle eine Struktur mit Daten, wandle die Daten in ein byte-Array um und schicke sie dann auf die Reise...
Oliver
Kha
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: Mo 19.11.07 20:11 
Dann ist dein erster Ansatz der einzig richtige, du hast wohl nur noch irgendeinen Fehler beim Marshalling (MarshalAsAttributes). Woher weißt du denn, wie groß das Array ist (ausrechnen kann das Marshal wohl leider nicht)?

Achja, hier noch ne etwas schönere Version:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
    public static T RawDeserialize<T>(byte[] rawdata)
    {
      if (Marshal.SizeOf(typeof(T)) > rawdata.Length)
        throw new ArgumentException("...");

      GCHandle handle = GCHandle.Alloc(rawdata, GCHandleType.Pinned);
      try {
        IntPtr buffer = handle.AddrOfPinnedObject();
        return (T)Marshal.PtrToStructure(buffer, typeof(T));
      }
      finally {
        handle.Free();
      }
    }
Codeexplorer Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 39



BeitragVerfasst: Di 20.11.07 09:58 
Die Größe des Arrays ist kein Problem, die wird in einem seperaten Datenfeld mit übertragen. Wenn ich das Datenformat kenne, weiß ich auch an welcher Stelle ich diesen Wert auslesen kann. Eine Frage zu Deiner Version von RawDeserialize: Bist Du sicher, dass die return-Anweisung im try-Block stehen sollte?
Oliver

Ach ja, Marshalling ist ein gutes Stichwort: Wenn ich
ausblenden C#-Quelltext
1:
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U1, SizeConst = 2)]					

für das Array verwende, funktioniert RawDeserialize auch, allerdings habe ich dann wieder zur Entwurfszeit eine feste Arraygrenze vorgegeben, was ich ja nicht möchte! Ohne SizeConst bekomme ich die oben gennante Fehlermeldung.
Codeexplorer Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 39



BeitragVerfasst: Fr 23.11.07 13:13 
So, scheinbar gibt es noch kein Patentrezept für mein Problem. Für alle die sich mit ähnlichen Dingen abplagen: Ich habe jetzt die Arrays deren Größe zur Entwurfszeit nicht feststeht aus den Strukturen herausgenommen, damit kann ich schon mal RawSerialize verwenden. Die Arrays lese ich dann mit der Bitconverter-Klasse Element für Element einzeln ein. Das ist nicht besonders elegant gelöst, aber es funktioniert. Trotzdem: Danke für alle Hinweise.
Oliver