Attribute VB_Name = "Strings"
' Strings.bas
Option Explicit

Public Enum SplitCompareMethod
    [Split BinaryCompare] = VbCompareMethod.vbBinaryCompare         ' InStrB
'    [Split TextCompare] = VbCompareMethod.vbTextCompare             ' InStr(TextCompare)
    [Split CharacterCompare] = VbCompareMethod.vbDatabaseCompare    ' InStr(BinaryCompare)
End Enum

Private Declare Function ArrPtr Lib "msvbvm60" Alias "VarPtr" (Arr() As Any) As Long
Private Declare Function InitStringArray Lib "oleaut32" Alias "SafeArrayCreate" (Optional ByVal VarType As VbVarType = vbString, Optional ByVal Dims As Integer = 1, Optional saBound As Currency) As Long
Private Declare Function SysAllocStringByteLen Lib "oleaut32" (ByVal Ptr As Long, ByVal Length As Long) As Long
Private Declare Function SysAllocStringLen Lib "oleaut32" (ByVal Ptr As Long, ByVal Length As Long) As Long

Private Declare Sub PutMem4 Lib "msvbvm60" (ByVal Ptr As Long, ByVal Value As Long)

' API
Private Declare Function GetModuleHandle Lib "kernel32" Alias "GetModuleHandleA" (ByVal lpModuleName As String) As Long
Private Declare Function GetProcAddress Lib "kernel32" (ByVal hModule As Long, ByVal lpProcName As String) As Long
Private Declare Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As Long

' Property
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Private Declare Function GetCurrentProcessId Lib "kernel32" () As Long
Private Declare Sub GetMem4 Lib "msvbvm60" (ByVal Ptr As Long, Value As Long)
Private Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
Private Declare Function WriteProcessMemory Lib "kernel32" (ByVal hProcess As Long, lpBaseAddress As Any, lpBuffer As Any, ByVal nSize As Long, Optional lpNumberOfBytesWritten As Long) As Long

Private m_A() As Long
Private m_AP As Long
Private m_H(0 To 6) As Long
Private m_HP As Long

Public Function AllocString(ByVal Ptr As Long, ByVal Length As Long) As String
    Procedure(AddressOf Strings.AllocString) = API("oleaut32", "SysAllocStringByteLen")
    AllocString = Strings.AllocString(Ptr, Length)
End Function

Private Property Get API(Module As String, Procedure As String) As Long
    Dim Handle As Long
    Handle = GetModuleHandle(Module)
    If Handle = 0 Then Handle = LoadLibrary(Module)
    If Handle Then API = GetProcAddress(Handle, Procedure)
End Property

Private Function InIDE(Optional IDE) As Boolean
    If IsMissing(IDE) Then Debug.Assert Not InIDE(InIDE) Else IDE = True
End Function

Private Property Get Procedure(ByVal AddressOfDest As Long) As Long
    ' get correct pointer to procedure in IDE
    If Not InIDE Then Procedure = AddressOfDest Else GetMem4 AddressOfDest + &H16&, Procedure
End Property

Private Property Let Procedure(ByVal AddressOfDest As Long, ByVal AddressOfSrc As Long)
    Dim JMP As Currency, PID As Long
    ' get process handle
    PID = OpenProcess(&H1F0FFF, 0&, GetCurrentProcessId)
    If PID Then
        ' get correct pointer to procedure in IDE
        If InIDE Then GetMem4 AddressOfDest + &H16&, AddressOfDest
        Debug.Assert App.hInstance
        ' ASM JMP (0xE9) followed by bytes to jump in memory
        JMP = (&HE9& * 0.0001@) + (AddressOfSrc - AddressOfDest - 5@) * 0.0256@
        ' write the JMP over the destination procedure
        WriteProcessMemory PID, ByVal AddressOfDest, JMP, 5
        ' close process handle
        CloseHandle PID
    End If
End Property

