Converting Block of Bytes to Structure

  • Thread starter Thread starter Mike
  • Start date Start date
M

Mike

I have this structure layout with 512 bytes of data:

<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi)> _
Public Structure TChannelMessage
Public Channel As Integer
Public SenderId As Integer
Public UserData As Short
Public DataSize As Short
<MarshalAs(UnmanagedType.ByValArray, sizeconst:=500)> _
Public Data() As Byte
End Structure

A marshaled callback function returns it:

Delegate Function cbWildcatDelegate(_
ByVal userdata As UInt32, _
ByRef msg As TChannelMessage) As Long

Which I would to do be able to do is to programmatically type cast,
map, the 500 bytes TChannelMessage.Data to other marshaled structure
layouts the block represents.

TPageMessage
TChatMessage
TSystemEventFileInfo
TSystemControlViewMsg
TSystemPageNewMessage
TSystemPageInstantMessage

For each, TPageMessage is:

<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi)> _
Public Structure SystemPageText
<MarshalAs(UnmanagedType.ByValTStr, sizeconst:=80)> _
Public PageText As String
End Structure

<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi)> _
Public Structure TPageMessage
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=28)> _
Public From As String
<MarshalAs(UnmanagedType.ByValArray, sizeconst:=3)> _
Public Message() As SystemPageText
Public InviteToChat As Integer
End Structure

In c/c++, of course, I can easily type case, but right now for VB.NET
this I have a wrapper for it:

Function GetWildcatPageMessage( _
Byval cmsg As TChannelMessage) As TPageMessage
Dim pmsg As New TPageMessage
pmsg.From = AZString(cmsg.Data, 0, 28)
Array.Resize(pmsg.Message, SIZE_SYSTEMPAGE_LINES)
For i As Integer = 0 To SIZE_SYSTEMPAGE_LINES - 1
pmsg.Message(i).PageText = AZString(cmsg.Data, 28 + i * 80, 80)
Next
pmsg.InviteToChat = BitConverter.ToInt32(cmsg.Data, 28 3*80)
Return pmsg
End Function

Function AZString(ByVal b() As Byte, _
ByVal ofs As Integer, ByVal len As Integer) As String
Dim wsp() As Char = {Chr(32), Chr(0), Chr(9)}
Return Text.Encoding.ASCII.GetString(b, ofs, len).Trim(wsp)
End Function

I have to repeat this for other structures, which is ok, but I also
need user defined structures to be mapped as well.

Any technique with a single function to make byte array to a structure?
 
Mike said:
In c/c++, of course, I can easily type case, but right now for VB.NET
this I have a wrapper for it:

Function GetWildcatPageMessage( _
Byval cmsg As TChannelMessage) As TPageMessage
Dim pmsg As New TPageMessage
pmsg.From = AZString(cmsg.Data, 0, 28)
Array.Resize(pmsg.Message, SIZE_SYSTEMPAGE_LINES)
For i As Integer = 0 To SIZE_SYSTEMPAGE_LINES - 1
pmsg.Message(i).PageText = AZString(cmsg.Data, 28 + i * 80, 80)
Next
pmsg.InviteToChat = BitConverter.ToInt32(cmsg.Data, 28 3*80)
Return pmsg
End Function

Function AZString(ByVal b() As Byte, _
ByVal ofs As Integer, ByVal len As Integer) As String
Dim wsp() As Char = {Chr(32), Chr(0), Chr(9)}
Return Text.Encoding.ASCII.GetString(b, ofs, len).Trim(wsp)
End Function

I have to repeat this for other structures, which is ok, but I also need
user defined structures to be mapped as well.

Any technique with a single function to make byte array to a structure?

For the search archives, this might be useful for the next person
needing something similar.

I came up with a method that is more generic. I will have at least 8
functions which only differ by the structure type mapped to the data
byte array that I am "type casting".

I wanted to to do using a template in VB.NET and noticed the pattern was:

Function ChannelEventType(ByRef cmsg As TChannelMessage) As TYPE_NAME
Dim x As TYPE_NAME
Dim p As IntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(x))
Marshal.Copy(cmsg.Data, 0, p, Marshal.SizeOf(x))
x = CType(Marshal.PtrToStructure(h,_GetType(TYPE_NAME)),_TYPE_NAME)
Marshal.FreeHGlobal(h)
Return x
End Function

After figuring out the syntax, VB.NET nicely provides Generic
Functions and its now:

Function ChannelEventType(Of T)(ByRef cmsg As TChannelMessage) As T
Dim x As T
Dim h As IntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(x))
Marshal.Copy(cmsg.Data, 0, h, Marshal.SizeOf(x))
x = CType(Marshal.PtrToStructure(h, GetType(T)), T)
Marshal.FreeHGlobal(h)
Return x
End Function

and the usage is in the callback for different types:

Dim page As TPageMessage = ChannelEventType(Of TPageMessage)(cmsg)
RaiseEvent OnPageMessage(page)

..
Dim page As TFileMessage = ChannelEventType(Of TFileMessage)(cmsg)
RaiseEvent OnFileMessage(page)

--
 
Mike said:
In c/c++, of course, I can easily type case, but right now for VB.NET
this I have a wrapper for it:

Function GetWildcatPageMessage( _
Byval cmsg As TChannelMessage) As TPageMessage
Dim pmsg As New TPageMessage
pmsg.From = AZString(cmsg.Data, 0, 28)
Array.Resize(pmsg.Message, SIZE_SYSTEMPAGE_LINES)
For i As Integer = 0 To SIZE_SYSTEMPAGE_LINES - 1
pmsg.Message(i).PageText = AZString(cmsg.Data, 28 + i * 80, 80)
Next
pmsg.InviteToChat = BitConverter.ToInt32(cmsg.Data, 28 3*80)
Return pmsg
End Function

Function AZString(ByVal b() As Byte, _
ByVal ofs As Integer, ByVal len As Integer) As String
Dim wsp() As Char = {Chr(32), Chr(0), Chr(9)}
Return Text.Encoding.ASCII.GetString(b, ofs, len).Trim(wsp)
End Function

I have to repeat this for other structures, which is ok, but I also need
user defined structures to be mapped as well.

Any technique with a single function to make byte array to a structure?

For the search archives, this might be useful for the next person
needing something similar.

I came up with a method that is more generic. I will have at least 8
functions which only differ by the structure type mapped to the data
byte array that I am "type casting".

I wanted to to do using a template in VB.NET and noticed the pattern was:

Function ChannelEventType(ByRef cmsg As TChannelMessage) As TYPE_NAME
Dim x As TYPE_NAME
Dim p As IntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(x))
Marshal.Copy(cmsg.Data, 0, p, Marshal.SizeOf(x))
x = CType(Marshal.PtrToStructure(h,_GetType(TYPE_NAME)),_TYPE_NAME)
Marshal.FreeHGlobal(h)
Return x
End Function

After figuring out the syntax, VB.NET nicely provides Generic
Functions and its now:

Function ChannelEventType(Of T)(ByRef cmsg As TChannelMessage) As T
Dim x As T
Dim h As IntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(x))
Marshal.Copy(cmsg.Data, 0, h, Marshal.SizeOf(x))
x = CType(Marshal.PtrToStructure(h, GetType(T)), T)
Marshal.FreeHGlobal(h)
Return x
End Function

and the usage is in the callback for different types:

Dim page As TPageMessage = ChannelEventType(Of TPageMessage)(cmsg)
RaiseEvent OnPageMessage(page)

..
Dim page As TFileMessage = ChannelEventType(Of TFileMessage)(cmsg)
RaiseEvent OnFileMessage(page)

--
 
Back
Top