-
What is a pointer?
When you declare a variable, its must have a memory location to store
it's value. A pointer is simply a variable that "points" to a memory
location. That is, a pointer knows "where it is" not the value. For
example, if you do DIM a AS INTEGER, then what do you think
happens? The program must allocate a 4 byte location in memory to store the
values you assign to variable a. There will be a pointer for variable a and
it will hold the address of the variable. For example:
-
- DIM a AS INTEGER
DIM lpVar AS LONG ' the lp prefix helps you remember it is a LONG
POINTERa = 5
-
lpVar = VARPTR(a)
Now lpVar holds a large number that is the ADDRESS in memory of the variable.
When passing variables to a DLL, SUB, FUNCTION, etc. the program normally
figures out whether you gave it a Pointer to a variable, or the value of the
variable. -
- Why are pointers
important?
When you make a call to a SUB, FUNCTION, or DLL, you may want it to change the
contents of the variable. Also, it is faster and easier to send the
address if you want the SUB to have a large chunk of data. That way the SUB
know where the large chunk of data is located. That is easier than copying all the data
to some location in memory (i.e., the stack) and then copy it back after the
DLL is done.
When you use a UDT in a call to a SUB, FUNCTION, or DLL RapidQ automatically passes the address of the
UDT for you, so you don't need to find the pointer for a UDT. If you need the
pointer for some reason, VARPTR won't work. Use RapidQ2.INC and use UDTPTR
instead.
Often, if you are using a DLL written in another language (preferably C), that
DLL might require you send pointers for some variables and values for others.
You can pass a pointer two ways:
If you know the type of variable that is needed you can
just send the usual BYREF method
- DECLARE SUB MyFunc(BYREF Data AS DOUBLE) 'send the
pointer to an 8-bit DOUBLE
DIM MyVariable As DoubleMyVariable = 1.00323 -
MyFunc(MyVariable)
Alternatively, you can just send the value of the
pointer
- DECLARE SUB MyFunc(BYVAL lpData AS LONG) 'send the
value of the pointer
DIM MyVariable As DoubleMyVariable = 1.00323
-
lpVar = VarPtr(myVariable)
MyFunc(lpVar)
-
- User Defined types (UDT) or "structures"
IF you need the address of members in the UDT, then define your UDT as EXTENDS
QOBJECT! Here is an example: - TYPE NewT extends QOBJECT
a as integer
b as long
c as string * 24
end type
dim NewObj as NewT
NewObj.a = 2 'give it a value if you want
Showmessage STR$(VARPTR(NewObj.a)) 'now you get the address
'but look what happens with the string:
Showmessage STR$(VARPTR(NewObj.c)) 'now you a
very different address
ShowMessage STR$(UDTPTR(NewObj)) 'note UDTPTR only works on basic
UDT
PORTING C/C++ code to RapidQ
-
- When you try to port code from C/C++ or Visual basic you
are going to run into some limitations in RapidQ. Some can be avoided with
re-coding, and others can't be fixed.
- Problem: DLL requires a pointer to a Structure with another type inside a type
TYPE SubType
x as integer
y as integer
zz(300) as single 'RapidQ only allocates four bytes for array pointer - r as RECT
'this won't work, compiles but will crash in exe
-
END TYPE
DIM MySubType as SubTypeProblem: Memory may not be "packed" together
in a UDT defined by STRUCT or TYPE
- Fix: Use QmemoryStream to get the pointer
TYPE MyType
a as integer
b as single
c as byte
d(5) as integer 'only four bytes allocated
z as SubType 'this compiles, and adds sizeof(subtype)
END TYPE
DIM MyUDT AS MyType
DIM Mem AS QMemoryStream
Mem.WriteUDT(MyUDT)
'Again, there will be limits to getting pointers
ShowMessage str$(Mem.Pointer) 'works
ShowMessage str$(sizeof(MyUDT)) 'works
'if subType is added then the UDT is bigger by sizeof(subType)
ShowMessage str$(sizeof(MySubType)) 'works
MyUDT.z.y = 8
'won't work Compiler doesn't recognize nested type
MyUDT.z.zz(1) = 2.23451 'doesn't work!!
showmessage str$(@MyUDT.c) 'works to get the value of the variable
showmessage str$(varptr(MyUDT.a)) 'doesn't work!!
'work around by adding offsets
ShowMessage str$(Mem.Pointer + Sizeof(XX)+ ... +SizeOf(SubType))
Another work around is to add the individual part of SubType --
'*** these 3 lines are added instead of z...
x as integer
y as integer
zz(1 to 3) as single
but they can't have the same name. This of course is a lot of work.
''ALSO'*** can't get pointers of QOBJECTS
DIM MyForm AS QFORM Showmessage STR$(VARPTR(MyForm)) 'Error Showmessage STR$(UDTPTR(MyForm)) 'Error
ShowMessage STR$(sizeof(MyForm)) 'Error
|