Public Function Join(SourceArray() As String, Optional Delimiter As String = ",") As String
    Static HJ2(0 To 6) As Long, PJ2 As Long
    Dim J2() As Integer, APJ2 As Long
    Static HJ4(0 To 6) As Long, PJ4 As Long
    Dim J4() As Long, APJ4 As Long
    Static HS(0 To 6) As Long, PS As Long
    Dim S() As Long, APS As Long
    
    Dim D2 As Integer, D2b As Integer, D2c As Integer
    Dim D4 As Long, D4b As Long, D4c As Long, D4d As Long, D4e As Long, D4f As Long, D4g As Long, D4h As Long
    
    Dim V2 As Integer, V2b As Integer, V2c As Integer
    Dim V4 As Long, V4b As Long, V4c As Long, V4d As Long, V4e As Long
        
    Dim I As Long, J As Long, L As Long, LD As Long, P As Long, PD As Long, PJ As Long, T As Long, US As Long
    
    Dim ReturnTo As Long
    
    P = Not Not SourceArray
    Debug.Assert App.hInstance
    If P Then
        US = UBound(SourceArray)
        If US < 0 Or LBound(SourceArray) <> 0 Then Exit Function
        If US = 0 Then Join = SourceArray(0): Exit Function
        LD = LenB(Delimiter)
        If LD Then T = LD * US
        For I = 0 To US
            T = T + LenB(SourceArray(I))
        Next I
        If T Then
            ' generic safe array hack
            If m_AP = 0 Then
                ' array variable pointer
                m_AP = ArrPtr(m_A)
                ' create a safe array header
                m_H(0) = vbLong: m_H(1) = &H800001: m_H(2) = 4: m_H(5) = &H7FFFFFFF
                ' header pointer
                m_HP = VarPtr(m_H(1))
            End If
            ' set pointer to array
            PutLong m_AP, m_HP
            ' local safe array hack
            APJ2 = ArrPtr(J2)
            APJ4 = ArrPtr(J4)
            APS = ArrPtr(S)
            If PS = 0 Then
                HJ2(0) = vbInteger: HJ2(1) = &H800001: HJ2(2) = 2: HJ2(5) = 16
                HJ4(0) = vbLong: HJ4(1) = &H800001: HJ4(2) = 4
                HS(0) = vbLong: HS(1) = &H800001: HS(2) = 4
                PJ2 = VarPtr(HJ2(1))
                PJ4 = VarPtr(HJ4(1))
                PS = VarPtr(HS(1))
            End If
            ' allocate string
            Join = AllocString(0, T)
            If LenB(Join) <> T Then Exit Function
            PJ = StrPtr(Join)
            ' update safe array headers
            HJ4(5) = 8 + US \ 4
            HS(4) = VarPtr(SourceArray(0)): HS(5) = US + 1
            ' start safe array hack for local arrays
            m_H(4) = APJ2: m_A(0) = PJ2
            m_H(4) = APJ4: m_A(0) = PJ4
            m_H(4) = APS: m_A(0) = PS
            ' pointer position
            P = PJ
            T = 0
            ' delimiter length
            Select Case LD
            Case 0
                ReturnTo = 0
                For I = 0 To US - 1
                    GoTo SourceToJoin
0:                  P = P + L
                Next I
            Case Is > 16: GoTo Over16
            Case 1, 2
                HJ2(4) = StrPtr(Delimiter)
                D2 = J2(0)
                ReturnTo = 2
                For I = 0 To US - 1
                    GoTo SourceToJoin
2:                  P = P + L
                    HJ2(4) = P
                    J2(0) = D2
                    P = P + LD
                Next I
            Case 3, 4
                HJ4(4) = StrPtr(Delimiter)
                D4 = J4(0)
                ReturnTo = 4
                For I = 0 To US - 1
                    GoTo SourceToJoin
