Click here to Skip to main content
Email Password   helpLost your password?

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.

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

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
GeneralSlightly confused
mitchell50
16:50 20 Dec '06  
In both articles about pointers, the author refers to an integer being 2 bytes in length in VB. In the code, the variables are dimensioned as Long, which is a signed 32 bit integer and requires 4 bytes in memory. If the SInt16 is stored at the base address of the variable by CopyMem in little endian, then subsequent values would be overwritten by the Long integer. In other words, wouldn't we be trying to put 4 bytes into a 2-byte memory address? It's late and I may be missing something obvious so humor me.
Generalobject browser
_robb_
9:47 9 Aug '06  
Hello!

I'm a new one here and I have a problem...
I’m not quite shore what do I have to do to get
those three hidden functions – ObjPtr, StrPtr and VarPtr.
when i open the "object browser" I can't find the VBA library and
the _HiddenModule class...

the other problem is the declaration of the next function:

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

"Any" is not supported - I must have forgotten something.. but I don't know what!?!!!

Please help me!! Thanks


GeneralASP string problem
akshakeel2k
3:52 26 May '06  
have a string extracting from a piece of text passed from one asp page to another.
when i print the string using Response.write its printing exactly the string without any problem, but when i get its length, its returning 5+the actual length.
this creates problem when i insert into database. its inserting some non-readable data along with the string.

But the following code,



Dim str
str = "abcd"
Response.write str
Response.write len(str)



is returning abcd and 4 properly.

but in my case, where i had to extract my string from http text passed from one page to another, the length gives 9.

Please help me how to work around this issue.

shakeel
Generalchange declaration pointer parameter function
Joe_Valenz
12:55 8 Jun '04  
Dear:
I have a problem.

See my code:

short AC_ADT_Capture(
unsigned long CaptureID,
unsigned long CapturePurpose,
short GrabImage,
unsigned char** CaptureOutputTemplate,
unsgined long* CaptureOutputTemplateSize
);

How I can change this declaration in Visual Basic?

Thanks for you help.

Jorge.

Joe_Valenz
Generaldata handling
Anonymous
11:31 11 Jan '04  
Using this techniques, shall we copy a file's data present in the disk into a object. Like, a 12 mb of students name present in a data file can be write in a grid. I think, if this is possible then populating large number of data into control like combo boxes, grids can be done in very speed manner.

Is this makes sense Roll eyes

-VK
GeneralRe: data handling
Anonymous
11:47 11 Jan '04  
I uses this code to copy a data present in a object to other object. as iam a newbie to this i may wrong, please let me know what is the wrong with the following code:-

Option Explicit Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _
(Destination As Any, Source As Any, ByVal Length As Long)
Private Sub Form_Load()

Dim a1 As New Collection
Dim a2 As New Collection

a1.Add "vadivel kumar"
CopyMemory ByVal VarPtr(a2), ByVal VarPtr(a1), 4
Debug.Print a2.Count ' displays 1 and it is correct but after this it gets crashes
End Sub

Thanks,

- VK Blush
GeneralRe: data handling
UB
6:29 13 Jan '04  
Try this.

Dim a1 As New Collection
Dim a2 As New Collection

a1.Add "vadivel kumar"
CopyMemory ByVal VarPtr(a2), ByVal VarPtr(a1), 4
Debug.Print a2.Count

CopyMemory ByVal VarPtr(a2), 0&, 4 // added new code - UB
'CopyMemory a2, 0&, 4 ' // also correct - UB

The reason for crashing is, in VB when a function goes out of scope it destroys all the variables. So when the object variables are being destroyed if the variable is pointing to some valid object in memory then that object memory is freed, else it is ignored. VB does this for all variables in the function's scope. In your example both object variables (a1, a2) are pointing to the same object in memory. The first one get freed, and when VB tries to free the second one, it is already freed. So it crashes. We can eliminate this problem by setting a null pointer to variable a2.

By the way check this out, I'm sure you'll like it.
http://www.vbaccelerator.com/codelib/imalloc/objstore.htm[^]

UB

You may stop this individual, but you can't stop us all... after all, we're all alike. +++Mentor+++
GeneralFYI: Win32 API Programming with Visual Basic
Mike Klimentiev
9:18 22 Dec '03  
People interested in the topic may lookup their copy of MSDN Library for a chapter of "Win32 API Programming with Visual Basic" by Steven Roman, 1999



MK
GeneralFormatting
Uwe Keim
2:29 20 Dec '03  
What about removing all those "...class=MsoNormal style=TEXT-ALIGN: justify..." and those hords of " "?

--
- Free Windows-based CMS: www.zeta-software.de/enu/producer/freeware/download.html - See me: www.magerquark.de - MSN Messenger: uwe_keim@hotmail.com

GeneralRe: Formatting
UB
7:28 20 Dec '03  
Formatting has been done, pls let me know if there's anyting else.

