Results 1 to 18 of 18

Thread: Dynamic change of a structure length inside a function

  1. #1

    Thread Starter
    Member
    Join Date
    Dec 2009
    Location
    Germany
    Posts
    47

    Dynamic change of a structure length inside a function

    Example declarations:
    Code:
    Private Type SUB_STRUCTURE
      SubMember1(15) As Byte
      SubMember2     As LARGE_INTEGER
      SubMember3     As LARGE_INTEGER
      SubMember4     As Long
    End Type
      
    Private Type STRUCTURE
      Member1    As Long
      Member2    As Long
      Member3    As SUB_STRUCTURE
      PadMember4 As Long
    ' static array size
      Member5(287) As Byte
    End Type
    In a function:
    Dim test As STRUCTURE
    MsgBox Len(test) ' it's "336" here

    For a specific DeviceIO-ControlCode I want to call, this length may be too small and causes an ERROR_INSUFFICIENT_BUFFER ("ErrNr. 122).
    So, i'm in need to redim Member5 dynamically in a way that length of variable "test" (length of STRUCTURE) also changes.

    I tried to declare the structure as follows:
    Code:
    Private Type STRUCTURE
      Member1    As Long
      Member2    As Long
      Member3    As SUB_STRUCTURE
      PadMember4 As Long
      Member5()  As Byte
    End Type
    In a function:
    Dim test As STRUCTURE
    MsgBox Len(test) ' it's "52" here
    ReDim test.Member5(287)
    MsgBox Len(test) ' still obviously "52" but should become at least 336


    I hope my problem was explained in a sufficient way.

    Thanks for any reply.

  2. #2
    Hyperactive Member
    Join Date
    Aug 2017
    Posts
    380

    Re: Dynamic change of a structure length inside a function

    Unfortunately, VB6 does not support variable-length structures. The typical workaround for this is to just simply make the structure as large as possible. However, keep in mind that VB6 limits UDTs to just 64 KB, so if the API needs more buffer space, you'll have to resort to other means (e.g., String, Byte array or your own allocated memory).

  3. #3
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: Dynamic change of a structure length inside a function

    At least three options I can think of right off

    1. As mentioned by Victor Bravo VI, oversize the member structure

    2. Use a byte array, but get a bit creative and test well...
    Edited: Approach below only works well if the last member is to be dynamic
    Code:
    Private Type STRUCTURE
      Member1    As Long
      Member2    As Long
      Member3    As SUB_STRUCTURE
      PadMember4 As Long
    ' static array size
      Member5(287) As Byte
    End Type
    
    ' /////////// Air-Code follows for test function
    
    ' dynamically sized, add another 1024 bytes to the final member
    Dim bStructure() As Byte, lSize As Long
    Dim uUDT As STRUCTURE
    
    ' fill in the structure then
    lSize = LenB(uUDT)
    ReDim bStructure(0 To lSize + 1023) ' add another 1024 bytes
    CopyMemory bStructure(0), uUDT, lSize
    
    ' pass to the API the address of bStructure(0)
    
    ' now if needed, you can copy from the byte array back to your uUDT variable, but only lSize in bytes
    ' uUDT.Member5 will still be 288 bytes.  But from that member's memory address there are actually 288+1024 bytes
    '   don't know if Member5 is string data or something else. If string data, it is doable to extract just those 288+1024 bytes to a string
    3. Create multiple versions of your structure. Many that use GDI are accustomed to this when declaring BitmapInfo and OSVersion structures
    Last edited by LaVolpe; Apr 18th, 2018 at 07:18 AM.
    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}

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

    Re: Dynamic change of a structure length inside a function

    Also, Zphere, you should get into the habit of using LenB() with your UDTs rather than Len(). They will often return the same thing. However, when they don't, you almost always want the value that LenB() returns rather than the value for Len(). There are a couple of different reasons they may be different, but I won't go into them here.

    And yeah, VB6 UDTs are rather completely resolved when compiled by VB6, which means there's no "dynamic" way to change their size. However, you've been given excellent work-arounds.

    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. To all, peace and happiness.

  5. #5

    Thread Starter
    Member
    Join Date
    Dec 2009
    Location
    Germany
    Posts
    47

    Re: Dynamic change of a structure length inside a function

    At first, a big thanks to all of you
    (In hope my english is good enough...)


    Victor Bravo VI:
    Clear answer to my initial problem (as it was posted). Thanks also for the reference.

    To be honest, at least I don't need this structure because I was able to read out all information by dimming a byte array with desired (or needed) size and passed this to the specific IOCTL-Function.
    Via Do...Loop While lRet = 0 And Err.LastDllError = 122 I simply resized the byte array before passing it again to the IOCTL-function.
    By looping through the byte array data, I've been able to find all offsets and length for each of the members from the data structure shown in my example.
    I was just curious and wanted to know if I could extract all info by declaring a structure in the declaration area of a module or a cls that can be resized.

    LaVolpe:
    I can follow your code of option 2 and it seems very clever to me.
    Indeed, we're talking about the last member only. But, the byte array contains not only string data.
    Moreover, numeric values must be extracted of datatype Long, Double or largeInteger.

    Option 3 sounds somehow funky - it would never came into my mind till you mentioned it. I'm curious to try this option.

    Elroy:
    Thanks for mention the Len/LenB issue ..behaviour changed

    After reading your suggestions, no use of a declared structure but usage of a byte array (as described above) dimmed inside a function seems to be the best choice.?
    Drawback is that I need sub-functions or subs to retrieve the appropriate byte sequences of this array and to convert data into the appropriate data type.
    Last edited by Zphere; Apr 20th, 2018 at 12:35 AM.

  6. #6
    Hyperactive Member
    Join Date
    Aug 2017
    Posts
    380

    Re: Dynamic change of a structure length inside a function

    Quote Originally Posted by Zphere View Post
    By looping through the byte array data, I've been able to find all offsets and length for each of the members from the data structure shown in my example.

    . . .

    Drawback is that I need sub-functions or subs to retrieve the appropriate byte sequences of this array and to convert data into the appropriate data type.
    There are a number of techniques that you can utilize to typecast your Byte array to any desired UDT. LaVolpe showed one such approach and here's another one. This method uses the CallWindowProc API function to perform typecasting (you could also use the DispCallFunc API if you want to do it in an Object module [.FRM, .CLS, .CTL, etc.]). The advantages of this technique are reduced memory usage and possibly faster execution especially when the structure is large.

    Code:
    Option Explicit     'In a standard (.BAS) module
    
    Private Declare Function CallWindowProcW Lib "user32.dll" (ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    
    Private Type UDT
        cbSize As Long
        Buffer As Byte
    End Type
    
    Private Sub Foo()
        Dim Buffer(0& To &HFFFF&) As Byte
    
       'This will cast the Buffer() Byte array to a UDT structure. Pass the buffer size as well.
        CallWindowProcW AddressOf Bar, VarPtr(Buffer(0&)), &H10000, 0&, 0&
    End Sub
    
    Private Function Bar(ByRef U As UDT, ByVal BufferSize As Long, ByVal Reserved1 As Long, ByVal Reserved2 As Long) As Long
    
       'The parameter U now occupies the same memory as the Buffer() variable in Sub Foo()
       'Any changes in U's members will be reflected in the Buffer() variable and vice versa
    
        U.cbSize = BufferSize
    
       'Call the API here and pass the UDT
    End Function

    EDIT

    Another possible solution that you could try is the SAFEARRAY method where you manipulate an array so that its elements overlays arbitrary memory locations.
    Last edited by Victor Bravo VI; Apr 18th, 2018 at 02:50 PM.

  7. #7
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,817

    Re: Dynamic change of a structure length inside a function

    Hi Zphere,

    I suppose I'll say a bit more. After re-reading your initial post, I see that you tried to use a dynamic array in your UDT (structure). There are certain things that, when placed in a UDT, only place a four-byte address in the UDT. The most obvious examples are Objects, variable length (BSTR) Strings, and Dynamic Arrays. In other words, for any kind of device I/O, these aren't going to work. That was your initial problem.

    I'm assuming that the size of this UDT (structure) is determined by certain fields in its header. If it were me, I'd use a Byte array, just as you apparently have.

    And then, I'd start using CopyMemory to move it into a UDT that was more convenient for me. In fact, if done correctly, after the data is read into your byte array, you could then use Dynamic Arrays. Here's an API declaration for it:

    Code:
    
    Private Declare Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" (ByRef destination As Any, ByRef source As Any, ByVal length As Long)
    
    Be sure to notice that destination is first, and then source.

    Let's say we'd like to move 8 bytes, starting at bb(12) of your Byte array, and you'd like to move this into a variable named SomeIeeeDouble. We could do something like the following:

    Code:
    
        CopyMemory SomeIeeeDouble, bb(12), 8
    
    Using those ideas, we could read our byte array, snoop around in it to figure out how large the Dynamic Array should be in our UDT, dimension this Dynamic Array, and then use the first (or whatever) element of this dynamic array as a destination (using some spot in our byte array as a source).

    Maybe that'll help.

    Elroy

    EDIT1: Just as a further FYI, there's no problem using the specific elements of a UDT as either the source or destination for CopyMemory. Or even specific elements within an array. Or both.
    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. To all, peace and happiness.

  8. #8

    Thread Starter
    Member
    Join Date
    Dec 2009
    Location
    Germany
    Posts
    47

    Re: Dynamic change of a structure length inside a function

    Very, very interesting Victor Bravo VI.
    This is new to me, I will test this.

    I'm shifting away from my initial question I know,
    but at first I would like to refer to Elroys approach.
    Elroy, let's say I initialised an array to a sufficient size.

    CLS: declaration area
    Code:
    Option Explicit
    
      ' Yes, in real I already use a UDT
    private Type UDTSub
      subMember1    As string
      subMember2    As string
      subMember3    As string
    end type
    
    Private Type UDT
      Member1    As string
      Member2    As string
      Member3    As string
      Member4    as string
      subMembers ()  as UDTSub
    End Type
    private DD as UDT
    In a function:
    Code:
    Friend Function Test() as Boolean
    Redim DD(0): Redim DD(0).subMembers(0)
    
    ' in this example the array is oversized and assumes! a needed length
    Dim DATA(18479) as byte
    
    ' DeviceHandle is known
      If DevIOCTL( _
        HDev, ANY_IOCTL_CONTROL_CODE, _
        ByVal 0&, 0&, ByVal VarPtr(DATA(0)), _
        Ubound(DATA), 0&, ByVal 0&) = 0 _
      Then
        ' error handling here
      Else
        Test=True
    
        ' To retrieve data from the 1st and 2nd Member 
        ' (both of long if a structure would be used - see my initial example)
        ' I use the following "universal" function to pass values directly to my UDT
        With DD(0)
          .Member1 = BytesToNumEx(Data, 0, 3)
          .Member2 = BytesToNumEx(Data, 4, 7)
         ...
        End With
      EndIf
    End Function
    
    Private Function BytesToNumEx(ByteArray() As Byte, StartRec As Long, EndRec As Long, Optional UnSigned As Boolean) As Double
    ' All credits to the Author: Imran Zaheer - http://www.freevbcode.com/ShowCode.asp?ID=1006
    Dim i                As Integer
    Dim lng256      As Double
    Dim lngReturn As Double
    
    On Error GoTo ExFkt
    lng256 = 1
    lngReturn = 0
    
    If EndRec < 1 Then EndRec = UBound(ByteArray)
    If StartRec > EndRec Or StartRec < 0 Then GoTo ExFkt
    
    lngReturn = lngReturn + (ByteArray(StartRec))
    For i = (StartRec + 1) To EndRec
      lng256 = lng256 * 256
      If i < EndRec Then
        lngReturn = lngReturn + (ByteArray(i) * lng256)
      Else
      ' if -ve
        If ByteArray(i) > 127 And UnSigned = False Then
          lngReturn = (lngReturn + ((ByteArray(i) - 256) * lng256))
        Else
          lngReturn = lngReturn + (ByteArray(i) * lng256)
        End If
      End If
    Next i
    BytesToNumEx = lngReturn
    Exit Function
    ExFkt:
    BytesToNumEx = -1
    Err.Clear
    End Function
    I'm not familar with CopyMemory. Where could it come into play here?
    Regarding your "tip", am I understanding right that here CopyMemory helps to copy a byte sequence
    into memory that will be available by the OutVariable (first parameter)?
    If so, I could replace the first parts of BytesToNumEx (setting the byte array sequence)
    with CopyMemory.?
    Last edited by Zphere; Apr 20th, 2018 at 12:37 AM.

  9. #9
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,817

    Re: Dynamic change of a structure length inside a function

    Hi Zphere,

    Ok, first, recognize that those strings in your UDTs are also only going to be memory-address-pointers. The strings themselves are actually not in the UDT.

    Rather than try and sort out what you're doing, let me mock up a little example of what I'm talking about. When I get it mocked up, I'll post it as another post.

    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. To all, peace and happiness.

  10. #10
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,817

    Re: Dynamic change of a structure length inside a function

    Here we go.

    This stuff can get involved, especially appreciating that VB6 stores strings as Unicode. I assumed any incoming string would be ASCII.

    Here's just an example. To test, throw it into Form1, and play. The MakeRandomDataStream is just a mock-up of some data with a known (but variable length) structure.

    Code:
    
    Option Explicit
    '
    Private Declare Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" (ByRef destination As Any, ByRef source As Any, ByVal length As Long)
    '
    ' Ok, for grins, I've assumed we have incoming data of variable length.
    ' However, we know that it has a certain structure:
    '   First, it will have a Long data #1 length, with the data representing a string(ASCII).
    '   The ASCII String data will follow the length.
    '   Next, it will have a Long data #2 length, with the data representing Bytes.
    '   The Byte data will follow the length.
    '   Next, it will just have two values at the end, one a Double and the second a Long.
    '
    ' We'll also assume the whole thing is never longer than 1000 bytes (actually less).
    '
    Private Type MyUdtType
        Data1Len As Long
        MyString As String
        Data2Len As Long
        MyBytes() As Byte
        MyValue3 As Double
        MyValue4 As Long
    End Type
    '
    
    
    
    
    
    Private Sub Form_Load()
        GetParseAndShowData
    End Sub
    
    Private Sub Form_Click()
        GetParseAndShowData
    End Sub
    
    Private Sub GetParseAndShowData()
        Dim bbIn() As Byte      ' This will be my input data stream.
        Dim bbTemp() As Byte
    
    
        bbIn = MakeRandomDataStream
        '
        ' Now, let's parse our data and make it "pretty".
        Dim MyUdt As MyUdtType
        '
        ' The string length (ASCII) and the string.
        CopyMemory MyUdt.Data1Len, bbIn(1), 4                                               ' Get the string length.
        ReDim bbTemp(1 To MyUdt.Data1Len)
        CopyMemory bbTemp(1), bbIn(1 + 4), MyUdt.Data1Len                                   ' Get string into bbTemp.
        MyUdt.MyString = StrConv(bbTemp, vbUnicode)                                         ' Make a Unicode VB6 string.
        '
        ' The bytes length and the bytes.
        CopyMemory MyUdt.Data2Len, bbIn(1 + 4 + MyUdt.Data1Len), 4                          ' Get the Bytes length.
        ReDim MyUdt.MyBytes(1 To MyUdt.Data2Len)                                            ' Make bytes space.
        CopyMemory MyUdt.MyBytes(1), bbIn(1 + 4 + MyUdt.Data1Len + 4), MyUdt.Data2Len       ' Get bytes.
        '
        ' And finally the last two values.
        CopyMemory MyUdt.MyValue3, bbIn(1 + 4 + MyUdt.Data1Len + 4 + MyUdt.Data2Len), 8
        CopyMemory MyUdt.MyValue4, bbIn(1 + 4 + MyUdt.Data1Len + 4 + MyUdt.Data2Len + 8), 4
    
    
    
        '
        ' And let's see what we got.
    
        Debug.Print "------------------------------"
        Debug.Print MyUdt.Data1Len, MyUdt.MyString
        Debug.Print MyUdt.Data2Len, StrConv(MyUdt.MyBytes, vbUnicode)   ' Convert the bytes to Unicode for printing.
        Debug.Print MyUdt.MyValue3
        Debug.Print MyUdt.MyValue4
        Debug.Print "------------------------------"
    
    
    
    End Sub
    
    Private Function MakeRandomDataStream() As Byte()
        Dim i1 As Long
        Dim i2 As Long
        Dim j As Long
        Dim bbData1() As Byte
        Dim bbData2() As Byte
        Dim bbOut() As Byte
        Dim Value3 As Double
        Dim Value4 As Long
        '
        Randomize
        '
        ' Some random string.
        ' But let's keep it simple and assume they're ASCII characters.
        i1 = Int(Rnd * 100 + 1)  ' A number between 1 and 100.
        ReDim bbData1(1 To i1)
        For j = 1 To i1
            bbData1(j) = Int(26 * Rnd + 65)      ' ASCII values for letters between A and Z.
        Next j
        '
        ' This time, some random collection of bytes, seen as bytes.
        i2 = Int(Rnd * 100 + 1)  ' A number between 1 and 100.
        ReDim bbData2(1 To i2)
        For j = 1 To i2
            bbData2(j) = Int(26 * Rnd + 65)      ' ASCII values for letters between A and Z.
        Next j
        '
        ' Make last two values.
        Value3 = Rnd * 10000# + 1#          ' Some value between 1 and 10000.
        Value4 = Int(Rnd * 10000@ + 1@)     ' Some integer (Long) between 1 and 10000.
        '
        ' And now we'll use CopyMemory to shove it into our Random Data Stream.
        ' Zphere, I assume you will be reading this from some other source.
        '
        ReDim bbOut(1 To (4 + i1 + 4 + i2 + 8 + 4))  ' Long, String[i1,ASCII], Long, Bytes[i2], Double, Long.
        '
        CopyMemory bbOut(1), i1, 4                              ' Length of string.
        CopyMemory bbOut(1 + 4), bbData1(1), i1                 ' The ASCII string.
        CopyMemory bbOut(1 + 4 + i1), i2, 4                     ' Length of bytes.
        CopyMemory bbOut(1 + 4 + i1 + 4), bbData2(1), i2        ' The bytes.
        CopyMemory bbOut(1 + 4 + i1 + 4 + i2), Value3, 8        ' First value at end.
        CopyMemory bbOut(1 + 4 + i1 + 4 + i2 + 8), Value4, 4    ' Second value at end.
    
    
        MakeRandomDataStream = bbOut
    
    End Function
    
    
    Enjoy,
    Elroy

    EDIT1: If I were actually doing this for production, I'd probably make a pointer into bbIn() that kept track of where we were, rather than just letting the expression get longer and longer.

    EDIT2: It was bugging me so I added a lBufPtr (buffer pointer):

    Code:
    
    Option Explicit
    '
    Private Declare Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" (ByRef destination As Any, ByRef source As Any, ByVal length As Long)
    '
    ' Ok, for grins, I've assumed we have incoming data of variable length.
    ' However, we know that it has a certain structure:
    '   First, it will have a Long data #1 length, with the data representing a string(ASCII).
    '   The ASCII String data will follow the length.
    '   Next, it will have a Long data #2 length, with the data representing Bytes.
    '   The Byte data will follow the length.
    '   Next, it will just have two values at the end, one a Double and the second a Long.
    '
    ' We'll also assume the whole thing is never longer than 1000 bytes (actually less).
    '
    Private Type MyUdtType
        Data1Len As Long
        MyString As String
        Data2Len As Long
        MyBytes() As Byte
        MyValue3 As Double
        MyValue4 As Long
    End Type
    '
    
    
    
    
    
    Private Sub Form_Load()
        GetParseAndShowData
    End Sub
    
    Private Sub Form_Click()
        GetParseAndShowData
    End Sub
    
    Private Sub GetParseAndShowData()
        Dim bbIn() As Byte      ' This will be my input data stream.
        Dim bbTemp() As Byte
        Dim lBufPtr As Long
    
        bbIn = MakeRandomDataStream
        '
        ' Now, let's parse our data and make it "pretty".
        Dim MyUdt As MyUdtType
        lBufPtr = 1                                                         ' Start buffer pointer.
        '
        ' The string length (ASCII) and the string.
        CopyMemory MyUdt.Data1Len, bbIn(lBufPtr), 4                         ' Get the string length.
        lBufPtr = lBufPtr + 4                                               ' Move buffer pointer.
        ReDim bbTemp(1 To MyUdt.Data1Len)
        CopyMemory bbTemp(1), bbIn(lBufPtr), MyUdt.Data1Len                 ' Get string into bbTemp.
        lBufPtr = lBufPtr + MyUdt.Data1Len                                  ' Move buffer pointer.
        MyUdt.MyString = StrConv(bbTemp, vbUnicode)                         ' Make a Unicode VB6 string.
        '
        ' The bytes length and the bytes.
        CopyMemory MyUdt.Data2Len, bbIn(lBufPtr), 4                         ' Get the Bytes length.
        lBufPtr = lBufPtr + 4                                               ' Move buffer pointer.
        ReDim MyUdt.MyBytes(1 To MyUdt.Data2Len)                            ' Make bytes space.
        CopyMemory MyUdt.MyBytes(1), bbIn(lBufPtr), MyUdt.Data2Len          ' Get bytes.
        lBufPtr = lBufPtr + MyUdt.Data2Len                                  ' Move buffer pointer.
        '
        ' And finally the last two values.
        CopyMemory MyUdt.MyValue3, bbIn(lBufPtr), 8
        lBufPtr = lBufPtr + 8                                               ' Move buffer pointer.
        CopyMemory MyUdt.MyValue4, bbIn(lBufPtr), 4
        lBufPtr = lBufPtr + 4                                               ' No need for this one, but hey ho.
    
    
    
        '
        ' And let's see what we got.
    
        Debug.Print "------------------------------"
        Debug.Print MyUdt.Data1Len, MyUdt.MyString
        Debug.Print MyUdt.Data2Len, StrConv(MyUdt.MyBytes, vbUnicode)   ' Convert the bytes to Unicode for printing.
        Debug.Print MyUdt.MyValue3
        Debug.Print MyUdt.MyValue4
        Debug.Print "------------------------------"
    
    
    
    End Sub
    
    Private Function MakeRandomDataStream() As Byte()
        Dim i1 As Long
        Dim i2 As Long
        Dim j As Long
        Dim bbData1() As Byte
        Dim bbData2() As Byte
        Dim bbOut() As Byte
        Dim Value3 As Double
        Dim Value4 As Long
        '
        Randomize
        '
        ' Some random string.
        ' But let's keep it simple and assume they're ASCII characters.
        i1 = Int(Rnd * 100 + 1)  ' A number between 1 and 100.
        ReDim bbData1(1 To i1)
        For j = 1 To i1
            bbData1(j) = Int(26 * Rnd + 65)      ' ASCII values for letters between A and Z.
        Next j
        '
        ' This time, some random collection of bytes, seen as bytes.
        i2 = Int(Rnd * 100 + 1)  ' A number between 1 and 100.
        ReDim bbData2(1 To i2)
        For j = 1 To i2
            bbData2(j) = Int(26 * Rnd + 65)      ' ASCII values for letters between A and Z.
        Next j
        '
        ' Make last two values.
        Value3 = Rnd * 10000# + 1#          ' Some value between 1 and 10000.
        Value4 = Int(Rnd * 10000@ + 1@)     ' Some integer (Long) between 1 and 10000.
        '
        ' And now we'll use CopyMemory to shove it into our Random Data Stream.
        ' Zphere, I assume you will be reading this from some other source.
        '
        ReDim bbOut(1 To (4 + i1 + 4 + i2 + 8 + 4))  ' Long, String[i1,ASCII], Long, Bytes[i2], Double, Long.
        '
        CopyMemory bbOut(1), i1, 4                              ' Length of string.
        CopyMemory bbOut(1 + 4), bbData1(1), i1                 ' The ASCII string.
        CopyMemory bbOut(1 + 4 + i1), i2, 4                     ' Length of bytes.
        CopyMemory bbOut(1 + 4 + i1 + 4), bbData2(1), i2        ' The bytes.
        CopyMemory bbOut(1 + 4 + i1 + 4 + i2), Value3, 8        ' First value at end.
        CopyMemory bbOut(1 + 4 + i1 + 4 + i2 + 8), Value4, 4    ' Second value at end.
    
    
        MakeRandomDataStream = bbOut
    
    End Function
    
    
    Last edited by Elroy; Apr 18th, 2018 at 05:23 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. To all, peace and happiness.

  11. #11

    Thread Starter
    Member
    Join Date
    Dec 2009
    Location
    Germany
    Posts
    47

    Re: Dynamic change of a structure length inside a function

    Elroy, thank you very much for "coaching" me here.

    "Secretely", methods of byte array handling was also what I'm looking for.
    I'm just changing my code regarding your suggestions and till now everything works as expected.
    Although not needed for my tasks, also thanks for your instructions on how to create a byte array with specific data types using CopyMemory.
    I learned much here.

    Anyway, in time I would although like to try the methods Victor Bravo VI described.
    Therefore, I won't mark this thread as resolved (I'm "somehow" convinced that questions will appear).

  12. #12
    PowerPoster
    Join Date
    Jun 2015
    Posts
    2,224

    Re: Dynamic change of a structure length inside a function

    using a typelib and an Array Map, you never end up allocating the memory for subMembers.
    You do have to watch out for access violations though, as VB assumes it's a large fixed size.

    Code:
    private Type DDSub
      subMember1    As string
      subMember2    As string
      subMember3    As string
    end type
    
    Private Type UDT
      Member1    As string
      Member2    As string
      Member3    As string
      Count      as Long
      subMembers (&HFFFF&)  as UDTSub
    End Type
    
    Dim MyUDT() As UDT
    With AryMap(RefAry(MyUDT), pData)
        With MyUDT(0)
            Dim I&
            For I = 0 To .Count - 1
                Debug.Print .subMembers(I).subMember1
            Next
        End With
    End With

  13. #13
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,817

    Re: Dynamic change of a structure length inside a function

    Also, Zphere, once you get the hang of CopyMemory, it's not too bad. Also, you'll eventually need to use it with "ByVal VarPtr()", but that's sort of another discussion.

    But, as a big caveat, just always make sure you understand what memory you're copying. If you ever try to copy memory that's not memory you're tracking, you'll rather quickly crash the VB6 IDE (and/or your compiled program). That's one reason to save often when you're developing code with CopyMemory so, if you do crash, you don't lose your work.

    Once you get it all running, and only copying memory that you understand, all should work extremely well.

    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. To all, peace and happiness.

  14. #14

    Thread Starter
    Member
    Join Date
    Dec 2009
    Location
    Germany
    Posts
    47

    Re: Dynamic change of a structure length inside a function

    Also, thanks for your warnings.
    Am I allowed to ask what "memory" one might try to copy is not memory?
    Could you/someone recommend a good reference about how CopyMemory works?

    DEXWERX, I think I understand what you were trying to say but I'm not able to follow your code.
    From which specific typelib are you talking about? And what about the AryMap function?
    Would it be presuming to ask for more specific explainations?
    Last edited by Zphere; Apr 19th, 2018 at 04:42 PM.

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

    Re: Dynamic change of a structure length inside a function

    Well, it's probably copying TO memory that you shouldn't as opposed to copying FROM memory that you shouldn't. However, Windows keeps pretty tight control over all of memory these days. If you're copying into/out-of your own variables, there should never be a problem.

    Here's the Microsoft MSDN page on the API call, but I'm not sure that's much help. Basically, when you pass any numeric variable, just pass it ByRef. When you pass VarPtr(SomeVariable), pass it ByVal. In terms of the actual call, the memory addresses to copy (along with the bytes to copy) must be on the stack. Strings get a bit more complicated, but that's not because of CopyMemory. That's just more to do with how VB6 deals with Strings.

    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. To all, peace and happiness.

  16. #16
    Hyperactive Member
    Join Date
    Aug 2017
    Posts
    380

    Re: Dynamic change of a structure length inside a function

    Quote Originally Posted by Zphere View Post
    Anyway, in time I would although like to try the methods Victor Bravo VI described.
    The methods DEXWERX and I are proposing are simply strategies for avoidance of data duplication (i.e., the copying of memory back and forth between the UDT and the Byte array). Why would you want to avoid data duplication? Well, there are at least two good reasons. The primary reason is, if you're the type of programmer who's mindful of your program's memory footprint, you would obviously want to reduce instances of the same data to the bare minimum, especially if it's taking quite a lot of space. The secondary reason is, copying bytes back and forth will definitely take some time (compared to simply making a variable point to the same memory occupied by another variable), again especially if there's a lot of data.

    People might argue that there is little benefit to be gained from using these kinds of strategies. Well, that's mostly true. However, it is also true that C/C++ programs tends to be a bit faster and more frugal in memory usage than VB6 programs. This is partly because the C/C++ language has cast operators (the reinterpret_cast in particular) that makes it easy to change the interpretation of one data type to another data type, thus avoiding unnecessary copying. VB6 has no such built-in capability, but various workarounds have been devised to help make up for this deficiency.



    Zphere, would it be possible for you to show your actual code? Seeing the actual code will enable us to give you better recommendations. Thank you.

  17. #17

    Thread Starter
    Member
    Join Date
    Dec 2009
    Location
    Germany
    Posts
    47

    Re: Dynamic change of a structure length inside a function

    Elroy, I think I now understand your statement of going sure that destination should be the first parameter.
    Regarding your link: habitually, RTFM is the first thing I do. This was the first side I visited.
    I've been in hope that somebody could provide a better reference.
    Nevermind, it's time for checking and experimenting now - thanks for everything.

    Victor Bravo VI, sure - but not now.
    I see, I've written working but somehow clumpsy code (2 years ago) that can be optimised by quite simple instructions from Elroy.
    Please give me some time to completely rewrite it before posting.
    I'm really interested in the thingies you stated and help from experts is always great.
    Please keep in mind, that I'm doing all this stuff in my rare sparetime (for fun and relaxation), so it may takes a little while.
    Am I allowed to drop you a pm?

  18. #18
    Hyperactive Member
    Join Date
    Aug 2017
    Posts
    380

    Re: Dynamic change of a structure length inside a function

    Quote Originally Posted by Zphere View Post
    Am I allowed to drop you a pm?
    Sure, go ahead.

Posting Permissions

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



Click Here to Expand Forum to Full Width