4:                  P = P + L
                    HJ4(4) = P
                    J4(0) = D4
                    P = P + LD
                Next I
            Case 5, 6
                HJ2(4) = StrPtr(Delimiter)
                D2 = J2(0)
                D2b = J2(1)
                D2c = J2(2)
                ReturnTo = 6
                For I = 0 To US - 1
                    GoTo SourceToJoin
6:                  P = P + L
                    HJ2(4) = P
                    J2(0) = D2
                    J2(1) = D2b
                    J2(2) = D2c
                    P = P + LD
                Next I
            Case 7, 8
                HJ4(4) = StrPtr(Delimiter)
                D4 = J4(0)
                D4b = J4(1)
                ReturnTo = 8
                For I = 0 To US - 1
                    GoTo SourceToJoin
8:                  P = P + L
                    HJ4(4) = P
                    J4(0) = D4
                    J4(1) = D4b
                    P = P + LD
                Next I
            Case 9, 10
                HJ4(4) = StrPtr(Delimiter)
                D4 = J4(0)
                D4b = J4(1)
                HJ2(4) = HJ4(4) + 8
                D2 = J2(0)
                ReturnTo = 10
                For I = 0 To US - 1
                    GoTo SourceToJoin
10:                 P = P + L
                    HJ4(4) = P
                    J4(0) = D4
                    J4(1) = D4b
                    HJ2(4) = P + 8
                    J2(0) = D2
                    P = P + LD
                Next I
            Case 11, 12
                HJ4(4) = StrPtr(Delimiter)
                D4 = J4(0)
                D4b = J4(1)
                D4c = J4(2)
                ReturnTo = 12
                For I = 0 To US - 1
                    GoTo SourceToJoin
12:                 P = P + L
                    HJ4(4) = P
                    J4(0) = D4
                    J4(1) = D4b
                    J4(2) = D4c
                    P = P + LD
                Next I
            Case 13, 14
                HJ4(4) = StrPtr(Delimiter)
                D4 = J4(0)
                D4b = J4(1)
                D4c = J4(2)
                HJ2(4) = HJ4(4) + 12
                D2 = J2(0)
                ReturnTo = 14
                For I = 0 To US - 1
                    GoTo SourceToJoin
14:                 P = P + L
                    HJ4(4) = P
                    J4(0) = D4
                    J4(1) = D4b
                    J4(2) = D4c
                    HJ2(4) = P + 12
                    J2(0) = D2
                    P = P + LD
                Next I
            Case 15, 16
                HJ4(4) = StrPtr(Delimiter)
                D4 = J4(0)
                D4b = J4(1)
                D4c = J4(2)
                D4d = J4(3)
                ReturnTo = 16
                For I = 0 To US - 1
                    GoTo SourceToJoin
16:                 P = P + L
                    HJ4(4) = P
                    J4(0) = D4
                    J4(1) = D4b
                    J4(2) = D4c
                    J4(3) = D4d
                    P = P + LD
                Next I
            Case Else
Over16:         PD = StrPtr(Delimiter)
                ReturnTo = 100
                For I = 0 To US - 1
                    GoTo SourceToJoin
100:                P = P + L
                    rtlMove P, PD, LD: P = P + LD
                Next I
            End Select
            ReturnTo = 1000
            GoTo SourceToJoin
1000:       ' end safe array hacks
            m_H(4) = APJ2: m_A(0) = 0
            m_H(4) = APJ4: m_A(0) = 0
            m_H(4) = APS: m_A(0) = 0
            m_H(4) = m_AP: m_A(0) = 0
        End If
    End If
    Exit Function
