Some people out there say that you can't manipulate pointers in VB. You can't blame them really, the 3 built-in functions that makes pointers in VB possible are largely undocumented. But without them, VB's power would be greatly diminished.
Besides those 3 functions, there is one other API function which is a VB guru's best friend and makes those pointers more then just pretty to look at. Those three, and that one API will be discussed in this lesson. StrPtr() VarPtr() ObjPtr() and CopyMemory() API.
First, let's go over a few definition:
Pointer = The numerical address of a block of memory.
Allocate = To set aside a block of memory for use
Variable = The name, supplied for programmatic convenience, for a block of allocated memory. When compiled, these names are resolved to POINTERS.
ByVal Operator = To make sure the VALUE of a variable and not the POINTER to the variable is passed to a function.CopyMemory(pDest As Any, pSrc As Any, ByVal ByteLen As Long) API Sub
All this very powerful function does is copy a block of memory from one location to another. It's pretty basic, you supply it with the destination pointer (pDest), the source pointer (pSrc), and the number of bytes to copy (ByteLen). In the declaraion you see how it says pDest and pSrc As Any
? That means, you can supply any variable you want to the function. At compile time the variable will be replaced with the variable pointer. See that 'ByVal' beside ByteLen? That's to make sure the VALUE of Var3 is passed to the function rather than the Var3 POINTER. Without the ByVal, even though Var3 may contain the value of 3. The pointer may be something like 1606088. See the diagram below:
Var1 = "Jim"
Var2 = ""
Var3 = Len(Var1) + 1 '+1 = null terminator
CopyMemory Var1, Var2, Var3
Var1's Pointer is: 1579328
Var2's Pointer is: 1644472
Var3's Pointer is: 1606088
After you compile, it will look like this:
CopyMemory 1579328, 1644472, 4
(copy 4 bytes from 1579328 to 1644472)
CopyMemory 1579328, 1644472, 1606088
(copy 1606088 bytes from 1579328 to 1644472)
As you can see, we want the VALUE, and NOT the POINTER of the number of bytes to copy. However, in the case of the pDest and pSrc, we want the POINTER, and NOT the VALUE. In case you're curious, watch what happens if we stuck a ByVal in front of pDest and pSrc in the declaration.
CopyMemory 74, 0, 4
(copy 3 bytes from 74 to 0)
See what happened? Since I used ByVal, I returned the VALUE of Var1 and Var2 instead of their POINTERS. The first byte in Var1 is 'J' and the ASCII value of 'J' is 74. Var2 is a blank variable so it's first byte is NULL, or 0. You do realize, that if you tried to do that, VB would crash.
So be careful, if you don't know your pointers very well, VB will be crashing like a mofo.VarPtr() Function
This function returns the Variable Pointer
to a given variable. Usually this function isn't very necessary cause it is the same value as your variable when compiled.
'Return the pointers to Var1 and Var2
Ex 1: CopyMemory Var1, Var2, Var3
'Return the value of the 2 variables (crash alert!)
Ex 2: CopyMemory ByVal Var1, ByVal Var2, Var3
'Return the VALUE of the variable pointer
Ex 3: CopyMemory ByVal VarPtr(Var1), ByVal VarPtr(Var2), Var3
Now see, the value of the variable pointer iiiiiiiiiiis... the pointer itself. Duh. Example 1 and Example 3 does the same thing. So VarPtr() isn't very useful in this case.StrPtr() Function
This function returns the String Pointer
within a string variable. You see, I lied earlier when I said the VALUE of Var1 starts with 'J' or 74. I was just making a point. Visual Basic stores some internally useful information at the variable pointer like what datatype it is and how many bytes is stored and such. The REAL string pointer can be returned with this StrPtr() function.
CopyMemory Var1, Var2, Var3
Remember that? If Var1 and Var2 are string variables then we're in trouble! You'll be writing over the Var1's variable information which VB requires to keep track of it's variables! Talk about a major boom! Instead, you'd want this:
CopyMemory ByVal StrPtr(Var1), ByVal StrPtr(Var2), Var3
This way we'll be overwriting Var1's STRING with Var2's STRING. We get the exact memory location of those strings with StrPtr(). Ya follow? Now you still gotta be careful. Don't try to write a big string to a small string. Like in the example above with writing Jim to a blank variable. Not a good idea. VB still thinks that Var2 is still blank cause the information located at the variable pointer hasn't changed. But you can do this with no crashes.
Var1 = "123"
Var2 = "456"
CopyMemory ByVal StrPtr(Var1), ByVal StrPtr(Var2), 3
Now, Var1 is equal to "456".ObjPtr() Function
This function returns a pointer to an OBJECT. Objects are stored in memory like everything else. And like everything else they have to start somewhere, well, that somewhere is the pointer to the Object. The value that replaces the object name when you compile.
I've only used this pointer once. In my TCP WorkShop project, I had a listbox which displayed all current telnet connections. Also, each telnet session had a window into which you type and recieve text. If I right-click an item in the listbox and say "Close Connection", then I want to close the matching window. I could do things the normal way... I could loop through all the loaded windows and look for the matching one. But this is inefficient, and I could have like 50 telnet sessions going at once. So instead, I saved the window's Object Pointer in the matching listitem. So if I needed to close the window matching a listitem, I could retrieve the pointer again (a LONG value) and using CopyMemory to store it into a Object Variable. I created the object variable from a pointer! Ugh, believe me, that took like 20 crashes for me to get right. Here's the code:
Public Sub GetForm(Pointer As Long) As Form
Dim oForm As Form
'Copy the 4 byte pointer into the object variable temporarily
CopyMemory oForm, Pointer, 4
'Now store the hacked object into a legit VB form object
Set GetForm = oForm
'Now reset the variable so VB doesn't crash
CopyMemory oForm, 0, 4
End SubAddressOf Operator
To make sure the POINTER of FunctionA is passed to FunctionB rather than the return value of FunctionA. Functions are no different than variables. Function names resolve to a pointer like anything else. It's just that THIS pointer doesn't point to a chunk of stored data. It points to code which is executed and returns a value. The main thing AddressOf is good for is API. Sometimes you need to tell Windows to call one of your functions if something happens. In that case, you must pass the function pointer to the API function so that it knows where your function location in memory is.
Look at the difference below:
ReturnValue = FunctionA(FunctionB)
If you call FunctionA like that, then FunctionB will be executed first and it's return value will be passed to FunctionA.
ReturnValue = FunctionA(AddressOf FunctionB)
However, in this case FunctionA will just recieve the pointer to FunctionB. A LONG value.
If anybody should find that I'm wrong on any point (which is possible), then let me know and I'll thoroughly explore the issue and correct myself.