locked
Initialising structures with byte arrays RRS feed

  • 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 Snippet

    Code 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 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 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 = &H0

    OutboxItem.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 UInt16

    OutboxItem.ucData(0) = &H1

    For i = 0 To CUShort(CUInt(text.Length - 1))

    OutboxItem.ucData(i + 1) = CByte(Asc(text(i)))

    Next

     

    '-- Send data to OutBox and return response

    Return ApiSdsOutboxWriteSdsItem(OutboxItem)

    End Function

     

     

     

     

    Wednesday, 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 Structure



    Wednesday, 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 Snippet
    Imports 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
    Class



    Thursday, 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 Snippet

    0x03C6F018  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