Pointers and CopyMemory
This article is based on Visual Basic 6. Find other Visual Basic 6 articles. |
If you're totally new to the concept of pointers, don't bother with this article. Having said that...
Pointers in VB?
Yes, that's right, it IS possible to use pointers in VB, although the fucnctions to do so are not documented, and at times it can be rather, erm, dodgy, so to speak.
3 Types of Pointers
VB defines 3 different types of pointers for different variable types, and those are Strings, Objects, and any other kind of variable (other than strings or objects). Their corresponding functions are as follows:
- StrPtr
- ObjPtr
- VarPtr
As aforementioned, these functions are NOT documented. Perhaps MS just 'forgot' to include them... *cough*
Anyway, I will begin with VarPtr, since it is relatively simple to understand.
VarPtr
This function will return the pointer to any kind of variable (hence its one parameter is defined as:
Ptr As Any
The main use for this is in callbacks/use with APIs in general. I shan't go into detail with this, other than to say that it is the equivalent of *myVar in C, and can be used with CopyMemory, but MUST be passed ByVal, otherwise your app jsut crashes.
StrPtr
This function perhaps requires a little more explanation. Since Version 4, VB has not used the standard C-type null-terminated char*/wchar* (or LPSTR/LPWSTR), but instead has used bstr, an entirely (well almost) different construct. In terms of what's going on in the memory, this means that 4 bytes before the actual start of the string data is stored an integer value that contains the length of the string. The string is also null-terminated to provide compatibility with C, the usefulness of which we will see in just a second. This necessitates an extra function to return the real position of the start of the string in memory - i.e. StrPtr().
As a demonstration of this, you might try the following code:
Private Declare Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" _ (ByRef Destination As Any, ByRef Source As Any, ByVal Length As Long) Private Sub Form_Load() Dim s As String Dim sLen As Long s = "test" CopyMemory sLen, ByVal StrPtr(s) - 4, 4 Debug.Print sLen End Sub
If you look at the Immediate window, you will see that '8' is the output of this. Obviously this is twice the actual length of the string, which would make no sense if VB weren't based around Unicode. Thankfully it is, so this is not utter nonsense-gibberish. Anyway...
Where this comes in handy is when you're writing your own API DLLs in a C language. There is usually some difficulty passing variables of unicode string types between C and VB. This solves the problem. If you have a function like this in C++:
void __stdcall foo(wchar *lpstring) { OutputDebugStringW((LPSTR)lpstring); }
Then you can quite easily pass this string to the DLL using StrPtr. The function would be declared in VB as follows:
Declare Sub foo Lib "myLib.dll" (lpstring As Long)
And pass a string to it like this:
Dim myString As String myString = "test" foo ByVal StrPtr(myString)
This should trace 'test' in your output in the C++ debugger of your choice. Note that I have used wchar and OutputDebugStringW in the C++ code. Usually when you call an API, VB will convert strings to ANSI for you, however, it will not do this when you use StrPtr, which allows you to pass a Unicode string in its full glory over to your C functions.
ObjPtr
ObjPtr does something else useful. It will give you the pointer to your object reference. Note: a pointer is NOT the same as a reference. The first 4 bytes after your object pointer will be the object reference. This knowledge allows you to do something incredibly useful: get callbacks from modules into class modules. For an example of how to do this, see Modularised Subclassing using interfaces and CopyMemory.
That's just about it. Pointers can do fun and funky things but they usually don't have that much application in VB, except in the special cases described above. Obviously there are PLENTY more applications, and if anyone feels the requirement to include them, then please feel free to do so. I haven't done so because I don't see it as necessary and can't be bothered.