Asked by:
Initialising structures with byte arrays

Question
-
I'm having trouble initialising ucData() byte array.
ucData appears to initialise but it does not put the valuables in the correct memory location for the structure.
All other valiables appear in correct memory loactions apart from the array.
can anyone help?
As I pass this structure ByVal to a function, I need to ensure array data appears contained in the structure.
I have also used so that reallocate memory locations for different data requirements (act like a c/c++ union)
Thanks in advance.
Code SnippetCode Snippet<StructLayout(LayoutKind.Explicit)> _
Public Structure Test<FieldOffset(0)> Dim sentDate As UInt32 ' 00..03
<FieldOffset(4)>
Dim sentTime As UInt32 ' 04..07<FieldOffset(8)>
Dim deliverdDate As UInt32 ' 08..11<FieldOffset(12)>
Dim deliveredTime As UInt32 ' 12..15<FieldOffset(16)>
Dim consumedDate As UInt32 ' 16..19<FieldOffset(20)>
Dim consumedTime As UInt32 ' 20..23<FieldOffset(24)>
Dim deliveryStatus As UInt32 ' 24..27<FieldOffset(28)>
Dim typeOfAddress As Byte ' 28<FieldOffset(29)>
Dim ucSpare29_31 As Byte ' 29..31<FieldOffset(32)>
Dim Issi As UInt32 ' 32..35<FieldOffset(36)>
Dim Mnc As UInt16 ' 36..37<FieldOffset(38)>
Dim Mcc As UInt16 ' 38..39 '-- Space here for future numbers ' 40..56<FieldOffset(57)>
Dim ucSpare57_59 As Byte ' 57..59'-- type of message (Union)
<FieldOffset(60)>
Dim ucSdsItemType As Byte ' 60<FieldOffset(61)>
Dim ucSpare61_63 As Byte ' 61..63'-- First Union Item to byte 327
<FieldOffset(64)>
Dim protocolIdentifier As UInt16 ' 64..65<FieldOffset(66)>
Dim dataLength As UInt16 ' 66..67<FieldOffset(68)>
Dim ucData() As Byte ' 68..322<FieldOffset(323)>
Dim ucSpare323 As Byte ' 323<FieldOffset(324)>
Dim DeliveryReportRequest As Byte ' 324<FieldOffset(325)>
Dim ConsumedReportRequest As Byte ' 325<FieldOffset(326)>
Dim ValidityPeriod As Byte ' 326<FieldOffset(327)>
Dim ucSpare327 As Byte ' 327 '-- Second union Item<FieldOffset(64)>
Dim statusCode As UInt16 ' 64..65<FieldOffset(66)>
Dim ucSpare66_67 As Byte ' 66..67 End StructureDim OutboxItem As Test
ReDim OutboxItem.ucData(254)Dim timeNow As New DateTime
timeNow = Now
'-- timestamp data
OutboxItem.sentDate =
CUInt(timeNow.Year * 10000 + timeNow.Month * 100 + timeNow.Day)OutboxItem.sentTime =
CUInt(timeNow.TimeOfDay.Seconds + timeNow.TimeOfDay.Minutes * 60 + timeNow.TimeOfDay.Hours * 3600)'-- Address data
OutboxItem.typeOfAddress =
&H0OutboxItem.Issi = Issi
OutboxItem.Mnc = Mnc
OutboxItem.Mcc = Mcc
'-- SDS data
OutboxItem.ucSdsItemType = &H4
OutboxItem.protocolIdentifier = Pid
OutboxItem.dataLength =
CUShort((text.Length + 1) * 8)'-- Load text message into UInt8(byte) array
Dim i As UInt16OutboxItem.ucData(0) =
&H1 For i = 0 To CUShort(CUInt(text.Length - 1))'-- Send data to OutBox and return response
Return ApiSdsOutboxWriteSdsItem(OutboxItem) End FunctionWednesday, April 23, 2008 2:33 PM
All replies
-
You probably just need to apply this to the array:
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=255)>
Your code wouldn't build on my 64 bit system. The array lies at 68 which is not a multiple of 8 (size of a pointer on a 64 bit OS), so it says the field is incorrectly aligned.
Try using layout sequential, this is 328 on my system, so I think it is laid out correctly. This means you have to get rid of the unions which would require an explicit layout. The union isn't vitally important in this case anyway,,,
<StructLayout(LayoutKind.Sequential, Pack:=1)> _
Public Structure Test
Dim sentDate As UInt32 ' 00..03
Dim sentTime As UInt32 ' 04..07
Dim deliverdDate As UInt32 ' 08..11
Dim deliveredTime As UInt32 ' 12..15
Dim consumedDate As UInt32 ' 16..19
Dim consumedTime As UInt32 ' 20..23
Dim deliveryStatus As UInt32 ' 24..27
Dim typeOfAddress As Byte ' 28
Dim ucSpare29_31 As Byte ' 29..31
Dim ucSpare30 As Byte
Dim ucSpare31 As Byte
Dim Issi As UInt32 ' 32..35
Dim Mnc As UInt16 ' 36..37
Dim Mcc As UInt16 ' 38..39
Dim ucSpare40 As Integer
Dim ucSpare44 As Integer
Dim ucSpare48 As Integer
Dim ucSpare52 As Integer
Dim ucSpare56 As Integer
Dim ucSdsItemType As Byte ' 60
Dim ucSpare61 As Byte
Dim ucSpare62 As Byte
Dim ucSpare63 As Byte
Dim protocolIdentifierOrStatusCode As UInt16 ' 64..65
Dim dataLength As UInt16 ' 66..67
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=255)> _
Dim ucData() As Byte ' 68..322
Dim ucSpare323 As Byte ' 323
Dim DeliveryReportRequest As Byte ' 324
Dim ConsumedReportRequest As Byte ' 325
Dim ValidityPeriod As Byte ' 326
Dim ucSpare327 As Byte ' 327
Public Sub Initialize()
Me.ucData = New Byte(254) {}
End Sub
End StructureWednesday, April 23, 2008 6:28 PM -
Thanks Jo0ls for your input.
You are correct about the union... there are a number of ways around that, but for your info I only posted 2 unions in this structure, there is actually 5, all strating at byte location 64.
I don' think there is anything I can do about the array misalignment apart from Dimensioning 255 individual bytes (which I may have to do anyway). You see, I need to send the contents of this structure as a paramter to a function call in a DLL. The DLL was written in c/c++. The struct for this chunk of memory is easy to produce and use in c. (I have this bit of code working ok in vc++ but I want to write it all in vb)
Further on your <LayoutKind.sequential> suggestion;
1> will this keep zero gaps between memory locations
2> how and when do I initialize ucData from a separate project code file in my solution? This is still not apparent to me with the things I have tried.
Sorry if I am a bit vague on this but I am new to vb.
Thanks again...
Wednesday, April 23, 2008 11:26 PM -
Does it not work with the extra attribute I mentioned? There's a test at the bottom that seems to show it works. (I'm on 32 bit now so it will compile with the explicit field offset).
Pack:=1 tells it to align the fields to the nearest 1 byte boundary, so there will be no gaps.
Create the structure, then assign a new array object to the ucData field, then fill it up. Arrays are Reference types and need to be instantiated. All the other fields, and the structure itself are value types.
The ByValArray attribute is telling the marshaller to treat the array as a value type instead - i.e. place the items directly in the structure instead of creating the array elsewhere (on the heap) and placing a reference to the array in the structure, which is what it would do in managed code.
Here's a test that I think shows it is using the correct layout (on 32 bit OS).
Code SnippetImports System.Runtime.InteropServices
Imports System.Text
Public Class Form1
Sub New()
' This call is required by the Windows Form Designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
Dim testString As String = "Hydrogen Helium Lithium Beryllium Boron Carbon Nitrogen Oxygen " & _
"Fluorine Neon Sodium Magnesium Aluminium Silicon Phosphorus Sulphur Chlorine Argon Potassium " & _
"Calcium Scandium Titanium Vanadium Chromium Manganese Iron Cobalt Nickel Copper Zinc Gallium " & _
"Germa"
Send(0, 0, 0, 0, testString)
End Sub
<StructLayout(LayoutKind.Explicit)> _
Public Structure Test
<FieldOffset(0)> Dim sentDate As UInt32 ' 00..03
<FieldOffset(4)> Dim sentTime As UInt32 ' 04..07
<FieldOffset(8)> Dim deliverdDate As UInt32 ' 08..11
<FieldOffset(12)> Dim deliveredTime As UInt32 ' 12..15
<FieldOffset(16)> Dim consumedDate As UInt32 ' 16..19
<FieldOffset(20)> Dim consumedTime As UInt32 ' 20..23
<FieldOffset(24)> Dim deliveryStatus As UInt32 ' 24..27
<FieldOffset(28)> Dim typeOfAddress As Byte ' 28
<FieldOffset(29)> Dim ucSpare29_31 As Byte ' 29_31
<FieldOffset(32)> Dim Issi As UInt32 ' 32..35
<FieldOffset(36)> Dim Mnc As UInt16 ' 36..37
<FieldOffset(38)> Dim Mcc As UInt16 ' 38..39
'-- Space here for future numbers ' 40..56
<FieldOffset(57)> Dim ucSpare57_59 As Byte ' 57..59
'-- type of message (Union)
<FieldOffset(60)> Dim ucSdsItemType As Byte ' 60
<FieldOffset(61)> Dim ucSpare61_63 As Byte ' 61..63
'-- First Union Item to byte 327
<FieldOffset(64)> Dim protocolIdentifier As UInt16 ' 64..65
<FieldOffset(66)> Dim dataLength As UInt16 ' 66..67
<FieldOffset(68), MarshalAs(UnmanagedType.ByValArray, SizeConst:=255)> Dim ucData() As Byte ' 68..322
<FieldOffset(323)> Dim ucSpare323 As Byte ' 323
<FieldOffset(324)> Dim DeliveryReportRequest As Byte ' 324
<FieldOffset(325)> Dim ConsumedReportRequest As Byte ' 325
<FieldOffset(326)> Dim ValidityPeriod As Byte ' 326
<FieldOffset(327)> Dim ucSpare327 As Byte ' 327
'-- Second union Item
<FieldOffset(64)> Dim statusCode As UInt16 ' 64..65
<FieldOffset(66)> Dim ucSpare66_67 As Byte ' 66..67
End Structure
Private Function Send(ByVal Mcc As UInt16, ByVal Mnc As UInt16, ByVal Issi As UInt32, ByVal Pid As UInt16, ByVal text As String) As Int32
Dim OutboxItem As New Test
OutboxItem.ucData = New Byte(254) {}
With OutboxItem
.sentDate = &H3020100
.sentTime = &H7060504
.deliverdDate = &H11100908
.deliveredTime = &H15141312
.consumedDate = &H19181716
.consumedTime = &H23222120
.deliveryStatus = &H27262524
.typeOfAddress = &H28
.ucSpare29_31 = &H29
.Issi = &H35343332UI
.Mnc = &H3736US
.Mcc = &H3938US
.ucSdsItemType = &H60
.ucSpare61_63 = &H61
.protocolIdentifier = &H6564
.dataLength = &H6766
.ucSpare323 = &H23
.DeliveryReportRequest = &H24
.ConsumedReportRequest = &H25
.ValidityPeriod = &H26
.ucSpare327 = &H27
End With
'-- Load text message into UInt8(byte) array
' Different technique
Dim textBytes() As Byte = encoding.ASCII.GetBytes(text)
OutboxItem.ucData(0) = &H1
Buffer.BlockCopy(textBytes, 0, OutboxItem.ucData, 1, textBytes.Count)
' Test: Copy the structure from some pinned memory to a byte array.
Dim bytes(Marshal.SizeOf(GetType(Test)) - 1) As Byte
Dim gch As GCHandle = GCHandle.Alloc(bytes, GCHandleType.Pinned)
Marshal.StructureToPtr(OutboxItem, gch.AddrOfPinnedObject, False)
gch.Free()
' And dump the bytes.
For j As Integer = 0 To bytes.Length - 1
If j > 68 And j < 323 Then
Debug.WriteLine(String.Format("{0} {1}", j, Chr(bytes(j))))
Else
Debug.WriteLine(String.Format("{0} {1}", j, Convert.ToString(bytes(j), 16)))
End If
Next
End Function
End ClassThursday, April 24, 2008 1:16 AM -
Thanks again but I still have the same problem.
looking at the memory space occupied by the structure and when I step through the code, a reference is always placed in the structure on the execution of "OutboxItem.ucData = New Byte(254) {}". Then when ucData is loaded the contents is laced elsewhere, I assume at the reference location.
cheers...
Thats weird, the memory space pointed to by "OutboxItem" structure doesn't contain the loaded ucData but your test array "bytes" does!
Thursday, April 24, 2008 2:05 AM -
Ok Jo0ls
I have investigated your above code and stronly beleive the text data is not placed in the structure memory block. See a copy of the memory below.
Below is the memory block and as can be seen, byte 68 contains the LSB of a 4 byte address. When i go to this address, I find 8 bytes of header, what looks like another 4 byte reference, then 4 byte array length, then the contents of the array itself.
If I dimension then 255 byte array as individual bytes and then load the text data into each byte individually, then I see the text loaded into the correct location of the structure and the call to the DLL function works ok. Its a petty I can't find the correct way to do this in vb. For the moment I will have to stick to my long drawn out way to achieve my goal. Finding this solution has delay me long enough... but I would still like to know.
Thanks for your help anyway.
Code Snippet0x03C6F018 28 67 32 01 aa d2 00 00 00 00 00 00 00 00 00 00 (g2.ªÒ..........
0x03C6F028 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x03C6F038 db 07 00 00 64 00 f9 01 00 00 00 00 00 00 00 00 Û...d.ù.........
0x03C6F048 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 ................
0x03C6F058 09 00 b8 00 14 4e 5d 01 00 00 00 00 00 00 00 00 ..¸..N].........
0x03C6F068 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x03C6F078 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x03C6F088 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x03C6F098 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x03C6F0A8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x03C6F0B8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x03C6F0C8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x03C6F0D8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x03C6F0E8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x03C6F0F8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x03C6F108 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x03C6F118 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x03C6F128 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x03C6F138 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x03C6F148 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x03C6F158 00 00 00 00 01 00 00
0x015D4E14 e8 da 12 79 ff 00 00 00 01 47 6f 6f 64 20 6d 6f èÚ.yÿ....Good mo
0x015D4E24 72 6e 69 6e 67 20 65 76 65 72 79 6f 6e 65 21 00 rning everyone!.
0x015D4E34 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x015D4E44 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x015D4E54 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x015D4E64 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................Sunday, April 27, 2008 11:29 AM