CopyMemory and Arrays: Proper Use

The Tricky Part

I mentioned that the calculation of the number of bytes to be moved was tricky. Well, it is because Visual Basic will pad certain UDT's with non-used bytes. But what does this mean? I'll detail this with an example.

Look at the following UDT:

Private Type TestType
    var1 As Long
    var2 As Integer
    var3 As Single
End Type

TestType seems to occupy 10 bytes: 4 bytes for the long (var1), 2 bytes for the integer (var2), and 4 bytes for the single number (var3). However, if you run the following code snippet you will prove this is not correct.

Public Sub Main()

Dim myVar As TestType

    MsgBox "LenB(myVar) = " & CStr(LenB(myVar)), vbInformation
End Sub

The message box will read "LenB(myVar) = 12". This can only mean one thing: Visual Basic will align the second variable in memory so it occupies 4 bytes instead of 2. This is normally referred to as DWORD alignment.

NOTE: DWORD stands for "double word", and it is a term that comes from the old computing days. A Word is two bytes, a DWORD is four bytes, and now with the introduction of 64-bit machines, a QWORD (quad word) is 8 bytes. Windows programming in C++ have maintained this nomenclature.

If you like, you can mess with the order of the variables in TestType. If you do, you will notice that if the integer goes down to the last position like in the following UDT, LenB() will return the original expected result: 10. A new piece of information for the resolution of this puzzle: A 2-byte variable will not be DWORD-aligned if it is at the end of the UDT.

Private Type TestType
    var1 As Long
    var3 As Single
    var2 As Integer
End Type

Now let's try with one-byte variables. Run the previous test with this UDT declaration:

Private Type TestType
    var1 As Long
    var2 As Byte
    var3 As Single
End Type

The result is 12 bytes again. But what about this next one?

Private Type TestType
    var1 As Long
    var3 As Single
    var2 As Byte
End Type

The result is 9 bytes, the result we could have obtained by manually adding up the bytes for each data type. Now the puzzle is almost complete. Let us see what happens with a more complex UDT:

Private Type TestType
    var1 As Long
    var2 As Byte
    var4 As Byte
    var3 As Single
End Type

This one returns 12 too. The following also yields 12.

Private Type TestType
    var1 As Long
    var2 As Integer
    var4 As Integer
    var3 As Single
End Type

Summarizing...

What can we say about these tests? Well, we can say that all variables not occupying a multiple of 4 bytes in the middle of a UDT declaration (the order of declaration determines the order they are stored in memory) will get padded so they are DWORD-aligned.

And to wrap this result up with CopyMemory, I must say that the number of bytes is of PARAMOUNT importance because you will not get the correct results if you do not use the correct number of bytes. This could happen if you confuse LenB() with Len(), or if you hardcode the number of bytes occupied by a UDT.

To finally complete the discussion on CopyMemory and UDTs and arrays, I must note a few restrictions of use. Please read the next page of this article.

You might also like...

Comments

Contribute

Why not write for us? Or you could submit an event or a user group in your area. Alternatively just tell us what you think!

Our tools

We've got automatic conversion tools to convert C# to VB.NET, VB.NET to C#. Also you can compress javascript and compress css and generate sql connection strings.

“Beware of bugs in the above code; I have only proved it correct, not tried it.” - Donald Knuth