dcsimg
Results 1 to 18 of 18

Thread: mapping data to structure

  1. #1

    Thread Starter
    Member
    Join Date
    Oct 2009
    Location
    Nijmegen, Netherlands
    Posts
    37

    Question mapping data to structure

    Hi, I'm working on a project to read data coming from a serial port. In the MSComm_OnComm event I collect all incoming data into InpBuf, global public declared as string. In another routine I extract the right amount of data I expect, e.g. 12 bytes, from this InpBuf.

    Question is how could I elegant map a string with binary data into a struct? Is there an way to use Lset? Or use CopyMemory routines? Belwo I used a routine 'Buf2Struct' to indicate what I want to achieve.

    Code:
    Option Explicit
    
    Private Type ScanData
      length As Integer
      start As Byte
      stop As Byte
      response As String * 8
    End Type
    
    Private Sub Command1_Click()
    Dim ScanInfo As ScanData, test As String
      test = Chr(0) & Chr(10) & Chr(5) & Chr(32) & "HELLO   " ' Just for testing 
      ScanInfo = Buf2Struct(test)
    End Sub
    
    Private Function Buf2Struct(inp As String) As ScanData
      With MapBuf2Struct
        .length = Asc(Mid(inp, 1, 2))
        .start = Asc(Mid(inp, 3, 1))
        .stop = Asc(Mid(inp, 4, 1))
        .response = Asc(Mid(inp, 5, 8))
      End With
    End Function

  2. #2
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    4,496

    Re: mapping data to structure

    Hi Wim,

    You're just wanting to copy some memory? LSet is certainly one way. However, it only works from one UDT (structure, User Defined Type) to another UDT. And ideally, they should be the same number of bytes. Also, in VB6, UDTs sometimes have some interesting internal padding. Roughly speaking, if you keep all the variables on a 4-byte boundary, normally there won't be any padding.

    Also, you'd have to wrap your byte array inside of a UDT to use LSet. That's probably not terribly difficult, but I'd tend to use other methods. If I were doing this, I'd immediately start thinking of the CopyMemory API call...

    Code:
    
    Public Declare Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" (ByRef Dest As Any, ByRef Source As Any, ByVal Bytes As Long)
    
    

    Now, notice it's "Destination", "Source", "Bytes". Destination is first.

    To use it with regular variables is trivial. For instance, if we have two Longs, and we want to copy them (rather than use an old-fashioned Let/assignment statement), we could do:

    Code:
    
    CopyMemory LongDest, LongSource, 4
    

    Let's say we have a Long array, and we wanted to copy the 5th element into the 2nd element. We could do...

    Code:
    
    CopyMemory LongArray(2), LongArray(5), 4
    

    Now, in those cases, it's sort of dumb to not just use a Let. However, when a Let isn't possible, that's where CopyMemory comes in very handy. You can also put the name of a UDT in the thing and that'll work too.

    The main caveat is that you MUST know how many bytes you wish to copy. With CopyMemory, it's trivial to start copying to/from memory that you shouldn't be messing with. You just must keep track of things.

    And just to say it, you'll also often see the VarPtr() function used with CopyMemory. When you do that, you must pass ByVal to keep the pointers straight. For example, in the first example above, I could have gone...

    Code:
    
    CopyMemory ByVal VarPtr(LongDest), ByVal VarPtr(LongSource), 4
    

    Or, I could have just done it to the source alone, or the destination alone. Sometimes we need to read (or write) data into a variable with an offset (such as writing into a Variant's structure). In these cases, we'll use ByVal VarPtr() + # type approach. But maybe that's more than you need right now.

    Good Luck,
    Elroy
    Last edited by Elroy; Aug 7th, 2018 at 01:47 PM.
    Any software I post in these forums written by me is provided “AS IS” without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. Please understand that I’ve been programming since the mid-1970s and still have some of that code. My contemporary VB6 project is approaching 1,000 modules. In addition, I have a “VB6 random code folder” that is overflowing. I’ve been at this long enough to truly not know with absolute certainty from whence every single line of my code has come, with much of it coming from programmers under my employ who signed intellectual property transfers. I have not deliberately attempted to remove any licenses and/or attributions from any software. If someone finds that I have inadvertently done so, I sincerely apologize, and, upon notice and reasonable proof, will re-attach those licenses and/or attributions. To all, peace and happiness.

  3. #3
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    4,496

    Re: mapping data to structure

    And say Wim,

    I just checked your UDT, and there's no internal padding in it. I've studied and written extensively about this UDT padding, but it's too strange to keep in my head. The LenB() function is your friend with these things. Here's how I did the test:

    Code:
    
    Option Explicit
    '
    Private Type ScanData
      length As Integer
      start As Byte
      stop As Byte
      response As String * 8
    End Type
    '
    
    Private Sub Form_Load()
    
        Dim u As ScanData
        Debug.Print LenB(u)     ' <--- reports 20.
    
    End Sub
    
    
    So, there's no padding. Integer = 2, Byte = 1 (times 2 for both of them), and String*8 = 16 (because it's Unicode). That adds up to 20.

    Good Luck,
    Elroy
    Any software I post in these forums written by me is provided “AS IS” without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. Please understand that I’ve been programming since the mid-1970s and still have some of that code. My contemporary VB6 project is approaching 1,000 modules. In addition, I have a “VB6 random code folder” that is overflowing. I’ve been at this long enough to truly not know with absolute certainty from whence every single line of my code has come, with much of it coming from programmers under my employ who signed intellectual property transfers. I have not deliberately attempted to remove any licenses and/or attributions from any software. If someone finds that I have inadvertently done so, I sincerely apologize, and, upon notice and reasonable proof, will re-attach those licenses and/or attributions. To all, peace and happiness.

  4. #4
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    17,440

    Re: mapping data to structure

    Quote Originally Posted by _Wim_ View Post
    Code:
    Private Sub Command1_Click()
    Dim ScanInfo As ScanData, test As String
      test = Chr(0) & Chr(10) & Chr(5) & Chr(32) & "HELLO   " ' Just for testing 
      ScanInfo = Buf2Struct(test)
    End Sub
    Part of the problem with the above is that you are building the string which is adding 2 bytes per character added. Therefore a straight CopyMemory, from the string, isn't really going to work for you because your UDT is 20 bytes and the "test" string is 24 bytes (12 'characters' at 2 bytes each).

    Edited: Another problem with above is that your "integer" is big-endian, not little endian. If you copy bytes 0 & 10, in that order, to an integer you get 2560 not 10. The way your are doing it by using Asc(Mid(input,2,1)) only works as long as the value you expect never exceeds 255. If it does, then the 1st byte will be non-zero and return an unexpected value for you.

    Maybe consider building the structure as the bytes come in from your comm port? or change your UDT to match your string?
    Last edited by LaVolpe; Aug 7th, 2018 at 03:16 PM.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  5. #5
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    4,496

    Re: mapping data to structure

    Ahhh, yes, and the following is also quite strange:

    Code:
    
    Asc(Mid(inp, 5, 8))
    
    This is only going to return a single number (an Integer). It's not designed to deal with several characters. The way it's written, it's going to evaluate the 5th character of inp, and then typecast that back to a String, completely losing the original bit-pattern.
    Any software I post in these forums written by me is provided “AS IS” without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. Please understand that I’ve been programming since the mid-1970s and still have some of that code. My contemporary VB6 project is approaching 1,000 modules. In addition, I have a “VB6 random code folder” that is overflowing. I’ve been at this long enough to truly not know with absolute certainty from whence every single line of my code has come, with much of it coming from programmers under my employ who signed intellectual property transfers. I have not deliberately attempted to remove any licenses and/or attributions from any software. If someone finds that I have inadvertently done so, I sincerely apologize, and, upon notice and reasonable proof, will re-attach those licenses and/or attributions. To all, peace and happiness.

  6. #6
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    17,440

    Re: mapping data to structure

    If filling this in on the fly, something like this is what I'm suggesting.

    We will use a couple of module/form level variables to help track
    Code:
    Private Type ScanData
      length As Integer
      start As Byte
      stop As Byte
      response As String * 8
    End Type
    
    Private m_myUDT As ScanData ' << filled on the fly
    Private m_BytePos As Long' << reset if/when necessary outside your comm routine
    air-code follows, comm routine
    Code:
        Dim n As Long
        
        ' as bytes come in, assumption is your buffer bInput() is byte array()?
        
        For n = 0 To UBound(bInput)
            m_BytePos= m_BytePos + 1
            Select Case m_BytePos
            Case 0: m_myUDT.length = bInput(n)
            Case 1
                ' note: if possible value can exceed max positive integer, rework next line
                m_myUDT.length = bInput(n) Or m_myUDT.length * &H100
            Case 2: m_myUDT.start = bInput(n)
            Case 3: m_myUDT.stop = bInput(n)
            Case Is < 12: Mid$(m_myUDT.response, m_BytePos - 3, 1) = Chr$(bInput(n))
            Case Else
                ' structure is filled, call whatever to process it
                ' then reset and continue on
                m_BytePos = 0
            End Select
        Next
    Last edited by LaVolpe; Aug 7th, 2018 at 03:24 PM. Reason: typos
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  7. #7

    Thread Starter
    Member
    Join Date
    Oct 2009
    Location
    Nijmegen, Netherlands
    Posts
    37

    Smile Re: mapping data to structure

    Asc(Mid(inp, 5, 8))
    Indeed that won't work... I was just quickly typing an example..
    But how about using CopyMemory? If I first convert my string to an array of bytes, then copy data from this array to the structure, overlaying whatever is in the array of bytes into the structure? Below code almost works.. After calling the routine:
    ScanInfo.length = 2560 (little endian, which is exactly what comes from my data stream!)
    ScanInfo.start=5, etc.
    Except ScanInfo.response is not a string. Probably need somewhere a StrConv(..., vbUnicode) to convert back to string. Also I realize that I can't have a string element in the middle of the structure. Probably I have to avoid using strings at all.

    But this CopyMemory seems to be promising for me! BTW if I understand correctly CopyMemory requires block lengths in multiple of 4? In this example it is either 20, or 12. Both complying, just 'accidently'.
    Thanks sofar.

    Code:
    Option Explicit
    
    Private Type ScanData
      length As Integer
      start As Byte
      stop As Byte
      response As String * 8
    End Type
    
    Private Declare Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" (ByRef Dest As Any, ByRef Source As Any, ByVal Bytes As Long)
    
    
    Private Sub Command1_Click()
    Dim ScanInfo As ScanData, test As String
      test = Chr(0) & Chr(10) & Chr(5) & Chr(32) & "HELLO   " ' Just for testing
      ScanInfo = Buf2Struct(test)
    End Sub
    
    Private Function Buf2Struct(inp As String) As ScanData
    Dim BytInp() As Byte, RetVal As ScanData
      BytInp = StrConv(inp, vbFromUnicode)
      CopyMemory ByVal VarPtr(RetVal), ByVal VarPtr(BytInp(0)), UBound(BytInp) + 1
      Buf2Struct = RetVal
    End Function

  8. #8
    PowerPoster
    Join Date
    Feb 2006
    Posts
    18,965

    Re: mapping data to structure

    First, use .InputMode = comInputModeBinary when you have binary data like this. Then the .Input property returns a Byte array with no risk of data distortion from being convert from ANSI to Unicode.

    Second, when you fetch the ANSI/ASCII data from a complete message onvert it to Unicode explicitly there.

    Third, your "integer" values may arrive in big-endian format depending on the remote platform and what the code there does. If so you need to be careful to swap the two bytes after extracting them from your stream assembly buffer.

    Fourth, the bytestreams sent via serial ports have no message boundaries. During any given OnComm event there might be 1 byte, 2, 3, ..., a whole message, one message and the start of another, etc. to be read via the .Input property call. This is why you need a stream assembly buffer.


    Each time you have a comEvReceive, append the value of .Input to the end of the buffer. Then process each whole message from the head of the buffer and remove it until the buffer is empty or only has a partial message remaining.

    You can implement such a buffer in a number of ways. With caution a String can hold byte data (that's why we have MidB$, LeftB$, etc.), or you might use a Byte array.

  9. #9

    Thread Starter
    Member
    Join Date
    Oct 2009
    Location
    Nijmegen, Netherlands
    Posts
    37

    Re: mapping data to structure

    Quote Originally Posted by dilettante View Post
    Each time you have a comEvReceive, append the value of .Input to the end of the buffer. Then process each whole message from the head of the buffer and remove it until the buffer is empty or only has a partial message remaining.
    That's precisely what I'm doing, and what I'm aware of using MsComm. The reason I'm using textmode as inputmode instead of binary, is because I find string handling easier than byte() arrays. Like copying part of the input buf e.g.
    Code:
          InpBuf = InpBuf & .Input ' within the OnComm event
    
    ' and process InpBuf elsewhere..
          response = Left(InpBuf, length) ' extract response from inpbuf
          InpBuf = Mid(InpBuf, length + 1) ' .. and strip it off the inpbuf
    And comparing if first 4 bytes of the response are equal target (declared as string!):
    Code:
    If Left(response, 4) = target Then ' check if command is as expected
    Using byte arrays I must use for.. next loops for each such action. Right, or are there easier ways?

  10. #10
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    17,440

    Re: mapping data to structure

    Quote Originally Posted by _Wim_ View Post
    But this CopyMemory seems to be promising for me! BTW if I understand correctly CopyMemory requires block lengths in multiple of 4? In this example it is either 20, or 1.

    ... The reason I'm using textmode as inputmode instead of binary, is because I find string handling easier than byte() arrays
    CopyMemory, as is, is not going to work for you as explained in post #4

    In post #6, there is a simple logic to populate the UDT structure and pass it off to some routine when it's fully populated.

    Byte arrays and For:Next loops are not difficult. Shying away from them because you have little experience isn't a good excuse IMO. If you stay with programming, you'll find they are so very useful and common.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  11. #11
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    4,496

    Re: mapping data to structure

    Quote Originally Posted by _Wim_ View Post
    CopyMemory requires block lengths in multiple of 4?
    Wim, just to jump in here a bit, your statement isn't correct. CopyMemory will copy however many bytes you specify. It's very precise about that.

    It's the UDTs that sometimes have padding, and require 4-byte offsets. However, as illustrated in post #3, your particular UDT doesn't have any padding.

    Now, I haven't studied your task in detail. However, as I see it, there are a couple of things you need to get straight, and to realize.

    1) There are many ways to copy memory. A simple Let/assignment (a = b) is one. LSet can do it when using two UDTs. Moving data between a String and a Byte array (possibly using StrConv()) is another. And there are many others. If you're wanting to keep things very fast-and-clean, you will attempt to copy/move your data as few times as possible.

    2) All VB6 Strings are stored in the UCS-2 character set. As such, they are all two-bytes-per-character. Realizing this, you recognize that there are some fundamental inefficiencies when frequently moving between a byte-array and a String. VB6 will constantly be expanding the byte-array to two-bytes-per-byte (or vice-versa) when moving between the two. If possible, you should avoid this except where absolutely needed (such as when you're actually going to print a string as a message to the user).

    3) All VB6 Integers and Longs are little-endian (in terms of bytes). If you have big-endian data, you can use CopyMemory to swap it around. This is one case where you'd need to use the VarPtr() function to set the second byte of an Integer (or possibly the 2nd, 3rd, & 4th bytes of a Long). I hesitate to mention them, but there are also GetMem1, GetMem2, GetMem4, & GetMem8 functions for use when you know you're copying either 1,2,4, or 8 bytes of memory, and they're faster than CopyMemory. Ask, and I'll (or someone) will post the declarations for them.

    Also, let me just also mention that LaVolpe knows his stuff, and Dilettante does too.

    Good Luck With It,
    Elroy
    Any software I post in these forums written by me is provided “AS IS” without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. Please understand that I’ve been programming since the mid-1970s and still have some of that code. My contemporary VB6 project is approaching 1,000 modules. In addition, I have a “VB6 random code folder” that is overflowing. I’ve been at this long enough to truly not know with absolute certainty from whence every single line of my code has come, with much of it coming from programmers under my employ who signed intellectual property transfers. I have not deliberately attempted to remove any licenses and/or attributions from any software. If someone finds that I have inadvertently done so, I sincerely apologize, and, upon notice and reasonable proof, will re-attach those licenses and/or attributions. To all, peace and happiness.

  12. #12
    PowerPoster
    Join Date
    Feb 2006
    Posts
    18,965

    Re: mapping data to structure

    Quote Originally Posted by _Wim_ View Post
    The reason I'm using textmode as inputmode instead of binary, is because I find string handling easier than byte() arrays. Like copying part of the input buf...

    ...or are there easier ways?
    Sure and most of them have been discussed here, samples posted in the CodeBank, etc. for two decades.

    Here's an example.

    The demo code here makes use of a class that employs such techniques. This one was written to append to the end of the buffer, grab things at "location for length" as Bytes, converted to a Unicode String, or as an Integer, and drop bytes off the head of the buffer.

    Code:
    Option Explicit
    
    Private Declare Sub PutMem2 Lib "msvbvm60" (ByRef Dest As Any, ByVal NewVal As Integer)
    
    Public Function ToHex(ByRef Bytes() As Byte) As String
        Const HexDigits As String = "0123456789ABCDEF"
        Dim HexValue As String
        Dim I As Long
        
        HexValue = Space$((UBound(Bytes) + 1) * 3)
        For I = 0 To UBound(Bytes)
            Mid$(HexValue, I * 3 + 1, 2) = Mid$(HexDigits, CLng(Bytes(I)) \ &H10& + 1, 1) _
                                         & Mid$(HexDigits, CLng(Bytes(I)) Mod &H10& + 1, 1)
        Next
        ToHex = HexValue
    End Function
    
    Private Sub Form_Load()
        Dim Bytes() As Byte
    
        With New ByteString
            ReDim Bytes(0 To 1)
            PutMem2 Bytes(0), 258
            .Cat Bytes
            ReDim Preserve Bytes(0)
            .Cat Bytes
            .Cat Bytes
            Bytes = StrConv("AAbb", vbFromUnicode)
            .Cat Bytes
            Bytes = StrConv("ÿÿÿÿÿÿ", vbFromUnicode)
            .Cat Bytes
    
            Print "Length = "; .Length
            Print "Value = "; ToHex(.Value)
            Print
            Print "IntegerAt(1) = "; .IntegerAt(1)
            Print "ByteAt(3) = "; .ByteAt(3)
            Print "ByteAt(4) = "; .ByteAt(4)
            Print "StringAt(5, 4) = "; .StringAt(5, 4)
            Print
            .Drop 8
            Print "Length = "; .Length
            Print "Value = "; ToHex(.Value)
        End With
    End Sub

    Name:  sshot.png
