Click here to Skip to main content
15,867,308 members
Articles / Programming Languages / VBScript

Pointers in Visual Basic using Undocumented Functions

Rate me:
Please Sign up or sign in to vote.
4.64/5 (26 votes)
18 Dec 2003CPOL5 min read 205.9K   25   26
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.

Image 1
  • 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.

VBScript
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:

VBScript
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:

VBScript
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:

VBScript
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:

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

or:

VBScript
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.

Image 2

So when we write the code:

VBScript
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.

VBScript
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:

VBScript
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:

VBScript
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:

VBScript
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:

VBScript
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:

VBScript
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.

VBScript
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.

VBScript
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:

VBScript
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:

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

or the much simpler version:

VBScript
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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
UB
Web Developer
Sri Lanka Sri Lanka
Expect The Unexpected!

Comments and Discussions

 
QuestionCopyMemry Problem in Vb6 at design-Time Pin
Member 1473653617-Aug-20 6:57
Member 1473653617-Aug-20 6:57 
QuestionYou got length from strptr, but where did you copy the contents to? Pin
vsrawat16-Dec-15 8:31
vsrawat16-Dec-15 8:31 
GeneralMy vote of 5 Pin
Paulo Buchsbaum30-Nov-12 17:33
Paulo Buchsbaum30-Nov-12 17:33 
GeneralSlightly confused Pin
mitchell5020-Dec-06 15:50
mitchell5020-Dec-06 15:50 
Generalobject browser Pin
_robb_9-Aug-06 8:47
_robb_9-Aug-06 8:47 
GeneralASP string problem Pin
akshakeel2k26-May-06 2:52
akshakeel2k26-May-06 2:52 
Generalchange declaration pointer parameter function Pin
Joe_Valenz8-Jun-04 11:55
Joe_Valenz8-Jun-04 11:55 
Generaldata handling Pin
Anonymous11-Jan-04 10:31
Anonymous11-Jan-04 10:31 
GeneralRe: data handling Pin
Anonymous11-Jan-04 10:47
Anonymous11-Jan-04 10:47 
GeneralRe: data handling Pin
UB13-Jan-04 5:29
UB13-Jan-04 5:29 
GeneralFYI: Win32 API Programming with Visual Basic Pin
Mike Klimentiev22-Dec-03 8:18
Mike Klimentiev22-Dec-03 8:18 
GeneralFormatting Pin
Uwe Keim20-Dec-03 1:29
sitebuilderUwe Keim20-Dec-03 1:29 
GeneralRe: Formatting Pin
UB20-Dec-03 6:28
UB20-Dec-03 6:28 
GeneralRe: Formatting Pin
Uwe Keim20-Dec-03 8:38
sitebuilderUwe Keim20-Dec-03 8:38 
GeneralRe: Formatting Pin
UB20-Dec-03 17:48
UB20-Dec-03 17:48 
Generalcopying objects Pin
Paolo Messina19-Dec-03 9:30
professionalPaolo Messina19-Dec-03 9:30 
GeneralRe: copying objects Pin
dog_spawn19-Dec-03 12:47
dog_spawn19-Dec-03 12:47 
GeneralRe: copying objects Pin
UB20-Dec-03 5:54
UB20-Dec-03 5:54 
GeneralRe: copying objects Pin
AnonymousToo21-Dec-03 4:39
sussAnonymousToo21-Dec-03 4:39 
GeneralRe: copying objects Pin
AnonymousToo21-Dec-03 4:53
sussAnonymousToo21-Dec-03 4:53 
GeneralRe: copying objects Pin
Paolo Messina21-Dec-03 6:59
professionalPaolo Messina21-Dec-03 6:59 
I didn't know you can call AddRef on VB objects. Anyway, there's no point in using this technique to copy objects. Just use the VB assignment operators.

A real example of use for the pointer returned by ObjPtr would have been nice. For example some API function. But since you can pass a VB object by reference with no special syntax, what's the point of using ObjPtr anyway? Wink | ;)

Paolo

Mod: ObjStr/ObjPtr

------
Why spend 2 minutes doing it by hand when you can spend all night plus most of the following day writing a system to do it for you? - (Chris Maunder)
GeneralRe: copying objects Pin
UB22-Dec-03 6:42
UB22-Dec-03 6:42 
GeneralRe: copying objects Pin
Paolo Messina22-Dec-03 7:22
professionalPaolo Messina22-Dec-03 7:22 
GeneralRe: copying objects Pin
UB22-Dec-03 8:06
UB22-Dec-03 8:06 
GeneralRe: copying objects - Problem Pin
drb050509-Dec-04 4:44
sussdrb050509-Dec-04 4:44 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.