Results 1 to 10 of 10

Thread: [RESOLVED] CopyMemory a range of integer array values to create a string?

  1. #1

    Thread Starter
    Fanatic Member
    Join Date
    Aug 2011
    Location
    Palm Coast, FL
    Posts
    762

    Resolved [RESOLVED] CopyMemory a range of integer array values to create a string?

    I have an integer array containing character codes. I want to create a string from a range of these character codes. I know that I can do this by concatenating the Chr$() of each character code, But I'm wondering if this can be done faster and in one go using CopyMemory. Everything I try either crashes or doesn't work.

    Ex.
    Dim arrCharCodes(1 to 5) as Integer
    arrCharCodes(1) = 65 'A
    arrCharCodes(2) = 66 'B
    arrCharCodes(3) = 67 'C
    arrCharCodes(4) = 68 'D
    arrCharCodes(5) = 69 'E


    dim strCharCodes as String
    strCharCodes = Chr$(arrCharCodes(2)) & Chr$(arrCharCodes(3)) & Chr$(arrCharCodes(4))

    'results in strCharCodes = "BCD"

    Can this be achieved faster using CopyMemory to copy a range of values from the Integer array into a string variable? If so, how?

  2. #2
    PowerPoster
    Join Date
    Jul 2010
    Location
    NYC
    Posts
    7,670

    Re: CopyMemory a range of integer array values to create a string?

    Code:
    Public Function WCHARtoStr(aCh() As Integer) As String
    Dim sBuf As String
    sBuf = String$(UBound(aCh) + 1, 0)
    CopyMemory ByVal StrPtr(sBuf), aCh(0), LenB(sBuf)
    WCHARtoStr = sBuf
    End Function
    or if you want to have that procedure itself able to select a range:
    Code:
    Public Function WCHARtoStrEx(aCh() As Integer, Optional ByVal nStart As Long = 0&, Optional ByVal nEnd As Long = -1&) As String
    Dim sBuf As String
    Dim nCh As Long
    If nEnd = -1& Then nEnd = UBound(aCh)
    nCh = (nEnd - nStart) + 1
    sBuf = String$(nCh, 0)
    CopyMemory ByVal StrPtr(sBuf), aCh(nStart), nCh * 2
    WCHARtoStrEx = sBuf
    End Function
    nStart and nEnd refer to the integer array so are zero-based. For ABCDE 1,3 would return BCD.
    Last edited by fafalone; Feb 18th, 2019 at 04:50 PM.

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

    Re: CopyMemory a range of integer array values to create a string?

    I'd tend to be a bit careful about the LBound of the incoming array. Something like the following to initialize the string might be a bit better:

    Code:
    sBuf = String$(UBound(aCh) - LBound(aCh) + 1, 0)

    And then maybe the following for the CopyMemory:

    Code:
    CopyMemory ByVal StrPtr(sBuf), aCh(LBound(aCh)), LenB(sBuf)

    This would do better at accommodating AAraya's array:

    Code:
    Dim arrCharCodes(1 to 5) as Integer
    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.

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

    Re: CopyMemory a range of integer array values to create a string?

    Quote Originally Posted by AAraya View Post
    Can this be achieved faster using CopyMemory ...
    Why bother with CopyMemory when there are API functions that deals specifically with BSTRs?

    Code:
    Option Explicit
    
    Private Declare Function SysReAllocStringLen Lib "oleaut32.dll" (ByVal pBSTR As Long, Optional ByVal pszStrPtr As Long, Optional ByVal Length As Long) As Long
    
    Private Sub Main()
        Dim arrCharCodes(1 To 5) As Integer
        Dim strCharCodes         As String
    
        arrCharCodes(1) = 65 'A
        arrCharCodes(2) = 66 'B
        arrCharCodes(3) = 67 'C
        arrCharCodes(4) = 68 'D
        arrCharCodes(5) = 69 'E
    
        If SysReAllocStringLen(VarPtr(strCharCodes), VarPtr(arrCharCodes(2&)), 3&) Then
            MsgBox """" & strCharCodes & """", vbInformation
        End If
    End Sub

  5. #5

    Thread Starter
    Fanatic Member
    Join Date
    Aug 2011
    Location
    Palm Coast, FL
    Posts
    762

    Re: CopyMemory a range of integer array values to create a string?

    Quote Originally Posted by fafalone View Post
    Code:
    Public Function WCHARtoStr(aCh() As Integer) As String
    Dim sBuf As String
    sBuf = String$(UBound(aCh) + 1, 0)
    CopyMemory ByVal StrPtr(sBuf), aCh(0), LenB(sBuf)
    WCHARtoStr = sBuf
    End Function
    Thanks! I was right there myself but wasn't creating a buffer. I was trying to copy to the sBuf string variable without creating a buffer. DOH!

  6. #6

    Thread Starter
    Fanatic Member
    Join Date
    Aug 2011
    Location
    Palm Coast, FL
    Posts
    762

    Re: CopyMemory a range of integer array values to create a string?

    Quote Originally Posted by Victor Bravo VI View Post
    Why bother with CopyMemory when there are API functions that deals specifically with BSTRs?
    Thanks for sharing those functions! I hadn't used those before. Performance-wise your method is very close to the CopyMemory method so I'm not sure what advantage there is to using one over the other.

  7. #7
    PowerPoster dilettante's Avatar
    Join Date
    Feb 2006
    Posts
    24,487

    Re: [RESOLVED] CopyMemory a range of integer array values to create a string?

    Code:
        Dim CharCodes() As Byte
        Dim Chars As String
    
        ReDim CharCodes(1 To 10)
        CharCodes(1) = 65 'A
        CharCodes(3) = 66 'B
        CharCodes(5) = 67 'C
        CharCodes(7) = 68 'D
        CharCodes(9) = 69 'E
    
        Chars = CharCodes
        MsgBox Chars

  8. #8

    Thread Starter
    Fanatic Member
    Join Date
    Aug 2011
    Location
    Palm Coast, FL
    Posts
    762

    Re: [RESOLVED] CopyMemory a range of integer array values to create a string?

    Quote Originally Posted by dilettante View Post
    Code:
        Dim CharCodes() As Byte
        Dim Chars As String
    
        ReDim CharCodes(1 To 10)
        CharCodes(1) = 65 'A
        CharCodes(3) = 66 'B
        CharCodes(5) = 67 'C
        CharCodes(7) = 68 'D
        CharCodes(9) = 69 'E
    
        Chars = CharCodes
        MsgBox Chars
    Thanks dilettante.

    I'm aware of assigning a byte array directly to a string. 1) I don't have a byte array, I have an array of integers. And they're not in Unicode format (with every other byte being a zero). This method won't work for me, will it? 2) I don't want to assign the entire integer array to a string but just a portion of it. How does that work with your method?

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

    Re: CopyMemory a range of integer array values to create a string?

    Quote Originally Posted by AAraya View Post
    Performance-wise your method is very close to the CopyMemory method so I'm not sure what advantage there is to using one over the other.
    Well, SysReAllocStringLen combines String$ + CopyMemory in one function call.

    OK, so I did some benchmarks and here are the results on my machine (all times are in seconds):

    Code:
    +-----------------------------------------------------------------------------+
    |      10,000,000      |  1st   |  2nd   |  3rd   |  4th   |  5th   ||  Ave.  |
    |----------------------+--------+--------+--------+--------+--------++--------|
    | String$ + CopyMemory | 2.6685 | 2.7969 | 2.6522 | 2.6635 | 2.6848 || 2.6932 |
    |----------------------+--------+--------+--------+--------+--------++--------|
    | SysReAllocStringLen  | 1.7836 | 1.8095 | 1.7908 | 1.7901 | 1.7878 || 1.7924 |
    +-----------------------------------------------------------------------------+
    Code:
    Option Explicit 'In a standard (.BAS) module
    
    Private Declare Function QueryPerformanceCounter Lib "kernel32.dll" (ByRef lpPerformanceCount As Currency) As Long
    Private Declare Function QueryPerformanceFrequency Lib "kernel32.dll" (ByRef lpFrequency As Currency) As Long
    Private Declare Function SysReAllocStringLen Lib "oleaut32.dll" (ByVal pBSTR As Long, Optional ByVal pszStrPtr As Long, Optional ByVal Length As Long) As Long
    Private Declare Sub CopyMemory Lib "ntdll.dll" Alias "RtlMoveMemory" (ByRef Destination As Any, ByRef Source As Any, ByVal Length As Long)
    Private Declare Sub InitCommonControls Lib "comctl32.dll" ()
    
    Private Sub Main()
        Const ITERATIONS = 10000000 - 1
        Dim iCharCodes() As Integer, I As Long, sBuffer As String
        Dim Freq As Currency, Start(1) As Currency, Stop_(1) As Currency
    
        InitCommonControls
    
        ReDim iCharCodes(0 To 999) As Integer
        SysReAllocStringLen VarPtr(sBuffer), , 1000&                'Allocate a buffer containing random data
        CopyMemory iCharCodes(0&), ByVal StrPtr(sBuffer), 2000&     'and use it to populate the Integer array
        sBuffer = vbNullString
    
        MsgBox "Set Priority to Realtime to minimize interference from other processes.", vbInformation
    
        QueryPerformanceFrequency Freq
    
        QueryPerformanceCounter Start(0&)
            For I = 0& To ITERATIONS
                sBuffer = String$(1000&, 0)
                CopyMemory ByVal StrPtr(sBuffer), iCharCodes(0&), 2000&
            Next
        QueryPerformanceCounter Stop_(0&)
    
        sBuffer = vbNullString
    
        QueryPerformanceCounter Start(1&)
            For I = 0& To ITERATIONS
                SysReAllocStringLen VarPtr(sBuffer), VarPtr(iCharCodes(0&)), 1000&
            Next
        QueryPerformanceCounter Stop_(1&)
    
        sBuffer = "String$ + CopyMemory: " & FormatNumber((Stop_(0&) - Start(0&)) / Freq, 4&) & vbCrLf & _
                  "SysReAllocStringLen: " & FormatNumber((Stop_(1&) - Start(1&)) / Freq, 4&)
        MsgBox sBuffer, vbInformation
    End Sub

  10. #10
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    6,202

    Re: [RESOLVED] CopyMemory a range of integer array values to create a string?

    JFYI, clearing target var w/ sBuffer = vbNullString just before calling SysReAllocStringLen increases performance another 30%

    Code:
    String$ + CopyMemory: 1.6947
    SysReAllocStringLen: 1.2316
    SysReAllocStringLen w/ clear: 0.9585
    cheers,
    </wqw>

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