getting a variable from its pointer.

pain_woman

New Member
Joined
Sep 21, 2006
Messages
3
how can i obtain the actual variable that a pointer points to ?

the vb function VarPtr returns the address of a variable . what i am after is the actual variable value given its pointer.i need this for some C-like winAPI code in excel.

TIA
 

Excel Facts

Copy formula down without changing references
If you have =SUM(F2:F49) in F50; type Alt+' in F51 to copy =SUM(F2:F49) to F51, leaving the formula in edit mode. Change SUM to COUNT.
L

Legacy 98055

Guest
Are you sure you do not simply need to pass by value? If not ByVal, what datatypes are we speaking of? Strings, string arrays, variant and other arrays, longs, are all dealt with differently.
 

Jaafar Tribak

Well-known Member
Joined
Dec 5, 2002
Messages
8,253
Office Version
  1. 2016
Platform
  1. Windows
To get the value of the variable pointed to by a Pointer is so simple in the C language as it fully supports Pointers and has the : (*) Indirection operator as opposed to VB.

to get around this problem,VB will need the use of the CopyMemory API .

Here is a reusable function that accepts two arguments.One is the Pointer and the second argument expects a Constant element of a user defined Enum which just tells the function what variable type is the Pointer ponting to.

In a standard module:

Code:
Option Explicit

Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _
(pDst As Any, pSrc As Any, ByVal ByteLen As Long)

Enum MyVarType
    longVar
    byteVar
    integerVar
    DoubleVar
    CurrencyVar
    DateVar
    SingleVar
    BoolVar
    StringVar
End Enum


Function Indirection(ByVal lpointer As Long, DataType As MyVarType) As Variant

    Select Case DataType
        'declare each "Dest" var according to the passed DataType
        'Enum argument before copying the passed pointer to them.
        Case Is = MyVarType.byteVar
            Dim bDest As Byte
            CopyMemory bDest, ByVal lpointer, LenB(bDest)
            Indirection = bDest
        Case Is = MyVarType.integerVar
            Dim iDest As Integer
            CopyMemory iDest, ByVal lpointer, LenB(iDest)
            Indirection = iDest
        Case Is = MyVarType.DoubleVar
            Dim dDest As Double
            CopyMemory dDest, ByVal lpointer, LenB(dDest)
            Indirection = dDest
        Case Is = MyVarType.CurrencyVar
            Dim cDest As Currency
            CopyMemory cDest, ByVal lpointer, LenB(cDest)
            Indirection = cDest
        Case Is = MyVarType.DateVar
            Dim dtDest As Date
            CopyMemory dtDest, ByVal lpointer, LenB(dtDest)
            Indirection = dtDest
        Case Is = MyVarType.SingleVar
            Dim sDest As Single
            CopyMemory sDest, ByVal lpointer, LenB(sDest)
            Indirection = sDest
        Case Is = MyVarType.longVar
            Dim lDest As Long
            CopyMemory lDest, ByVal lpointer, LenB(lDest)
            Indirection = lDest
        Case Is = MyVarType.BoolVar
            Dim blDest As Boolean
            CopyMemory blDest, ByVal lpointer, LenB(blDest)
            Indirection = blDest
        Case Is = MyVarType.StringVar
            Dim stDest As String
            stDest = String$(1000, " ")
            CopyMemory ByVal StrPtr(stDest), ByVal lpointer, Len(stDest) - 1
            Indirection = stDest
    End Select

End Function


Here are some Test examples for various variable types:

Code:
'\\some examples..............................................

Sub ReturnStringFromPointer_Test()

    Dim sString  As String
    Dim lpointer As Long
    
    sString = "Hello friend !"
    'get the var pointer
    lpointer = StrPtr(sString)
    'return the actual var value
    MsgBox " the pointer points to the string :  " & _
    Indirection(lpointer, MyVarType.StringVar), vbInformation

End Sub

Sub ReturnDateFromPointer_Test()

    Dim dDate  As Date
    Dim lpointer As Long
    
    dDate = #9/22/2006#
    'get the var pointer
    lpointer = VarPtr(dDate)
    'return the actual var value
    MsgBox " the pointer points to the date:  " & _
    Indirection(lpointer, MyVarType.DateVar), vbInformation

End Sub

Sub ReturnLongFromPointer_Test()

    Dim lLong  As Long
    Dim lpointer As Long
    
    lLong = 1278899
    'get the var pointer
    lpointer = VarPtr(lLong)
    'return the actual var value
    MsgBox " the pointer points to the long:  " & _
    Indirection(lpointer, MyVarType.longVar), vbInformation

End Sub

Sub ReturnDoubleFromPointer_Test()

    Dim dDouble  As Double
    Dim lpointer As Long
    
    dDouble = -1278899.9851
    'get the var pointer
    lpointer = VarPtr(dDouble)
    'return the actual var value
    MsgBox " the pointer points to the double:  " & _
    Indirection(lpointer, MyVarType.DoubleVar), vbInformation

End Sub

Regards.
 

Jaafar Tribak

Well-known Member
Joined
Dec 5, 2002
Messages
8,253
Office Version
  1. 2016
Platform
  1. Windows

ADVERTISEMENT

Re: thank you.

I get a compile error apparently relating to the enum declaration.

TIA.

