POINTERS in  Rapid-Q
Documentation by
John Kelly

POINTERS 


  • 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 Double
    MyVariable = 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 SubType
    Problem: 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
  • Contents Next Chapter