Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Pointers in Visual Basic using Undocumented Functions

0.00/5 (No votes)
18 Dec 2003 1  
VB->Pointers using VarPtr, StrPtr, ObjPtr and CopyMemory API

Introduction

Some of you may think that I've got the title wrong, well... sometimes I get them mixed up, but not this time. You can do pointers in Visual Basic. There’s another nice article on “How to do pointers in Visual Basic”, and I recommend you to read it before or after reading this article if you haven't read it yet.

Undocumented Functions

Now let’s see what these undocumented functions are. Get the Object Browser window and select VBA library, right click on Object Browser and select show hidden members from the menu. Now select _HiddenModule class, and you can see three hidden functions – ObjPtr, StrPtr and VarPtr. These functions are not documented as Microsoft does not guarantee they will be available in future releases of VB.

  • VarPtr - gives the memory address of a variable
  • StrPtr - gives the memory address of the contents of a string
  • ObjPtr - gives the memory address of the object (interface)

Surely we can view variables’ memory addresses with these functions, but something is missing. How can we set the contents of a memory address? To do that, we need the API function CopyMemory which is in kernel32.dll.

Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _
                   (Destination As Any, Source As Any, ByVal Length As Long) 

This function copies a block of memory, from one memory address to another. Note that according to the declaration, Destination and Source are passed by reference (default is ByRef) which means that CopyMemory function is expecting memory addresses for the Destination and Source arguments. Although they are declared as ByRef we can override it by including ByVal in our call (override ... don't you love that word?). Finally look at that Any data type. Any means that we can pass “any” data type for Destination and Source arguments, but ultimately what is being passed is a 4-byte long memory address. Keep this in mind. It's very important when working with Win32 API.

Using VarPtr

A pointer is a variable which contains the address in memory of another variable. In Windows, it takes 4 bytes to hold a memory address. So if we want to declare a pointer in VB, we must use the Long data type.

Take a look at this code sample:

Dim myInt As Integer         
Dim ptr As Long            ' Long pointer – need 4 bytes to hold a memory address
    
ptr = VarPtr(myInt)        ' ptr now points to myInt
Debug.Print ptr            ' this will print the memory address of myInt
    
CopyMemory ByVal ptr, 123, 2    ' copy 2 bytes (Integer size - 2 bytes)
   
Debug.Print myInt            ' now contains the value 123

If you run this code, the value 123 will be copied to the memory address of myInt, so at the end myInt will contain the copied value 123.

Now take a closer look at this line:

CopyMemory ByVal ptr, 123, 2    ' copy 2 bytes (Integer size - 2 bytes)  

Variable ptr is a pointer to myInt, in other words ptr holds the memory address of myInt. So if we write this without ByVal keyword, what happens? The memory address of ptr will be passed instead of the memory address of myInt because Destination is declared as ByRef (default).

Without any hassle, we can re-write this like the following:

CopyMemory myInt, 123, 2

So myInt is passed as ByRef, in other words the memory address of myInt is passed, which is exactly what we want to do. Remember this small tip: When the memory address that you want to pass is in a variable, you must use ByVal keyword to override the ByRef.

If we want to copy the value of variable intA to variable intB we can do it by writing either:

CopyMemory ByVal VarPtr(intB), ByVal VarPtr(intA), 2

or:

CopyMemory intB, intA, 2

Hope you don't have any doubts about CopyMemory or VarPtr now. Let's move on to StrPtr.

Using StrPtr

Did you ever wonder how the Len(str) function works. Well, you might guess it counts the characters from the beginning of string until a null character is found. Guess again, this is not the way VB handles strings. When we declare a variable of type String we are declaring a member of a data type called BSTR which stands for Basic String. BSTR is a pointer to a Unicode (2-bytes per character) character array that is preceded by a 4-byte length field and terminated by a single 2-byte null character. Look at the below figure to get a better understanding.

So when we write the code:

Dim str as string
str = "hello"

Variable str is actually a member of type BSTR which is holding the memory address to the beginning of actual Unicode character array. Notice that it is not pointing to the 4-byte length field. This length field holds the number of bytes excluding the terminating null. So "hello" takes 10 bytes when represented in Unicode.

Dim str As String
Dim length As Long                  ' variable to hold the length of string
Dim ptrLengthField As Long          ' pointer to 4-byte length field
          
str = "hello"
Debug.Print StrPtr(str)             ' address of the character array
    
ptrLengthField = StrPtr(str) - 4    ' length field is 4 bytes behind

' // CopyMemory ByVal ptrLengthField, 200&, 4
CopyMemory length, ByVal ptrLengthField, 4

' // this is also correct
' // CopyMemory ByVal VarPtr(length), ByVal ptrLengthField, 4

Debug.Print length                  ' number of bytes (without null terminator)
Debug.Print Len(str)                ' number of characters

Before you run this code, let's clear things out. Examine this line:

ptrLengthField = StrPtr(str) - 4    ' length field is 4 bytes behind

StrPtr(str) gives the address to the character array, so we have to reduce 4 bytes to get the address to the length field.

Take a look at this line:

CopyMemory length, ByVal ptrLengthField, 4

The variable ptrLengthField is holding the memory address to the length field of str, so we have to use the ByVal keyword to pass it by value.

Now run the code and the output of:

Debug.Print length                  ' number of bytes (without null terminator)
Debug.Print Len(str)                ' number of characters

will be:

10
5

Variable length is set to 10, because of Unicode, "hello" takes 10 bytes, and Len(str) returns 5 which is the number of characters in "hello". Now let’s find out how Len() function really works!

Uncomment this line:

CopyMemory ByVal ptrLengthField, 200&, 4

What happens here is the value 200 is copied to the length field of str replacing the original value of 10. The & sign in 200& is there to say that treat 200 as a Long (type declaration character for Long is &) .

Run the code, and the output of:

Debug.Print length                  ' number of bytes (without null terminator)
Debug.Print Len(str)                ' number of characters

will be:

200
100

We get 100 for Len(str) when str contains "hello", huh ? So VB has returned us the value of length field divided by 2. I think now you know how Len() works for strings.

Using ObjPtr

Finally we'll see ObjPtr in action.

Dim obj As New Form1
Debug.Print ObjPtr(obj) ' gives the address to the object (new instance of Form1)
Debug.Print VarPtr(obj) ' gives the address to the variable - obj

There’s nothing to explain here. Here’s another simple code sample.

Dim objA As New Form1
Dim objB As New Form1

Debug.Print "before"
Debug.Print ObjPtr(objA)
Debug.Print ObjPtr(objB)

Set objA = objB

Debug.Print "after"
Debug.Print ObjPtr(objA)
Debug.Print ObjPtr(objB)

The output will be:

before
 1849600 
 1761448 

after
 1761448 
 1761448

As you can see, after the line:

Set objA = objB

objA now points to the same memory location as objB, as it should be. You can also replace the above line with the following:

CopyMemory ByVal VarPtr(objA), ByVal VarPtr(objB), 4

or the much simpler version:

CopyMemory objA, objB, 4

It works, but don't use this kind of coding to set objects because sometimes an illegal operation is thrown when objects are being destroyed.

That's it. These functions are used in fast string handling routines and subclassing. I am not going to talk about them here, 'cuz .. err ... I don't have a clue about them. Remember ... I can only show you the door, you are the one that has to walk through it!

Happy coding !!!

History

  • 18th December, 2003: Initial post

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here