SourceToJoin:
    L = LenB(SourceArray(I))
    Select Case L
    Case 0
    Case 1, 2: GoTo Bytes2
    Case 3, 4: GoTo Bytes4
    Case 5, 6: GoTo Bytes6
    Case 7, 8: GoTo Bytes8
    Case 9, 10: GoTo Bytes10
    Case 11, 12: GoTo Bytes12
    Case 13, 14: GoTo Bytes14
    Case 15, 16: GoTo Bytes16
    Case 19, 20: GoTo Bytes20
    Case 23, 24: GoTo Bytes24
    Case 27, 28: GoTo Bytes28
    Case 31, 32: GoTo Bytes32
    Case Else: rtlMove P, S(I), L
    End Select
BytesCopied:
    Select Case ReturnTo
    Case 0: GoTo 0:     Case 2: GoTo 2:     Case 4: GoTo 4
    Case 6: GoTo 6:     Case 8: GoTo 8:     Case 10: GoTo 10
    Case 12: GoTo 12:   Case 14: GoTo 14:   Case 16: GoTo 16
    Case 100: GoTo 100: Case 1000: GoTo 1000
    End Select
Bytes2:
        HJ2(4) = S(I)
        V2 = J2(0)
        HJ2(4) = P
        J2(0) = V2
    GoTo BytesCopied
Bytes4:
        HJ4(4) = S(I)
        V4 = J4(0)
        HJ4(4) = P
        J4(0) = V4
    GoTo BytesCopied
Bytes6:
        HJ2(4) = S(I)
        V2 = J2(0)
        V2b = J2(1)
        V2c = J2(2)
        HJ2(4) = P
        J2(0) = V2
        J2(1) = V2b
        J2(2) = V2c
    GoTo BytesCopied
Bytes8:
        HJ4(4) = S(I)
        V4 = J4(0)
        V4b = J4(1)
        HJ4(4) = P
        J4(0) = V4
        J4(1) = V4b
    GoTo BytesCopied
Bytes10:
        HJ4(4) = S(I)
        V4 = J4(0)
        V4b = J4(1)
        HJ2(4) = HJ4(4) + 8
        V2 = J2(0)
        HJ4(4) = P
        J4(0) = V4
        J4(1) = V4b
        HJ2(4) = P + 8
        J2(0) = V2
    GoTo BytesCopied
Bytes12:
        HJ4(4) = S(I)
        V4 = J4(0)
        V4b = J4(1)
        V4b = J4(2)
        HJ4(4) = P
        J4(0) = V4
        J4(1) = V4b
        J4(2) = V4c
    GoTo BytesCopied
Bytes14:
        HJ4(4) = S(I)
        V4 = J4(0)
        V4b = J4(1)
        V4c = J4(2)
        HJ2(4) = HJ4(4) + 12
        V2 = J2(0)
        HJ4(4) = P
        J4(0) = V4
        J4(1) = V4b
        J4(1) = V4c
        HJ2(4) = P + 12
        J2(0) = V2
    GoTo BytesCopied
Bytes16:
        HJ4(4) = S(I)
        V4 = J4(0)
        V4b = J4(1)
        V4c = J4(2)
        V4d = J4(3)
        HJ4(4) = P
        J4(0) = V4
        J4(1) = V4b
        J4(2) = V4c
        J4(3) = V4d
    GoTo BytesCopied
Bytes20:
        T = S(I)
        
        HJ4(4) = T
        V4 = J4(0)
        V4b = J4(1)
        V4c = J4(2)
        V4d = J4(3)
        V4e = J4(4)
        HJ4(4) = P
        J4(0) = V4
        J4(1) = V4b
        J4(2) = V4c
        J4(3) = V4d
        J4(4) = V4e
    GoTo BytesCopied
Bytes24:
        T = S(I)
        
        HJ4(4) = T
        V4 = J4(0)
        V4b = J4(1)
        V4c = J4(2)
        V4d = J4(3)
        HJ4(4) = P
        J4(0) = V4
        J4(1) = V4b
        J4(2) = V4c
        J4(3) = V4d
        
        HJ4(4) = T + 16
        V4 = J4(0)
        V4b = J4(1)
        HJ4(4) = P + 16
        J4(0) = V4
        J4(1) = V4b
    GoTo BytesCopied
