Link to home
Start Free TrialLog in
Avatar of Gatesy
Gatesy

asked on

dereferencing a pointer to an array

I have a handle to a block of memory (allocated using GlobalAlloc) that contains an array of singles.  Using GlobalLock I can get a pointer to the memory.   How can I access elements of the array using the pointer in VB6?
ASKER CERTIFIED SOLUTION
Avatar of waty
waty
Flag of Belgium image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Pointers in VB or Another Undocumented Microsoft Feature

Pointers to Variables  

     Since the original release of Visual Basic 1.0 for Windows, many programmers thought that lack of pointers was one of the major flaws that prevented Visual Basic from becoming a language for the "real programmers". With the release of Visual Basic 5.0 in 1997, Microsoft, however, attempted to fix that with the introduction of the AddressOf operator, which allowed us to have pointers to functions. However, that still did not help us with pointers to variables and objects that can be so extremely useful and convenient in many cases. (Please see my programs for some examples of how pointers can be useful in VB)

Recently, however, it was discovered that Visual Basic (starting with version 3.0) does, in fact, have an "undocumented function" that allows us now to have pointers to variables! That function is VARPTR, which has been present in many version of Basic under DOS for quite some time now (ex. QBasic, Visual Basic for DOS, etc).

In Visual Basic 5.0, Microsoft has introduced 3 undocumented functions for pointers to variables: VARPTR for variables, STRPTR for strings, and OBJPTR for objects.

Here is an example of how to use variables in Visual Basic 5.0 and Visual Basic 3.0.


Visual Basic 5.0: Variables: Strings:
Dim Var1 as Integer 'declare variables Dim Str1 As String 'declare variables
Dim Var2 as Integer Dim Str2 as String
Dim ptrVar as Long Dim ptrStr as Long
   
Var1 = 5 'Initialize variable Str1 = "Hello World" 'Initialize string
ptrVar = VarPtr(Var1) 'Get pointer to Var1 ptrStr = StrPtr(Str1) 'Get pointer to Str1
  Str2 = Space$(Len(Str1)) 'Allocate space for Str2
RtlMoveMemory VarPtr(Var2), ptrVar, Len(Var1)
'Var2 now equals Var1 RtlMoveMemory StrPtr(Str2), ptrStr, Len(Str1) * 2
'We need to multiply by 2 because strings in VB5 are UNICODE and, therefore, each character is 2 bytes long, not 1
'Str2 now equals Str1


Note: In order for this to work, you need to declare RtlMoveMemory function: Public Declare Sub RtlMoveMemory Lib "kernel32" (ByVal hpvDest As Any, ByVal hpvSource As Any, ByVal nBytes As Long)

Visual Basic 3.0:

You can use the exact same example as above with Visual Basic 3.0, EXCEPT you need to make the following changes:

Add these declarations:
Declare Function VarPtr Lib "VBRUN300.DLL" Alias "VARPTR" (Var1 As <Integer>) as Long 'Change <Integer> to whatever data type you want to make a pointer to (except String)
Declare Function StrPrt Lib "VBRUN300.DLL" Alias "VARPTR" (Str1 As String) as Long
Change RtlMoveMemory function to hmemcpy with the following declaration: Declare Sub hmemcpy Lib "Kernel" (ByVal hpvDest As Any, ByVal hpvSource As Any, ByVal nBytes As Long)
Pointers to Functions  

     Even though Visual Basic 5.0 has introduced AddressOf operator, the support for pointers to functions in Visual Basic is limited even today.

AddressOf returns a pointer to the function that you provide as a parameter to it. However, it has numerous limitations. First of all, you can only find addresses of functions that are declared in modules and NOT in forms or classes. This is not as much of a limitation as it is a nuisance. The second and most important restriction is that Microsoft apparently does not provide any way for you to use that pointer once you get it (e.g. actually call the function using it's pointer). As the official manuals/books say, you can only pass it to a 3rd party control written in a more advanced language (such as C, C++, Delphi, etc) that have the ability to use it. This is not 100% correct. There is a way around it, even though I, personally, do NOT recommend it.

The way to dereference the pointers that you get with AddressOf is very similar to the way described in Pointers to Variables - using an API call that accepts a pointer as a parameter. In the case of Pointers to Variables it was the RtlMoveMemory API function and in this case it's the CreateThread API call. I'm not going to explain how this function works - read an API reference book for that - but I will tell you this: I DO NOT RECOMMEND ANY PROGRAMMER WHO DOES NOT HAVE AT LEAST SEVERAL YEARS OF EXPERIENCE IN VISUAL BASIC TO EVEN TRY THIS FUNCTION. It, if not used extremely carefully can wreck havoc in your program!

Visual Basic 6.0 has introduced a new function called CallByName. It provides a similar effect as pointers to functions, except that it uses the actual function name (declared as a string) to achieve a similar effect. It is not the exact same thing as pointers to function, which I would personally prefer, but it can be used to achieve the same result without too much trouble.

You can use CopyMemory to copy data from the locked block over to a local variable:

Private Declare Sub CopyMemory Lib "Kernel32" Alias "RtlMoveMemory" ( _
           ByRef Destination As Any, _
           Source As Any, _
           ByVal numbytes As Long)

Call CopyMemory(DestData, ByVal pData, Len(DestData))