Views: 52
Size:  2.6 KB
    Attached Files Attached Files
    Last edited by dilettante; Aug 8th, 2018 at 11:16 PM.

  13. #13

    Thread Starter
    Member
    Join Date
    Oct 2009
    Location
    Nijmegen, Netherlands
    Posts
    37

    Re: mapping data to structure

    Thanks all for your replies... as for the topic, mapping data to a struct, I'm done. I use the CopyMemery method with success, I'm not using strings in the struct. As for little/big endian, I yet have to find out, but it seems that the device I'm working with (BLED112 Bluetooth dongle) spits out a uint16 number as 2 bytes in the right order as VB6 expects an integer.

    As far as the use of binary mode for MsComm, I'm still unsure how to work with array of bytes. There are quite some topics on various forums on this subject, but still unable to grasp how to implement. I understand that its not very efficient to use textmode if VB has to convert back and forward between 1 byte or 2 bytes per character. For this specific project I'm working on (interfacing with a Bluetooth dongle), the fist phase in communication is slow anyhow: discovering my advertising application. Sofar I can succesfully discover and see the advertising scan response data from my application.

    However later on I need to transfer lots of data, wireless, so binary mode might be better alternative. But last night I tried to convert my current OnComm routine to use binarymode, but couldn't figure out to write code with InpBuf (global) declared as array of bytes.

    This is my current code:
    Code:
    Private Sub MSComm_OnComm()
    ''' Event handler for the serial port. Any character received is added to a buffer
      With MSComm
        If .CommEvent = comEvReceive Then ' Received RThreshold number of chars
          Do
            InpBuf = InpBuf & .Input
          Loop While .InBufferCount > 0
        Else
          AddLog "Unexpected serial port event!"
        End If
      End With
    End Sub
    I don't want to start a rathole here, nor want to offend anybody, but using string functions in VB6 seems so much easier for me, and since my programs are only used for demo or test purposes, efficiency is not my priority...

  14. #14

    Thread Starter
    Member
    Join Date
    Oct 2009
    Location
    Nijmegen, Netherlands
    Posts
    37

    Re: mapping data to structure

    @Elroy:
    I believe I have problems with one structure, with this padding thing you mentioned.. These are the 4 structs I use, and LenB() of each gives me unexpected results on the last one.

    Code:
    Public Type ScanResponse 'pg129
      rssi As Byte
      packtype As Byte
      sender(5) As Byte
      addrtype As Byte
      bond As Byte
      len As Byte ' Length of actual ScanResponse in data
      data(116) As Byte ' fill up this struct up to 128
    End Type
    Public UDTScanResponse As ScanResponse
    
    Public Type Connection_status 'pg98
      connection As Byte
      flags As Byte
      address(5) As Byte
      conn_interval As Integer
      timeout As Integer
      latency As Integer
      bonding As Byte
    End Type
    Public UDTConnStatus As Connection_status
    
    Public Type Find_Information_found ' pg66
      connection As Byte
      HandleLSB As Byte
      HandleMSB As Byte
      uuidLen As Byte
      uuid(2) As Byte
    End Type
    Public UDTuuid(100) As Find_Information_found
    
    Public Type msg_attclient_attribute_value ' pg65
      hilen As Byte
      lolen As Byte
      class As Byte
      method As Byte
      connection As Byte
    '  atthandleLSB As Byte 'Integer
    '  atthandleMSB As Byte
      atthandle As Integer
      atttype As Byte
      attlen As Byte
      attdata(100) As Byte
    End Type
    Public UDTAttMessage As msg_attclient_attribute_value
    ? lenb(UDTScanResponse)
    128
    ? lenb(UDTConnStatus)
    16
    ? lenb(UDTuuid(0))
    7
    ? lenb(UDTAttMessage)
    112 --> 2 bytes too much

    If I change the integer to two bytes, then:
    ? lenb(UDTAttMessage)
    110 --> OK

    So how/where should I pad? I guess integer should be on 2 or 4 byte boundarie? So is there a solution, or shall I use the workaround, and define an integer as two bytes?
    BTW, I use this to copy th response to the UDT variable. (First 4 bytes skipped)
    Code:
    CopyMemory ByVal VarPtr(UDTAttMessage), ByVal VarPtr(BytArr(4)), LenB(UDTAttMessage) ' UDTAttMessage holds data returnde from application

  15. #15
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    4,496

    Re: mapping data to structure

    Hi Wim,

    I've written about that padding before, but it's a bit strange to keep it in my head. However, here's something you can do to "see" it.

    Code:
    
    Option Explicit
    '
    Private Type msg_attclient_attribute_value ' pg65
      hilen As Byte
      lolen As Byte
      class As Byte
      method As Byte
      connection As Byte
    '  atthandleLSB As Byte 'Integer
    '  atthandleMSB As Byte
      atthandle As Integer
      atttype As Byte
      attlen As Byte
      attdata(100) As Byte
    End Type
    
    Private Sub Form_Click()
        Dim u As msg_attclient_attribute_value
    
    
        Debug.Print "Memory Start and Offsets: "; VarPtr(u)
        Debug.Print "hilen:       "; VarPtr(u.hilen) - VarPtr(u)
        Debug.Print "lolen:       "; VarPtr(u.lolen) - VarPtr(u)
        Debug.Print "class:       "; VarPtr(u.class) - VarPtr(u)
        Debug.Print "method:      "; VarPtr(u.method) - VarPtr(u)
        Debug.Print "connection:  "; VarPtr(u.connection) - VarPtr(u)
        Debug.Print "atthandle:   "; VarPtr(u.atthandle) - VarPtr(u)
        Debug.Print "atttype:     "; VarPtr(u.atttype) - VarPtr(u)
        Debug.Print "attlen:      "; VarPtr(u.attlen) - VarPtr(u)
        Debug.Print "attdata(0):  "; VarPtr(u.attdata(0)) - VarPtr(u)
    
    
    End Sub
    
    

    If we study that, we'll see that there's a byte of padding between connection and atthandle. That method (shown) should always give you a way to identify where padding is taking place. I suspect that's why those items are commented between ... you were probably trying to figure out what was going on.

    Hope That Helps,
    Elroy

    EDIT1: Just FYI, the output from the above:

    Code:
    Memory Start and Offsets:  1701688 
    hilen:        0 
    lolen:        1 
    class:        2 
    method:       3 
    connection:   4 
    atthandle:    6 
    atttype:      8 
    attlen:       9 
    attdata(0):   10
    Last edited by Elroy; Yesterday at 08:54 AM.
    Any software I post in these forums written by me is provided “AS IS” without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. Please understand that I’ve been programming since the mid-1970s and still have some of that code. My contemporary VB6 project is approaching 1,000 modules. In addition, I have a “VB6 random code folder” that is overflowing. I’ve been at this long enough to truly not know with absolute certainty from whence every single line of my code has come, with much of it coming from programmers under my employ who signed intellectual property transfers. I have not deliberately attempted to remove any licenses and/or attributions from any software. If someone finds that I have inadvertently done so, I sincerely apologize, and, upon notice and reasonable proof, will re-attach those licenses and/or attributions. To all, peace and happiness.

  16. #16
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    4,496

    Re: mapping data to structure

    And Wim, here's a page that does a pretty good job of explaining the VB6 structure (UDT) padding.
    Any software I post in these forums written by me is provided “AS IS” without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. Please understand that I’ve been programming since the mid-1970s and still have some of that code. My contemporary VB6 project is approaching 1,000 modules. In addition, I have a “VB6 random code folder” that is overflowing. I’ve been at this long enough to truly not know with absolute certainty from whence every single line of my code has come, with much of it coming from programmers under my employ who signed intellectual property transfers. I have not deliberately attempted to remove any licenses and/or attributions from any software. If someone finds that I have inadvertently done so, I sincerely apologize, and, upon notice and reasonable proof, will re-attach those licenses and/or attributions. To all, peace and happiness.

  17. #17

    Thread Starter
    Member
    Join Date
    Oct 2009
    Location
    Nijmegen, Netherlands
    Posts
    37

    Re: mapping data to structure

    Ahh thanks Elroy, this makes it clear. I guess I was 'lucky' with the first 3 structs, but the last gave me indeed strange results after using CopyMemory.
    So this padding happens internally in memory. I guess my workaround I already tried (replacing the integer with two bytes), is the only solution. Actually I probably have to do this anyhow, because the Endianess is different from what I expected. Then 'assembling' the integer is then a matter of:

    IntValue = 256*UDTAttMessage.AttHandleMSB + UDTAttMessage.AttHandleLSB


    But now I understand were the extra 'bytes' are coming from. Thanks again.
    _Wim_

  18. #18
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    4,496

    Re: mapping data to structure

    Wim, I typically correct Endianness problems still using CopyMemory, I just copy one-byte-at-a-time, putting the bytes in the correct order. Just saying.
    Any software I post in these forums written by me is provided “AS IS” without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. Please understand that I’ve been programming since the mid-1970s and still have some of that code. My contemporary VB6 project is approaching 1,000 modules. In addition, I have a “VB6 random code folder” that is overflowing. I’ve been at this long enough to truly not know with absolute certainty from whence every single line of my code has come, with much of it coming from programmers under my employ who signed intellectual property transfers. I have not deliberately attempted to remove any licenses and/or attributions from any software. If someone finds that I have inadvertently done so, I sincerely apologize, and, upon notice and reasonable proof, will re-attach those licenses and/or attributions. To all, peace and happiness.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Featured


Click Here to Expand Forum to Full Width