Bytes28:
        T = S(I)
        
        HJ4(4) = T
        V4 = J4(0)
        V4b = J4(1)
        V4c = J4(2)
        V4d = J4(3)
        HJ4(4) = P
        J4(0) = V4
        J4(1) = V4b
        J4(2) = V4c
        J4(3) = V4d
        
        HJ4(4) = T + 16
        V4 = J4(0)
        V4b = J4(1)
        V4c = J4(2)
        HJ4(4) = P + 16
        J4(0) = V4
        J4(1) = V4b
        J4(2) = V4c
    GoTo BytesCopied
Bytes32:
        T = S(I)
        
        HJ4(4) = T
        V4 = J4(0)
        V4b = J4(1)
        V4c = J4(2)
        V4d = J4(3)
        HJ4(4) = P
        J4(0) = V4
        J4(1) = V4b
        J4(2) = V4c
        J4(3) = V4d
        
        HJ4(4) = T + 16
        V4 = J4(0)
        V4b = J4(1)
        V4c = J4(2)
        V4d = J4(3)
        HJ4(4) = P + 16
        J4(0) = V4
        J4(1) = V4b
        J4(2) = V4c
        J4(3) = V4d
    GoTo BytesCopied
End Function

Public Function Replace(Expression As String, Find As String, ReplaceWith As String, Optional ByVal Start As Long = 1, Optional ByVal Count As Long = -1, Optional ByVal Compare As VbCompareMethod) As String
    
    Static P() As Long
    Dim CF As Long, CR As Long, CFmask As Long, CRmask As Long, UF As Long, UR As Long
    Dim PtrE As Long, PtrR As Long, PtrN As Long
    Dim C As Long, I As Long, J As Long, K As Long, L As Long, M As Long, PC As Long, PL As Long
    Dim LE As Long, LF As Long, LR As Long, S As Boolean
    ' length information
    LE = LenB(Expression)
    LF = LenB(Find)
    LR = LenB(ReplaceWith)
    ' validate start
    Start = Start * 2
    If Start < 0 Then Start = LE + Start + 1
    If Start < 1 Or Start > LE Then Exit Function
    ' validate lengths and limit
    If LE > 0 And LF > 0 And Count >= -1 Then
        If Count = -1 Then Count = LE \ LF Else Count = Count - 1
    Else
        Count = -1
    End If
    ' can we go on?
    If Count >= 0 Then
        
    End If
End Function

Public Function Split(Expression As String, Optional Delimiter As String = " ", Optional ByVal Limit As Long = -1, Optional ByVal Compare As SplitCompareMethod) As String()
    Procedure(AddressOf Strings.Split) = Procedure(AddressOf Strings.z_Split)
    Split = Strings.Split(Expression, Delimiter, Limit, Compare)
End Function

