Results 1 to 8 of 8

Thread: [RESOLVED] Copymemory array

  1. #1

    Thread Starter
    Frenzied Member Jim Davis's Avatar
    Join Date
    Mar 2001
    Location
    Mars base one Username: Jim Davis Password: yCrm33
    Posts
    1,284

    Resolved [RESOLVED] Copymemory array

    Hello!

    Code:
    Private Declare Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" (ByRef Destination As Any, ByRef Source As Any, ByVal Length As Long)
    Private Declare Sub ZeroMemory Lib "kernel32" Alias "RtlZeroMemory" (dst As Any, ByVal iLen&)
    
      Dim X As Long, Y As Long
      ReDim Source(0 To 500, 0 To 5) As String
    
      For X = 0 To 5
        For Y = 0 To 500
          Source(Y, X) = "Item " + CStr(Y) + " in col " + CStr(X)
        Next Y
      Next X
      
      
      ReDim out(UBound(Source, 1)) As String
      
      
      CopyMemory ByVal VarPtr(out(0)), ByVal VarPtr(Source(0, 2)), 4 * (UBound(out) + 1)
      ZeroMemory ByVal VarPtr(Source(0, 2)), 4 * (UBound(out) + 1)
      Erase Source
      MsgBox "125th element: " + out(124) + vbNewLine + "126th element:" + out(125)
      
      End
    By using this code you can simply move a 2d string arrays one indexed dimension into a single dimension array.

    But if you change the variable type to Variant, everything goes to wrong. It copies the first 125 element (0-124), but after the 125th element it copies only null strings.

    Do you have any ideas how can i fix this code?

    Ok ive found it. Variant type string variants has 8 byte long pointers, but strings has 4. So i have to copy the 8 byte long pointers to get it to work.
    Last edited by Jim Davis; Oct 12th, 2007 at 10:10 AM.

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

    Re: Copymemory array

    Edited: hang on. Testing something, be back in couple minutes

  3. #3

    Thread Starter
    Frenzied Member Jim Davis's Avatar
    Join Date
    Mar 2001
    Location
    Mars base one Username: Jim Davis Password: yCrm33
    Posts
    1,284

    Re: Copymemory array

    Thanks Ive sent a PM to you a few hours before.

  4. #4

    Thread Starter
    Frenzied Member Jim Davis's Avatar
    Join Date
    Mar 2001
    Location
    Mars base one Username: Jim Davis Password: yCrm33
    Posts
    1,284

    Re: Copymemory array

    Ahh i cant belive it.. it copies another 25 elements but it copies only the half of the array, then copies nullstrings....

    Edited: hang on. Testing something, be back in couple minutes
    Ok im waiting.. i have no idea whats wrong with it..

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

    Re: Copymemory array

    Ok, I'm back. Variants are a stranger beast. Each Variant contains 16 bytes and within those 16 bytes is a pointer to the string, which I believe is at the 8th byte within the variant structure (don't really recall without testing - FYI).
    Verify: ? varptr(source(1,0))-varptr(source(0,0))
    When you want to move variant pointers, multiply by 16, not 4.

    Also, don't mix/match. Dim source & destination to the same. If Variants, then make destination variant.

  6. #6

    Thread Starter
    Frenzied Member Jim Davis's Avatar
    Join Date
    Mar 2001
    Location
    Mars base one Username: Jim Davis Password: yCrm33
    Posts
    1,284

    Re: Copymemory array

    Yeehaw! Maximum respect to you my friend!

    Code:
    Private Declare Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" (ByRef Destination As Any, ByRef Source As Any, ByVal Length As Long)
    Private Declare Sub ZeroMemory Lib "kernel32" Alias "RtlZeroMemory" (dst As Any, ByVal iLen&)
    
      Dim X As Long, Y As Long
      ReDim Source(0 To 500, 0 To 5) As Variant
    
      For X = 0 To 5
        For Y = 0 To 500
          Source(Y, X) = "Item " + CStr(Y) + " in col " + CStr(X)
        Next Y
      Next X
      
      
      ReDim out(UBound(Source, 1)) As Variant
      
      
      CopyMemory ByVal VarPtr(out(0)), ByVal VarPtr(Source(0, 2)), 16 * (UBound(out) + 1)
      ZeroMemory ByVal VarPtr(Source(0, 2)), 16 * (UBound(out) + 1)
      Erase Source
    Thanks a lot.

  7. #7

    Thread Starter
    Frenzied Member Jim Davis's Avatar
    Join Date
    Mar 2001
    Location
    Mars base one Username: Jim Davis Password: yCrm33
    Posts
    1,284

    Re: [RESOLVED] Copymemory array

    Quote Originally Posted by LaVolpe
    If your arrays are large, you may want to entertain idea of converting variant to string pointer. Why? Using 500K as example: 16 byte Variant requires 8mb of memory, but 4 byte string pointer, 2mb memory requirement. The logic is simple, but does require a loop, significant changes only...
    Code:
    ReDim out(UBound(Source, 1)) As String 
    For Y = 0 To 500 
      CopyMemory ByVal VarPtr(out(Y)), ByVal VarPtr(Source(Y, 2)) + 8, 4& ' string pointer in variant 
      CopyMemory ByVal VarPtr(Source(Y, 2)) + 8, 0&, 4& ' clear string pointer in variant 
    Next 
    
    MsgBox "125th element: " + out(124) + vbNewLine + "126th element:" + out(125)
    Thanks for sharing this useful piece of code

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

    Re: [RESOLVED] Copymemory array

    To finish up. This little hack can be used to convert Variant arrays containing numerical data to a array of just numerical data too. The final 8 bytes in the Variant structure contains the actual numerical data. If the numer is a byte, then just 8th byte used, Longs: 8-11 used, Doubles: 8-15 used.
    For example the passed Variant array contains only longs
    Code:
    ReDim out(UBound(Source, 1)) As Long
    For Y = 0 To 500 
      CopyMemory out(Y), ByVal VarPtr(Source(Y, 2)) + 8, 4& ' Long value in variant 
      ' no need to erase anything, numerical data are not pointers
    Next
    And if the Variant array contained only Integers
    Code:
    ReDim out(UBound(Source, 1)) As Integer
    For Y = 0 To 500 
      CopyMemory out(Y), ByVal VarPtr(Source(Y, 2)) + 8, 2& ' Integer value in variant 
      ' no need to erase anything, numerical data are not pointers
    Next
    And if the Variant array contained only Dates
    Code:
    ReDim out(UBound(Source, 1)) As Date
    For Y = 0 To 500 
      CopyMemory out(Y), ByVal VarPtr(Source(Y, 2)) + 8, 8& ' Date value in variant 
      ' no need to erase anything, numerical data are not pointers
    Next
    Last edited by LaVolpe; Oct 13th, 2007 at 10:34 AM.

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