Yes, that's because the Enum KeyWord wasn't inrtroduced until XL2000 (I believe).

Anyway, you can easily avoid this problem by declaring independent long Constantes instead of an Enumeration such us :

Const longVar As Long = 1
Const byteVar As Long = 2.... and so on...

Regards.
 

pain_woman

New Member
Joined
Sep 21, 2006
Messages
3
Tried it yesterday on my home machine running Excel 2003 and it worked brilliantly. thanks very much for your help with this.
 

tusharm

MrExcel MVP
Joined
May 28, 2002
Messages
11,029
Hi Jaafar,

While this is intellectually very interesting, it seems to have little applicability in VB(A). Maybe, pain_woman can educate me on how s/he is using it.

OTOH, something I would find very useful would be calling a subroutine (preferably, with parameters), where I only know the address of the subroutine (from the use of AddressOf)

To get the value of the variable pointed to by a Pointer is so simple in the C language as it fully supports Pointers and has the : (*) Indirection operator as opposed to VB.

to get around this problem,VB will need the use of the CopyMemory API .{snip}
 

Jaafar Tribak

Well-known Member
Joined
Dec 5, 2002
Messages
8,253
Office Version
  1. 2016
Platform
  1. Windows
While this is intellectually very interesting, it seems to have little applicability in VB(A). Maybe, pain_woman can educate me on how s/he is using it.

Dear Tusharm,

Using Indirection can be useful and sometimes necessary when working with some API functions in particular those which handle strings.

a good example is the GetEnvironmentStrings API ( corresponds to the VBA Environ function ) which returns a 32bit long pointer to a String NOT the String itself hence the VB declaration that allocate a Long for its return value instead of allocating a Sting.

there is no way you can get the actual string results from this function unless you use Inderection via the CopyMemory API.

the Inderection function I've provided here is just wrapper for easier coding.

Code:
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _
(lpvDest As Any, lpvSource As Any, ByVal cbCopy As Long)

Private Declare Function GetEnvironmentStrings Lib "kernel32" Alias _
"GetEnvironmentStringsA" () As Long

Private Declare Function FreeEnvironmentStrings Lib "kernel32" Alias _
"FreeEnvironmentStringsA" (ByVal lpsz As String) As Long


'\\ here is a string version of the custom VB "Indirection" function:
Function Indirection(lPointer As Long) As String

    Dim stDest As String
    stDest = String$(1000, Chr(0))
    CopyMemory ByVal (stDest), ByVal lPointer, Len(stDest) - 1
    Indirection = stDest

End Function


'\\ *** these two test routines return the same result ****
Sub TAKE_1()

    Dim lStringPointer As Long
    Dim sBuffer As String
    sBuffer = String(1000, Chr(0))
    lStringPointer = GetEnvironmentStrings
    CopyMemory ByVal sBuffer, ByVal lStringPointer, Len(sBuffer) - 1
    MsgBox sBuffer
    FreeEnvironmentStrings lStringPointer

End Sub

Sub TAKE_2()

    Dim lRet As Long
    lRet = GetEnvironmentStrings()
    MsgBox Indirection(lRet)
    FreeEnvironmentStrings lStringPointer

End Sub




OTOH, something I would find very useful would be calling a subroutine (preferably, with parameters), where I only know the address of the subroutine (from the use of AddressOf)

Actually, I have been experimenting a bit with this AddressOfand the CallWindowProc API which is typically used in Subclassing and which is passed the address of a default window procedure of a Window but which also can be passed a normal user Function\Sub address. Thus we can indeed call a function just by knowing its memory address as shown in the example below :

to achieve this , here is a wrapper routine which I named (CallProcedureFromItsAddress):


Code:
Private Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" _
(ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, _
ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long


Private Sub CallProcedureFromItsAddress(ProcAddress As Long, _
 Optional firstParm As Long = 0, Optional secParm As Long = 0 _
 , Optional thirdParam As Long = 0, Optional fourthParm As Long = 0)

    CallWindowProc ProcAddress, firstParm, secParm, thirdParam, fourthParm

End Sub

'\\ supporting function
Private Function ProcedurePtr(ByVal arg As Long) As Long
   ' Return whatever was passed.
   ProcedurePtr = arg
End Function


here is a demo (run the Test routine):


Code:
Sub OurProcedure(ByVal a As Long, ByVal b As Long, ByVal c As Long, ByVal d As Long)

    'simply display the Product of the parameters
    
    MsgBox a * b * c

End Sub


Sub Test()

    '\\ run OurProcedure routine by passing
    '\\ its memory address and only 3 of its parameters

    Call CallProcedureFromItsAddress(ProcedurePtr(AddressOf OurProcedure), 5, 5, 4)

End Sub


In order for this to work, I have noticed that the called function ie: "OurProcedure" must have either 4 arguments which correspond to the last 4 of the CallWindowProc API or no arguments at all. Careful here: If you change this precise signature it will crash XL!!

Also, I haven't tried passing parameters to the "OurProcedure" other than Longs.I 'll experiment with Strings,Dates.. etc later on and I'll see how many times I'll manage to crash the system :)

Obviously, this is a bit rough and needs much polishing but it does show that with some tricks, calling a function from its memory address can be done in VB.

Regards.
 

Forum statistics

Threads
1,136,992
Messages
5,679,018
Members
419,799
Latest member
APInfa

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Top