Public Function z_Split(Expression As String, Optional Delimiter As String = " ", Optional ByVal Limit As Long = -1, Optional ByVal Compare As SplitCompareMethod) As Long
    ' general variables that we need
    Static R() As Long, RP As Long
    Dim P() As Long
    Dim C As Long, I As Long, J As Long, K As Long, LD As Long, LD2 As Long, LE As Long, PL As Long, PS As Long
    ' get pointer
    PS = StrPtr(Expression)
    ' length information
    LE = LenB(Expression)
    LD = LenB(Delimiter)
    ' unlimited or limited?
    If Limit = -1 Then If LD Then Limit = LE \ LD + 1
    ' validate lengths and limit
    If LE > 0 And LD > 0 And Limit >= 0 Then
        ' pointer to R array
        If RP = 0 Then RP = ArrPtr(R)
        ' generic safe array hack
        If m_AP = 0 Then
            ' array variable pointer
            m_AP = ArrPtr(m_A)
            ' create a safe array header
            m_H(0) = vbLong: m_H(1) = &H800001: m_H(2) = 4: m_H(5) = &H7FFFFFFF
            ' header pointer
            m_HP = VarPtr(m_H(1))
        End If
        ' set pointer to array
        PutLong m_AP, m_HP
        ' find the first item
        If Limit > 1 Then
            If Compare = [Split BinaryCompare] Then
                Do: I = InStrB(I + 1, Expression, Delimiter)
                Loop Until (I And 1) = 1 Or (I = 0)
            Else
                I = InStr(Expression, Delimiter)
            End If
        End If
        ' did we find an item?
        If I Then
            ReDim P(3) As Long
            ' space for knowing the positions
            PL = (Limit \ 96)
            If PL > 8191 Then PL = 8191
            If PL > UBound(P) Then ReDim Preserve P(0 To PL)
            ' InStrB?
            If Compare = [Split BinaryCompare] Then
                For C = 0 To Limit
                    ' exit if nothing found
                    If I = 0 Then Exit For
                    ' make sure will always have enough items
                    If C >= PL Then PL = PL + C: ReDim Preserve P(PL)
                    ' remember position
                    P(C) = I - 1
                    ' find next
                    I = I + LD - 1
                    Do: I = InStrB(I + 1, Expression, Delimiter)
                    Loop Until (I And 1) = 1 Or (I = 0)
                Next C
            Else ' InStr
                LD2 = LD \ 2
                For C = 0 To Limit
                    ' exit if nothing found
                    If I = 0 Then Exit For
                    ' make sure will always have enough items
                    If C >= PL Then PL = PL + C: ReDim Preserve P(PL)
                    ' remember position
                    P(C) = (I - 1) * 2
                    ' find next
                    I = InStr(I + LD2, Expression, Delimiter)
                Next C
            End If
            P(C) = LE
            ' make space for the new items
            z_Split = InitStringArray(, , (C + 1) * 0.0001@)
            ' set pointer
            m_H(4) = RP: m_A(0) = z_Split
            ' keep it simple, stupid!
            I = 0
            For C = 0 To C
                K = P(C)
                J = K - I
                If J Then R(C) = SysAllocStringByteLen(PS + I, J)
                I = K + LD
            Next C
        Else
            ' one item
            z_Split = InitStringArray(, , 0.0001@)
            ' set pointer
            m_H(4) = RP: m_A(0) = z_Split
            R(0) = SysAllocStringByteLen(PS, LE)
        End If
        ' clean up z_Split reference
        m_A(0) = 0
        ' clean up safe array reference
        m_H(4) = m_AP: m_A(0) = 0
    Else
        z_Split = InitStringArray
    End If
End Function

