Lesen einer C / C ++ - Datenstruktur in C # aus einem Byte-Array

  • Was ist der beste Weg, eine C # -Struktur aus einem Byte [] -Array zu füllen, wo die Daten aus einer C / C ++ - Struktur stammen? Die C struct würde ungefähr so ​​aussehen (mein C ist sehr rostig):

     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 this:

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

    Was ist der beste Weg, OldStuff nach NewStuff zu kopieren, wenn OldStuff war als Byte [] -Array übergeben?

    Ich mache derzeit so etwas wie das Folgende, aber es fühlt sich irgendwie unbeholfen 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 eine bessere Möglichkeit, dies zu erreichen?


    Würde das verwenden Die Klasse BinaryReader bietet Leistungsverbesserungen, wenn der Speicher festgehalten und Marshal.PtrStructure?

    verwendet wird
    07 February 2016
    Markus SafarMHop
4 answers
  • Nach allem, was ich in diesem Zusammenhang sehen kann, müssen Sie SomeByteArray nicht in einen Puffer kopieren. Sie müssen lediglich das Handle von SomeByteArray abrufen, es anheften, die IntPtr -Daten mit PtrToStructure kopieren und dann loslassen. Keine Kopie.

    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 
    {
        GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
        try
        {
            T stuff = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
        }
        finally
        {
            handle.Free();
        }
        return stuff;
    }
     

    Einfachere Version (erfordert Schalter unsafe):

     unsafe T ByteArrayToStructure<T>(byte[] bytes) where T : struct
    {
        fixed (byte* ptr = &bytes[0])
        {
            return (T)Marshal.PtrToStructure((IntPtr)ptr, typeof(T));
        }
    }
     
    29 September 2017
    Coincoin
  • Achten Sie auf Verpackungsprobleme. In dem Beispiel, das Sie angegeben haben, befinden sich alle Felder bei den offensichtlichen Offsets, da sich alles auf 4-Byte-Grenzen befindet. Dies ist jedoch nicht immer der Fall. Visual C ++ packt standardmäßig 8-Byte-Grenzen.

    03 December 2009
    Tim Ring
  •  [&&& 1]
                                        
    01 February 2012
    Richard J. Ross III
  • Wenn Sie ein Byte [] haben, sollten Sie die BinaryReader-Klasse verwenden und mit den verfügbaren ReadX-Methoden Werte für NewStuff festlegen können.

    06 August 2008
    onestopLazyCat