Convert Structure to Byte Array

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Charles Law

    Convert Structure to Byte Array

    Suppose I have a structure

    Private Structure MyStruct
    Dim el1 As Byte
    Dim el2 As Int16
    Dim el3 As Byte
    End Structure

    I want to convert this into a byte array where

    Dim st as MyStruct
    Dim arr(3) As Byte

    arr(0) = st.el1
    arr(1) = st.el2 >> 8
    arr(2) = st.el2 And &HFF
    arr(3) = st.el3

    Is there a neat way to do this in the NET Framework? Ideally, it would be
    generic, so that it doesn't have to be hand coded for each different
    structure that I have. It would also be nice to be able to specify big or
    little endian, in the case of el2.

    Thanks

    Charles


  • Trev Hunter

    #2
    Re: Convert Structure to Byte Array

    I'm not sure if it's what you're after, but have a look at the
    StructLayoutAtt ribute and FieldOffsetAttr ibute classes that let you define
    the memory positions of each member of the structure:

    E.g.

    ---------------

    Imports System.Runtime. InteropServices

    <StructLayout(L ayoutKind.Expli cit)> Public Structure MyColor
    <FieldOffset(0) > Public Red As Byte
    <FieldOffset(1) > Public Green As Byte
    <FieldOffset(2) > Public Blue As Byte
    <FieldOffset(3) > Public Alpha as Byte
    <FieldOffset(0) > Public ColorValue As Integer
    End Structure

    ---------------

    In, the above example the layout of the structure is such that ColorValue is
    made up of the same 4 bytes that the Red, Green, Blue and alpha color bytes
    use.

    I know this ain't exactly converting it to an array, but it's the closest I
    can think of without resorting to serializing the structure.

    Hope this is a little help,

    Trev.



    "Charles Law" <blank@nowhere. com> wrote in message
    news:un1nBWB6DH A.2692@TK2MSFTN GP09.phx.gbl...[color=blue]
    > Suppose I have a structure
    >
    > Private Structure MyStruct
    > Dim el1 As Byte
    > Dim el2 As Int16
    > Dim el3 As Byte
    > End Structure
    >
    > I want to convert this into a byte array where
    >
    > Dim st as MyStruct
    > Dim arr(3) As Byte
    >
    > arr(0) = st.el1
    > arr(1) = st.el2 >> 8
    > arr(2) = st.el2 And &HFF
    > arr(3) = st.el3
    >
    > Is there a neat way to do this in the NET Framework? Ideally, it would be
    > generic, so that it doesn't have to be hand coded for each different
    > structure that I have. It would also be nice to be able to specify big or
    > little endian, in the case of el2.
    >
    > Thanks
    >
    > Charles
    >
    >[/color]


    Comment

    • Trev Hunter

      #3
      Re: Convert Structure to Byte Array

      Almost forgot, but you could use Reflection to get the values of the fields
      and add them to the array.

      e.g.

      ---------------------------

      Dim objTest As MyTest ' Structure containing 3 byte fields
      Dim aFields As FieldInfo() = GetType(MyTest) .GetFields
      Dim aValues As New ArrayList

      'Populate the structure
      objTest.Val1 = 1
      objTest.Val2 = 2
      objTest.Val3 = 3

      ' Get the byte values of each field
      For Each objField As FieldInfo In aFields

      If objField.FieldT ype.Equals(GetT ype(Byte)) Then

      ' Add the byte
      aValues.Add(cby te(objField.Get Value(objTest)) )

      Else
      ' Code to determine how many bytes I should add
      ' (i.e. check the datatype of the field and use little or big-endian
      ' math to get the byte values
      ' ......
      End If

      Next

      ' Convert the arraylist to an array of bytes
      Dim aBytes As Byte() = DirectCast(aVal ues.ToArray(Get Type(Byte)), Byte())

      ---------------------------

      I'm not sure that it would return the fields in the same order all the time
      though, but it should be generic enough as long as you handle situations
      where the structure contains fields that are not bytes (integers, strings,
      floats, objects etc.)

      HTH,

      Trev


      Comment

      • Charles Law

        #4
        Re: Convert Structure to Byte Array

        Hi Trev

        I had noticed the StructLayoutAtt ribute class and thought it might be a step
        in the right direction, but I am not sure how to make the last step.
        Serialization sounds like code, which I may have to resort to if there isn't
        a class already designed to do this type of conversion.

        I will have a play with the FieldOffsetAttr ibute class.

        Cheers

        Charles


        "Trev Hunter" <hunter_trev@ho tmail.com> wrote in message
        news:eJ727LC6DH A.2524@TK2MSFTN GP11.phx.gbl...[color=blue]
        > I'm not sure if it's what you're after, but have a look at the
        > StructLayoutAtt ribute and FieldOffsetAttr ibute classes that let you define
        > the memory positions of each member of the structure:
        >
        > E.g.
        >
        > ---------------
        >
        > Imports System.Runtime. InteropServices
        >
        > <StructLayout(L ayoutKind.Expli cit)> Public Structure MyColor
        > <FieldOffset(0) > Public Red As Byte
        > <FieldOffset(1) > Public Green As Byte
        > <FieldOffset(2) > Public Blue As Byte
        > <FieldOffset(3) > Public Alpha as Byte
        > <FieldOffset(0) > Public ColorValue As Integer
        > End Structure
        >
        > ---------------
        >
        > In, the above example the layout of the structure is such that ColorValue[/color]
        is[color=blue]
        > made up of the same 4 bytes that the Red, Green, Blue and alpha color[/color]
        bytes[color=blue]
        > use.
        >
        > I know this ain't exactly converting it to an array, but it's the closest[/color]
        I[color=blue]
        > can think of without resorting to serializing the structure.
        >
        > Hope this is a little help,
        >
        > Trev.
        >
        >
        >
        > "Charles Law" <blank@nowhere. com> wrote in message
        > news:un1nBWB6DH A.2692@TK2MSFTN GP09.phx.gbl...[color=green]
        > > Suppose I have a structure
        > >
        > > Private Structure MyStruct
        > > Dim el1 As Byte
        > > Dim el2 As Int16
        > > Dim el3 As Byte
        > > End Structure
        > >
        > > I want to convert this into a byte array where
        > >
        > > Dim st as MyStruct
        > > Dim arr(3) As Byte
        > >
        > > arr(0) = st.el1
        > > arr(1) = st.el2 >> 8
        > > arr(2) = st.el2 And &HFF
        > > arr(3) = st.el3
        > >
        > > Is there a neat way to do this in the NET Framework? Ideally, it would[/color][/color]
        be[color=blue][color=green]
        > > generic, so that it doesn't have to be hand coded for each different
        > > structure that I have. It would also be nice to be able to specify big[/color][/color]
        or[color=blue][color=green]
        > > little endian, in the case of el2.
        > >
        > > Thanks
        > >
        > > Charles
        > >
        > >[/color]
        >
        >[/color]


        Comment

        • Charles Law

          #5
          Re: Convert Structure to Byte Array

          Thanks Trev.

          I will have a try with this. If I wrap it all up in a class then, as you
          say, it will be generic enough.

          Cheers

          Charles


          "Trev Hunter" <hunter_trev@ho tmail.com> wrote in message
          news:e8BcLUC6DH A.2404@TK2MSFTN GP11.phx.gbl...[color=blue]
          > Almost forgot, but you could use Reflection to get the values of the[/color]
          fields[color=blue]
          > and add them to the array.
          >
          > e.g.
          >
          > ---------------------------
          >
          > Dim objTest As MyTest ' Structure containing 3 byte fields
          > Dim aFields As FieldInfo() = GetType(MyTest) .GetFields
          > Dim aValues As New ArrayList
          >
          > 'Populate the structure
          > objTest.Val1 = 1
          > objTest.Val2 = 2
          > objTest.Val3 = 3
          >
          > ' Get the byte values of each field
          > For Each objField As FieldInfo In aFields
          >
          > If objField.FieldT ype.Equals(GetT ype(Byte)) Then
          >
          > ' Add the byte
          > aValues.Add(cby te(objField.Get Value(objTest)) )
          >
          > Else
          > ' Code to determine how many bytes I should add
          > ' (i.e. check the datatype of the field and use little or[/color]
          big-endian[color=blue]
          > ' math to get the byte values
          > ' ......
          > End If
          >
          > Next
          >
          > ' Convert the arraylist to an array of bytes
          > Dim aBytes As Byte() = DirectCast(aVal ues.ToArray(Get Type(Byte)), Byte())
          >
          > ---------------------------
          >
          > I'm not sure that it would return the fields in the same order all the[/color]
          time[color=blue]
          > though, but it should be generic enough as long as you handle situations
          > where the structure contains fields that are not bytes (integers, strings,
          > floats, objects etc.)
          >
          > HTH,
          >
          > Trev
          >
          >[/color]


          Comment

          • Trev Hunter

            #6
            Re: Convert Structure to Byte Array

            > Serialization sounds like code, which I may have[color=blue]
            > to resort to if there isn't
            > a class already designed to do this type of conversion.[/color]

            With serialization, you can convert any class or structure that is marked
            with the <Serializable > attribute into a stream of bytes (and to an array of
            bytes) for saving to a disk or remoting accross a network. If you're only
            interested in the bytes used by the fields, use the reflection method
            mentioned in another post as serialization will add headers and could
            transform the data so it can be stored in different ways (e.g. XML or
            Binary) etc.

            HTH,

            Trev.

            "Charles Law" <blank@nowhere. com> wrote in message
            news:e$23mUC6DH A.2412@TK2MSFTN GP09.phx.gbl...[color=blue]
            > Hi Trev
            >
            > I had noticed the StructLayoutAtt ribute class and thought it might be a[/color]
            step[color=blue]
            > in the right direction, but I am not sure how to make the last step.
            > Serialization sounds like code, which I may have to resort to if there[/color]
            isn't[color=blue]
            > a class already designed to do this type of conversion.
            >
            > I will have a play with the FieldOffsetAttr ibute class.
            >
            > Cheers
            >
            > Charles
            >
            >
            > "Trev Hunter" <hunter_trev@ho tmail.com> wrote in message
            > news:eJ727LC6DH A.2524@TK2MSFTN GP11.phx.gbl...[color=green]
            > > I'm not sure if it's what you're after, but have a look at the
            > > StructLayoutAtt ribute and FieldOffsetAttr ibute classes that let you[/color][/color]
            define[color=blue][color=green]
            > > the memory positions of each member of the structure:
            > >
            > > E.g.
            > >
            > > ---------------
            > >
            > > Imports System.Runtime. InteropServices
            > >
            > > <StructLayout(L ayoutKind.Expli cit)> Public Structure MyColor
            > > <FieldOffset(0) > Public Red As Byte
            > > <FieldOffset(1) > Public Green As Byte
            > > <FieldOffset(2) > Public Blue As Byte
            > > <FieldOffset(3) > Public Alpha as Byte
            > > <FieldOffset(0) > Public ColorValue As Integer
            > > End Structure
            > >
            > > ---------------
            > >
            > > In, the above example the layout of the structure is such that[/color][/color]
            ColorValue[color=blue]
            > is[color=green]
            > > made up of the same 4 bytes that the Red, Green, Blue and alpha color[/color]
            > bytes[color=green]
            > > use.
            > >
            > > I know this ain't exactly converting it to an array, but it's the[/color][/color]
            closest[color=blue]
            > I[color=green]
            > > can think of without resorting to serializing the structure.
            > >
            > > Hope this is a little help,
            > >
            > > Trev.
            > >
            > >
            > >
            > > "Charles Law" <blank@nowhere. com> wrote in message
            > > news:un1nBWB6DH A.2692@TK2MSFTN GP09.phx.gbl...[color=darkred]
            > > > Suppose I have a structure
            > > >
            > > > Private Structure MyStruct
            > > > Dim el1 As Byte
            > > > Dim el2 As Int16
            > > > Dim el3 As Byte
            > > > End Structure
            > > >
            > > > I want to convert this into a byte array where
            > > >
            > > > Dim st as MyStruct
            > > > Dim arr(3) As Byte
            > > >
            > > > arr(0) = st.el1
            > > > arr(1) = st.el2 >> 8
            > > > arr(2) = st.el2 And &HFF
            > > > arr(3) = st.el3
            > > >
            > > > Is there a neat way to do this in the NET Framework? Ideally, it would[/color][/color]
            > be[color=green][color=darkred]
            > > > generic, so that it doesn't have to be hand coded for each different
            > > > structure that I have. It would also be nice to be able to specify big[/color][/color]
            > or[color=green][color=darkred]
            > > > little endian, in the case of el2.
            > > >
            > > > Thanks
            > > >
            > > > Charles
            > > >
            > > >[/color]
            > >
            > >[/color]
            >
            >[/color]


            Comment

            • Charles Law

              #7
              Re: Convert Structure to Byte Array

              Ah. I am only interested in the bytes, exactly as they appear in the
              structure, so I will stick with reflection.

              Charles


              "Trev Hunter" <hunter_trev@ho tmail.com> wrote in message
              news:emSeL5C6DH A.2908@tk2msftn gp13.phx.gbl...[color=blue][color=green]
              > > Serialization sounds like code, which I may have
              > > to resort to if there isn't
              > > a class already designed to do this type of conversion.[/color]
              >
              > With serialization, you can convert any class or structure that is marked
              > with the <Serializable > attribute into a stream of bytes (and to an array[/color]
              of[color=blue]
              > bytes) for saving to a disk or remoting accross a network. If you're only
              > interested in the bytes used by the fields, use the reflection method
              > mentioned in another post as serialization will add headers and could
              > transform the data so it can be stored in different ways (e.g. XML or
              > Binary) etc.
              >
              > HTH,
              >
              > Trev.
              >
              > "Charles Law" <blank@nowhere. com> wrote in message
              > news:e$23mUC6DH A.2412@TK2MSFTN GP09.phx.gbl...[color=green]
              > > Hi Trev
              > >
              > > I had noticed the StructLayoutAtt ribute class and thought it might be a[/color]
              > step[color=green]
              > > in the right direction, but I am not sure how to make the last step.
              > > Serialization sounds like code, which I may have to resort to if there[/color]
              > isn't[color=green]
              > > a class already designed to do this type of conversion.
              > >
              > > I will have a play with the FieldOffsetAttr ibute class.
              > >
              > > Cheers
              > >
              > > Charles
              > >
              > >
              > > "Trev Hunter" <hunter_trev@ho tmail.com> wrote in message
              > > news:eJ727LC6DH A.2524@TK2MSFTN GP11.phx.gbl...[color=darkred]
              > > > I'm not sure if it's what you're after, but have a look at the
              > > > StructLayoutAtt ribute and FieldOffsetAttr ibute classes that let you[/color][/color]
              > define[color=green][color=darkred]
              > > > the memory positions of each member of the structure:
              > > >
              > > > E.g.
              > > >
              > > > ---------------
              > > >
              > > > Imports System.Runtime. InteropServices
              > > >
              > > > <StructLayout(L ayoutKind.Expli cit)> Public Structure MyColor
              > > > <FieldOffset(0) > Public Red As Byte
              > > > <FieldOffset(1) > Public Green As Byte
              > > > <FieldOffset(2) > Public Blue As Byte
              > > > <FieldOffset(3) > Public Alpha as Byte
              > > > <FieldOffset(0) > Public ColorValue As Integer
              > > > End Structure
              > > >
              > > > ---------------
              > > >
              > > > In, the above example the layout of the structure is such that[/color][/color]
              > ColorValue[color=green]
              > > is[color=darkred]
              > > > made up of the same 4 bytes that the Red, Green, Blue and alpha color[/color]
              > > bytes[color=darkred]
              > > > use.
              > > >
              > > > I know this ain't exactly converting it to an array, but it's the[/color][/color]
              > closest[color=green]
              > > I[color=darkred]
              > > > can think of without resorting to serializing the structure.
              > > >
              > > > Hope this is a little help,
              > > >
              > > > Trev.
              > > >
              > > >
              > > >
              > > > "Charles Law" <blank@nowhere. com> wrote in message
              > > > news:un1nBWB6DH A.2692@TK2MSFTN GP09.phx.gbl...
              > > > > Suppose I have a structure
              > > > >
              > > > > Private Structure MyStruct
              > > > > Dim el1 As Byte
              > > > > Dim el2 As Int16
              > > > > Dim el3 As Byte
              > > > > End Structure
              > > > >
              > > > > I want to convert this into a byte array where
              > > > >
              > > > > Dim st as MyStruct
              > > > > Dim arr(3) As Byte
              > > > >
              > > > > arr(0) = st.el1
              > > > > arr(1) = st.el2 >> 8
              > > > > arr(2) = st.el2 And &HFF
              > > > > arr(3) = st.el3
              > > > >
              > > > > Is there a neat way to do this in the NET Framework? Ideally, it[/color][/color][/color]
              would[color=blue][color=green]
              > > be[color=darkred]
              > > > > generic, so that it doesn't have to be hand coded for each different
              > > > > structure that I have. It would also be nice to be able to specify[/color][/color][/color]
              big[color=blue][color=green]
              > > or[color=darkred]
              > > > > little endian, in the case of el2.
              > > > >
              > > > > Thanks
              > > > >
              > > > > Charles
              > > > >
              > > > >
              > > >
              > > >[/color]
              > >
              > >[/color]
              >
              >[/color]


              Comment

              • Mattias Sjögren

                #8
                Re: Convert Structure to Byte Array

                Charles,

                Check out



                It's C# code, but shouldn't be too hard to translate to VB.



                Mattias

                --
                Mattias Sjögren [MVP] mattias @ mvps.org
                http://www.msjogren.net/dotnet/ | http://www.dotnetinterop.com
                Please reply only to the newsgroup.

                Comment

                • Charles Law

                  #9
                  Re: Convert Structure to Byte Array

                  Hi Mattias

                  Well spotted. I have converted it and tried it succesfully. It is certainly
                  shorter and quicker than the reflection route, but perhaps less flexible.

                  The latter makes it possible to code for big endian and little endian,
                  whereas the former simply does a byte for byte copy.

                  I will keep both up my sleeve I think.

                  For completeness, I have included both solutions below.

                  <reflection>
                  Imports System.Reflecti on

                  Public Class Struct

                  Public Shared Function Convert(ByVal MyStruct As Object) As Byte()

                  Dim al As ArrayList
                  Dim Fields As FieldInfo() = MyStruct.GetTyp e.GetFields

                  al = New ArrayList

                  For Each fld As FieldInfo In Fields
                  If fld.FieldType.E quals(GetType(B yte)) Then
                  ' Add byte to array list
                  al.Add(CByte(fl d.GetValue(MySt ruct)))

                  ElseIf fld.FieldType.E quals(GetType(I nt16)) Then
                  ' Add 16-bit value to array list
                  Dim i16 As Int16

                  i16 = CType(fld.GetVa lue(MyStruct), Int16)
                  al.Add(CByte(i1 6 >> 8))
                  al.Add(CByte(i1 6 And &HFF))
                  Else
                  Throw New Exception("Cann ot convert type.")
                  End If
                  Next fld

                  Return DirectCast(al.T oArray(GetType( Byte)), Byte())

                  End Function
                  End Class
                  </reflection>

                  <memcopy>
                  Public Function RawSerialize(By Val anything As Object) As Byte()

                  Dim rawsize As Integer = Marshal.SizeOf( anything)
                  Dim buffer As IntPtr = Marshal.AllocHG lobal(rawsize)

                  Marshal.Structu reToPtr(anythin g, buffer, False)

                  Dim rawdatas(rawsiz e - 1) As Byte

                  Marshal.Copy(bu ffer, rawdatas, 0, rawsize)
                  Marshal.FreeHGl obal(buffer)

                  Return rawdatas

                  End Function

                  Public Function RawDeserialize( ByVal rawdatas As Byte(), ByVal anytype As
                  Type) As Object

                  Dim rawsize As Integer = Marshal.SizeOf( anytype)

                  If (rawsize > rawdatas.Length ) Then
                  Return Nothing
                  End If

                  Dim buffer As IntPtr = Marshal.AllocHG lobal(rawsize)

                  Marshal.Copy(ra wdatas, 0, buffer, rawsize)

                  Dim retobj As Object = Marshal.PtrToSt ructure(buffer, anytype)

                  Marshal.FreeHGl obal(buffer)

                  Return retobj

                  End Function
                  </memcopy>

                  Cheers

                  Charles


                  "Mattias Sjögren" <mattias.dont.w ant.spam@mvps.o rg> wrote in message
                  news:ujRSmkE6DH A.2760@TK2MSFTN GP09.phx.gbl...[color=blue]
                  > Charles,
                  >
                  > Check out
                  >
                  > http://groups.google.com/groups?selm...%40tkmsftngp05
                  >
                  > It's C# code, but shouldn't be too hard to translate to VB.
                  >
                  >
                  >
                  > Mattias
                  >
                  > --
                  > Mattias Sjögren [MVP] mattias @ mvps.org
                  > http://www.msjogren.net/dotnet/ | http://www.dotnetinterop.com
                  > Please reply only to the newsgroup.[/color]


                  Comment

                  • Jay B. Harlow [MVP - Outlook]

                    #10
                    Re: Convert Structure to Byte Array

                    Charles,
                    In addition to the other suggestions, I would consider reflection using
                    System.IO.Binar yReader & BinaryWriter (where the BinaryReader & BinaryWriter
                    are operating on a MemoryStream, as the MemoryStream is the array of
                    Bytes!). However this may be slightly more work then the ArrayList

                    Especially if the structure contained reference types that
                    Marshal.Structu reToPtr & PtrToStructure did not know how to handle
                    correctly...

                    However I suspect Mattias's suggestion will be the most useful in most
                    cases.

                    Hope this helps
                    Jay

                    "Charles Law" <blank@nowhere. com> wrote in message
                    news:un1nBWB6DH A.2692@TK2MSFTN GP09.phx.gbl...[color=blue]
                    > Suppose I have a structure
                    >
                    > Private Structure MyStruct
                    > Dim el1 As Byte
                    > Dim el2 As Int16
                    > Dim el3 As Byte
                    > End Structure
                    >
                    > I want to convert this into a byte array where
                    >
                    > Dim st as MyStruct
                    > Dim arr(3) As Byte
                    >
                    > arr(0) = st.el1
                    > arr(1) = st.el2 >> 8
                    > arr(2) = st.el2 And &HFF
                    > arr(3) = st.el3
                    >
                    > Is there a neat way to do this in the NET Framework? Ideally, it would be
                    > generic, so that it doesn't have to be hand coded for each different
                    > structure that I have. It would also be nice to be able to specify big or
                    > little endian, in the case of el2.
                    >
                    > Thanks
                    >
                    > Charles
                    >
                    >[/color]


                    Comment

                    Working...