' btw, this would be fastest for VB5... as VB6 DLL is always available in Windows these days
'Public Function StrReverse(Expression As String) As String
'    Procedure(AddressOf Strings.StrReverse) = API("msvbvm60", "rtcStrReverse")
'    StrReverse = Strings.StrReverse(Expression)
'End Function
Public Function StrReverse(Expression As String, Optional ByVal AllCharBelow0x8000 As Boolean = True) As String
    Static HE(0 To 6) As Long, HS(0 To 6) As Long, HPE As Long, HPS As Long
    Dim E() As Integer, S() As Long, APE As Long, APS As Long
    Dim C1 As Integer, C2 As Integer, C1L As Long, C2L As Long, I As Long, L As Long, M As Long, M2 As Long, U As Long
    ' length (ignore half character)
    L = LenB(Expression) And Not 1
    If L Then
        ' generic safe array hack
        If m_AP = 0 Then
            ' array variable pointer
            m_AP = ArrPtr(m_A)
            ' create a safe array header
            m_H(0) = vbLong: m_H(1) = &H800001: m_H(2) = 4: m_H(5) = &H7FFFFFFF
            ' header pointer
            m_HP = VarPtr(m_H(1))
        End If
        ' set pointer to array
        PutLong m_AP, m_HP
        ' local safe array hack
        APE = ArrPtr(E)
        APS = ArrPtr(S)
        If HPE = 0 Then
            HE(0) = vbInteger: HE(1) = &H910001: HE(2) = 2: HE(5) = &H7FFFFFFF
            HS(0) = vbLong: HS(1) = &H910001: HS(2) = 4: HS(5) = &H7FFFFFFF
            HPE = VarPtr(HE(1))
            HPS = VarPtr(HS(1))
        End If
        ' ubound
        U = L \ 4 - 1
        ' allocate output string
        StrReverse = AllocString(0, L)
        HE(4) = StrPtr(Expression)
        HS(4) = StrPtr(StrReverse)
        ' start safe array hack
        m_H(4) = APE: m_A(0) = HPE
        m_H(4) = APS: m_A(0) = HPS
        ' first character in odd length strings
        If L Mod 4 Then
            S(0) = E(L \ 2 - 1) And &HFFFF&
            HS(4) = HS(4) + 2
        End If
        ' simple loop
        If AllCharBelow0x8000 Then
            For M = U To 0 Step -1
                M2 = M * 2
                C1L = E(M2)
                C2L = E(M2 + 1)
                I = U - M
                S(I) = C1L * &H10000 Or C2L
            Next M
        Else
            For M = U To 0 Step -1
                M2 = M * 2
                C1 = E(M2)
                C2 = E(M2 + 1)
                I = U - M
                S(I) = &H80000000 * ((C1 And &H8000&) \ &H8000&) Or (C1 And &H7FFF&) * &H10000 Or (C2 And &HFFFF&)
            Next M
        End If
        ' end safe array hack
        m_H(4) = APE: m_A(0) = 0
        m_H(4) = APS: m_A(0) = 0
        m_H(4) = m_AP: m_A(0) = 0
    End If
End Function

Public Sub GetByte(ByVal Ptr As Long, Value As Byte)
    Procedure(AddressOf Strings.GetByte) = API("msvbvm60", "GetMem1")
    GetByte Ptr, Value
End Sub

Public Sub GetInteger(ByVal Ptr As Long, Value As Integer)
    Procedure(AddressOf Strings.GetInteger) = API("msvbvm60", "GetMem2")
    GetInteger Ptr, Value
End Sub

Public Sub GetLong(ByVal Ptr As Long, Value As Long)
    Procedure(AddressOf Strings.GetLong) = API("msvbvm60", "GetMem4")
    GetLong Ptr, Value
End Sub

Public Sub GetCurrency(ByVal Ptr As Long, Value As Currency)
    Procedure(AddressOf Strings.GetCurrency) = API("msvbvm60", "GetMem8")
    GetCurrency Ptr, Value
End Sub

Public Sub PutLong(ByVal Ptr As Long, ByVal Value As Long)
    Procedure(AddressOf Strings.PutLong) = API("msvbvm60", "PutMem4")
    PutLong Ptr, Value
End Sub

Public Sub PutLong2(ByVal Ptr As Long, ByVal Value As Long)
    Procedure(AddressOf Strings.PutLong2) = Procedure(AddressOf Strings.z_PutLong)
    PutLong2 Ptr, Value
End Sub

Public Sub z_PutLong(Ptr As Long, ByVal Value As Long)
    Ptr = Value
End Sub

Public Sub rtlMove(ByVal Dest As Long, ByVal Src As Long, ByVal Length As Long)
    Procedure(AddressOf Strings.rtlMove) = API("kernel32", "RtlMoveMemory")
    rtlMove Dest, Src, Length
End Sub

Public Sub rtlStringToPtr(ByVal Dest As Long, ByVal Src As String, ByVal Length As Long)
    Procedure(AddressOf Strings.rtlStringToPtr) = API("kernel32", "RtlMoveMemory")
    rtlStringToPtr Dest, Src, Length
End Sub