UB
GeneralRe: Formatting
Uwe Keim
9:38 20 Dec '03  
Nothing, I've just voted Smile

--
- Free Windows-based CMS: www.zeta-software.de/enu/producer/freeware/download.html - See me: www.magerquark.de - MSN Messenger: uwe_keim@hotmail.com

GeneralRe: Formatting
UB
18:48 20 Dec '03  
Hey ... I really appreciate it - Thanks ! Smile

UB
Generalcopying objects
Paolo Messina
10:30 19 Dec '03  
Do not use CopyMemory to assign an object to another, like in the last example. You are only copying the address of a COM interface, without reference counting. That's the cause of the access violation errors.

I don't know how to use the return value of ObjPtr in API calls, but don't use it to copy objects.

Paolo

------
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
dog_spawn
13:47 19 Dec '03  
This is an interesting article but I am left wondering what the actual point of any of the techniques are. As Paolo shows, you should not be using these functions for the wrong purpose. So, my question to the article authour is: is there a good reason for knowing about these functions or are they just interesting and nothing more?
GeneralRe: copying objects
UB
6:54 20 Dec '03  
I know i have only pointed out some techniques ... but you can actually use these functons. StrPtr can be used to create much faster string handling routines (sorting, swapping) and ObjPtr can be used for subclassing. A subject like subclassing won't fit into this article and it will get too lengthy. The purpose of this article is only to show that pointers can be used in VB also with the aid of these functions. So after learning that functions like these exist in VB it's totally upto the reader to search more about them and make use of them.

UB
GeneralRe: copying objects
AnonymousToo
5:39 21 Dec '03  
dog_spawn wrote: So, my question to the article authour is: is there a good reason for knowing about these functions or are they just interesting and nothing more?
The point is, you can use pointers in VB just like you can use C struct in C++. It may not be useful in most VB programs because the problems VB developers want to solve are different from those for C++ developers, however this knowledge will be handy in some special situations.
GeneralRe: copying objects
AnonymousToo
5:53 21 Dec '03  
Paolo Messina wrote: Do not use CopyMemory to assign an object to another, like in the last example. You are only copying the address of a COM interface, without reference counting. That's the cause of the access violation errors.
Since we are talking about VB here, what's wrong with the following:
CopyMemory objA, objB, 4 objA.AddRef
Then you should not have a problem when the object is destroyed (but I haven't tried it myself Smile ).

GeneralRe: copying objects
Paolo Messina
7:59 21 Dec '03  
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
UB
7:42 22 Dec '03  
You mean ObjPtr right? ... not ObjStr. I had to use it once to subclass a user control. I was having trouble with seperate instances of the user control. Then I saw an article in the Knowledgebase - HOWTO: Subclass a UserControl, which describes how to do it with the help of ObjPtr function. (The return value itself is used) So I think that's one place you gonna need it. If you can pls, check the MSDN Documentation and let me know if there's another way to do it without using ObjPtr. Wink

UB

You may stop this individual, but you can't stop us all... after all, we're all alike. +++Mentor+++
GeneralRe: copying objects
Paolo Messina
8:22 22 Dec '03  
I read the KB article you were referring to (179398), and found the line where ObjPtr is used:
Call SetWindowLong(hWnd, GWL_USERDATA, ObjPtr(Me))
You need to use ObjPtr here only because the last argument to SetWindowLong is declared as Long. Write an alias for pointers and you won't need ObjPtr anymore:
      Public Declare Function SetWindowLongPtr _
Lib "user32" Alias "SetWindowLongA" _
(ByVal hWnd As Long, _
ByVal nIndex As Long, _
dwNewLong As Any) As Long
But be careful and use it only with objects, they will be passed as pointers automatically.

Paolo

------
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
UB
9:06 22 Dec '03  
Thanks! I really appreciate it. It didn't struck me at first, 'cuz I used that coding long time back. Yes of course, if it is declared as Any a pointer would be passed automatically. Sorry to trouble you. Thanks again.

UB

You may stop this individual, but you can't stop us all... after all, we're all alike. +++Mentor+++
GeneralRe: copying objects - Problem
drb05050
5:44 9 Dec '04  

When I run this code (assigned values for intA and B are arbitrary)


Dim IntA, IntB As Integer

IntA = 111
IntB = 999

CopyMemory IntB, IntA, 2


IntB becomes 2; if I assign A as -9876 or something, it sometimes sets B to 3

This however:


Dim IntA, IntB As Integer

IntA = 111
IntB = 999

CopyMemory IntB, 111, 2

works as expected

I'm guessing it's a problem with some keyword in the declarations that I neglected to set

Thanks,

db

GeneralRe: copying objects - Problem
daChug
13:04 16 Sep '05  
In this case IntA is not an Integer.

Try
Dim IntA as Integer
Dim IntB as Integer

and you'll have better luck.

To see for yourself Debug.Print(VarType(IntA)) will expose a 0 for an unitialized type.


Last Updated 19 Dec 2003 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010