Byte type (Array) and CopyMemory
As a prelude to moving on finally to the main reason for a lot of this Thread, (VB strings in the win32 api), a review of the connection to Byte type arrays and strings and an introduction to byte type arrays in the CopyMemory function is worthwhile.
1 to 1 Byte to string character phenomena, arrByte()="xyz"
This "phenomena" has crept up a few time in previous discussions, and it is quite useful to us. Briefly, this "phenomena" that we observe is that things like the following do not error, but rather seem to give us a simple way to go convert from a string of characters directly to the Unicode byte array of code point numbers as represented by the Microsoft Unicode Encoding of UTF-16 LE*
Dim Harry() As Byte, pBSTR As String
Let pBSTR = "A" & "…" & "e"
Let Harry() = pBSTR
Let Harry() = "A" & "…" & "e"
Debug.Print Harry()
Here below a few actual working demo codings in Rem 1
Code:
Sub BitesArray() ' https://www.excelfox.com/forum/showthread.php/2824-Tests-Copying-Pasting-API-Cliipboard-issues-and-Rough-notes-on-Advanced-API-stuff?p=17885&viewfull=1#post17885
Rem 1 1 to 1 Byte to string character phenomena, arrByte()="xyz"
Dim Harry() As Byte, pBSTR As String, LngSrc As Long, vTemp As Variant
Let LngSrc = 1
' Let Harry() = LngSrc ' Compile error - No assignment to data field possible
Let pBSTR = "A" & "…" & "e" ' Three characters, ( the middle one is Unicode ChrW(8230) and also it is in most Window Code Pages also AASI Chr(133)
Let Harry() = pBSTR
Let vTemp = Harry() ' This remains as an array
Let vTemp = CStr(Harry()) ' This gives the 3 character string A…e https://i.postimg.cc/XYvP7Wyh/CStr-A-e.jpg https://postimg.cc/CzW7mW7H
Debug.Print Harry() ' A…e
Call DBugPrntArr(Harry()) ' {65, 0, 38, 32, 101, 0} - see https://www.excelfox.com/forum/showthread.php/2824/page3#post17883
' Let vTemp = Len(Harry()) ' oompile error - variable required - assignment to this expression not possible
Rem 2 VBA seems to know when my string ends, and its not at a null character
Dim ByteArray(0 To 11) As Byte, arrByte As Variant
Let arrByte = AddBytesToArray(ByteArray(), Harry())
Call DBugPrntArr(arrByte) ' {65, 0, 38, 32, 101, 0, 0, 0, 0, 0, 0}
Debug.Print arrByte ' A…e
'Call WtchaGot_Unic_NotMuchIfYaChoppedItOff(arrByte) ' "A" & ChrW(8230) & "e" & Chr(0) & Chr(0) & Chr(0)
Let arrByte(10) = 65
Debug.Print arrByte
'Call WtchaGot_Unic_NotMuchIfYaChoppedItOff(arrByte) ' "A" & ChrW(8230) & "e" & Chr(0) & Chr(0) & "A"
End Sub
Code lines like that seem to allow us to either fill a byte type array by simply assigning a string of text characters to the array, or conversely print out a string by using that array of numbers , ( *the Unicode byte array of code point numbers as represented by the Microsoft Unicode Encoding of UTF-16 LE ) , where we might more typically require to pass the string of text characters
So there seems to be some simple equivalent , something like
_____" A…e" < ------- > {65, 0, 38, 32, 101, 0}
In most situations something similar to this, that is to say putting an array to a string somehow, would almost always cause an error. That sounds reasonable, - even if knowing nothing about computers , common sense tells us that a string of text and an array of numbers are different things that are unlikely usually to "fit" together. But in this particular case it "works", or rather it seems that what we would like to have done gets done somehow…. Or maybe it just happens as expected if we look in more detail at what is going on behind the scenes.
So what is going on
We could put it down to one of, or a combination of three things.
_1 We sometimes talk about coerce or coerceing and suggest it is when we do something that cause something to happen, and this can partly be part of _2
_2 VBA is often set to do some things in situations where it may not have all the correct full explicit syntax.
_3 In this particular case, it might just be that the two things are the same or very similar: a VB(A) string is just a chunk of sequential memory containing the bytes representing the characters in the string, at least in the middle section of the full memory place holding it. Similarly, or in some ways exactly the same, an array of bytes ... is just a chunk of sequential memory containing bytes. In other words they are pretty much the same thing, just a different context. When we try to obtain or print out a string in VBA, we know we are "pointed" to the start of this character array. It is perhaps reasonable to assume that when we "point" to a byte array then we are doing the same thing, - going the start of the array. At this point what is seen deep down is indeed the same sort t of thing. VBA is told to give us the character string in the context something wanting a string, whereas in the context of an array, it is just an array of numbers, a "field" of values, of the appropriate type which we may apply to a dynamic array directly, just as we may be more familiar with things like
Dim arrRng() As Variant: Let arrRng() = Range("A1:C1").Value
Dim arrStr() As String: Let arrStr() = Split("a b", " ")
What use is this / significance to our current discussions.
The last bit above tells us that the above possibilities are likely at some point to be useful in any playing around with strings. And that above was by way of reminding revising the "phenomena". So having the abilities to do some convenient things with Byte arrays, leads us on to, that is to say compliments nicely the following. As far as experiments with RtlMoveMemory are concerned, we were passing bytes around, and for the first two parameters , that is to say the locations to copy from or to, we used actual variables. In the simple case of a long things were fairly "safe" and understandable. However as we precede to more complicated variables, copying and pasting bytes into existing variables could be dangerous – for example perhaps putting bytes representing a number where they may have been representing a string or a pointer etc. might get messy. It is therefore perhaps worth considering, for example assigning a Byte array and use that to copy to. We can then consider that array examining that array then in VBA explicitly, rather then looking at what happens when we use a filed variable, as we did in the last long examples.
_.____________
As a simple example, we repeat the last long experiment but pass the copied bytes to a byte array.
In the coding below, in Rem 1, we repeat the section '_2 CopyMemory of all 4 Bytes of a Long in memory The only difference in this coding below is that the first element of a byte array is used for the destination.
I use the same number example, and we on examining the final filled byte array, we see once again from the results that the byte order in memory is in the "back to front" way
Rem 2 is a bit of playing around for fun: I pick the number 65 for the source long variable. In normal maths, with 4 bytes (32 bits) , we would have this,
00000000 00000000 00000000 01000001
, but deep in memory it is
01000001 00000000 00000000 00000000
So when we copy these 4 bytes in the order that they are , we will have in our Byte array
65 0 0 0
(In fact we used a larger byte array, so the full byte array looks finally like
65 0 0 0 0 0 0 0 0 0 0 0 )
When we do the Debug.Print ByteArray() trick of putting a byte array where a string is expected, we will get printed out an A character, ( along with 5 Chr(0) characters which typically we do not see )
Code:
Sub LongLEwithBites()
Dim LngSource As Long
Rem 1
' "Normal" maths Binary 00000001 00000000 00000000 00000000 - if this is "normal typical conventional everyday school maths" binary then its decimal number is 2^24=16777216
Let LngSource = 16777216 ' 2^24=16777216
' In memory,16777216 is 00000000 00000000 00000000 00000001 , - Byte order "back to front" as it were
Dim ByteArray(0 To 11) As Byte
CopyMemory ByteArray(0), LngSource, 4
Call DBugPrntArr(ByteArray()) ' {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0}
Rem 2 "make a string using a long"
' ' "Normal" maths Binary 00000000 00000000 00000000 01000001
Let LngSource = 65 ' 0 0 0 65
' In memory, 65 is 01000001 00000000 00000000 00000000 , - Byte order "back to front" as it wereCopyMemory ByteArray(0), LngSource, 4
' 65 0 0 0
Call DBugPrntArr(ByteArray()) ' {65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
Debug.Print ByteArray() ' 65 0 0 0 0 0 0 0 0 0 0 0
'Call WtchaGot_Unic_NotMuchIfYaChoppedItOff(ByteArray()) ' "A" & Chr(0) & Chr(0) & Chr(0) & Chr(0) & Chr(0)
End Sub
Bookmarks