Can I call a procedure by its pointer?

Just starting out? Need help? Post your questions and find answers here.
clover
User
User
Posts: 14
Joined: Tue Dec 30, 2008 4:43 am

Can I call a procedure by its pointer?

Post by clover »

I want to call a procedure which has several parameters as followed:

Code: Select all

Procedure FuncA(param1.l, param2.l)
    ;......
EndProcedure

Define *p = @FuncA()
Now the problem is how could I manage to call it with *p just like C language:

Code: Select all

(*p)(param1, param2);
User avatar
Josh
Addict
Addict
Posts: 1183
Joined: Sat Feb 13, 2010 3:45 pm

Re: Can I call a procedure by its pointer?

Post by Josh »

1) CallFunctionFast (deprecated)
2) Prototype
3) Maybe: Interfaces using with VTables
Last edited by Josh on Mon Jun 14, 2010 8:46 am, edited 1 time in total.
sorry for my bad english
User avatar
Comtois
Addict
Addict
Posts: 1431
Joined: Tue Aug 19, 2003 11:36 am
Location: Doubs - France

Re: Can I call a procedure by its pointer?

Post by Comtois »

use prototype

Code: Select all

Prototype Proto(param1.l, param2.l=3)

Procedure FuncA(param1.l, param2.l)
    ProcedureReturn  param1 + param2
EndProcedure
  
Define P.proto

P = @FuncA()

Debug P(2, 43)
Debug P(4)
Please correct my english
http://purebasic.developpez.com/
clover
User
User
Posts: 14
Joined: Tue Dec 30, 2008 4:43 am

Re: Can I call a procedure by its pointer?

Post by clover »

Oh, thank you very much, Josh & Comtois.
I was nearly forgot it, what a useful function -- CallCFunctionFast()!
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: Can I call a procedure by its pointer?

Post by netmaestro »

Just remember that CallCFunctionFast is limited to long parameters. For more power and flexibility use a prototype or ImportC.
BERESHEIT
User avatar
skywalk
Addict
Addict
Posts: 4211
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: Can I call a procedure by its pointer?

Post by skywalk »

Hi,
I have a question on ByRef use in Prototypes?
Both lines below marked "Which is correct?" give the same answer.

Code: Select all

Procedure.d FuncByVal(p1.s, p2.d)
  Protected.d x
  x = ValD(p1) + p2
  ProcedureReturn x
EndProcedure
Prototype.d ProtoByVal(p1.s, p2.d)
Define PByVal.ProtoByVal = @FuncByVal()

Procedure.d FuncByRef(*p1, *p2.Double)
  Protected.d x
  x = ValD(PeekS(*p1)) + *p2\d  
  PokeS(*p1, "Changed")
  *p2\d = 999
  ProcedureReturn x
EndProcedure
;Prototype.d ProtoByRef(*p1.s, *p2.d)      ; <--- Which is correct?
Prototype.d ProtoByRef(*p1, *p2.Double)   ; <--- Which is correct? 
Define PByRef.ProtoByRef = @FuncByRef()

Global s.s, d.d
s = "1"
d = 10
Debug "...ByVal..."
Debug PByVal(s, d)
Debug s
Debug d
Debug " "
Debug "...ByRef..."
Debug PByRef(@s, @d)
Debug s
Debug d
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
User avatar
Josh
Addict
Addict
Posts: 1183
Joined: Sat Feb 13, 2010 3:45 pm

Re: Can I call a procedure by its pointer?

Post by Josh »

*p1.s
*p2.d
*p1
*p2.Double

each variable with * is only a pointer (i)

*p1.s, *p2.d makes no sense, its the same like *p1 or *p2
*p2.Double is also only a pointer, but this pointer shows to a structure from type Double, so you can use this structure with the pointer *p2

Code: Select all

PokeS(*p1, "Changed")
where you have allocated memory for this?

i think it's better, you make correct procedures without prototypes first
sorry for my bad english
User avatar
Demivec
Addict
Addict
Posts: 4260
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Re: Can I call a procedure by its pointer?

Post by Demivec »

skywalk wrote:I have a question on ByRef use in Prototypes?

Code: Select all

Prototype.d ProtoByRef(*p1.s, *p2.d)      ; <--- This is definately not correct!
Prototype.d ProtoByRef(*p1, *p2.Double)   ; <--- Which is correct?
Prototype.d ProtoByRef(*p1.String, *p2.Double ;  <--- This one requires the address of a String structure as the first parameter
To restate Josh, a pointer can only be structured or not structured. Types of '.d' or '.s' are not structures and so shouldn't be used with pointers, instead use '.Double' or '.String' or leave it untyped if not using the built-in dereferencing (as you did with 'PeekS(*p1)') . This is because all pointers, even structured ones, hold an address of integer type. For pointers with a structure the structure is used for dereferencing the pointer's value (which is an address of integer type).

Because a pointer always contains an address of type integer it isn't checked for a matching type when it is compiled. It is only checked for the type of integer (i.e. using the @ operator or the need for conversion from another numeric type). This means both of these statements will result in equivalent results with your previous code:

Code: Select all

Prototype.d ProtoByRef(*p1, *p2.Double)
;Prototype.d ProtoByRef(*p1, *p2.Byte)   ;This will work because the procedure actually contains the code for structuring the pointer parameter
Even though the results will be the same the prototype should reflect the code or it will lead to problems of readability. :wink:

It can be taken advantage of though by using the same prototype with functions that differ only in the structure of their pointers.

Code: Select all

Procedure Add_d(*p1.Double,*p2.Double)
  Debug StrD(*p1\d + *p2\d)
EndProcedure

Procedure Add_b(*p1.Byte,*p2.Byte)
  Debug Str(*p1\b + *p2\b)
EndProcedure

Procedure Add_string(*p1.String,*p2.String)
  Debug Str(Val(*p1\s) + Val(*p2\s))
EndProcedure

Prototype addFunc_prt(*n1,*n2)

Define nd.d = 1.0, nb.b = 2, nString.String\s = "3"
  
Define genAddFunc.addFunc_prt

genAddFunc = @Add_d() : genAddFunc(@nd, @nd)
genAddFunc = @Add_b() : genAddFunc(@nb, @nb)
genAddFunc = @Add_string() : genAddFunc(nString, nString)
User avatar
skywalk
Addict
Addict
Posts: 4211
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: Can I call a procedure by its pointer?

Post by skywalk »

@Josh,
My intended use of prototype is to call external DLL functions that modify some of the passed parameters.
The procedure FuncByRef was my attempt to mimic calling an external DLL.

The manual was not clear to me for ByRef and prototypes.

Also, if the Global variable 's' was assigned, what more memory is required to allocate?

@Demivec,
Thanks for clearing this up and explaining the type independence allowing for a generic prototype. I agree with you on the readability issue. So, I have taken the approach of un-typing pointers when passing strings. Yeah, I know the pointer is still an integer. :)
For ByRef cases, rarely are my passed strings defined as structures. So, I stick with PeekS/PokeS.
I prefer case 1. not case 3. ---> http://www.purebasic.fr/english/viewtop ... 69#p325469

Code: Select all

Procedure Add_d(*p1.Double,*p2.Double)
  Debug StrD(*p1\d + *p2\d)
EndProcedure

Procedure Add_b(*p1.Byte,*p2.Byte)
  Debug Str(*p1\b + *p2\b)
EndProcedure

Procedure Add_string(*p1,*p2)
  Debug Str(Val(PeekS(*p1)) + Val(PeekS(*p2)))
EndProcedure

Prototype addFunc_ptr(*n1,*n2)
Define nd.d = 1.0, nb.b = 2, nString.S = "3"
Define genAddFunc.addFunc_ptr

genAddFunc = @Add_d()      : genAddFunc(@nd, @nd)
genAddFunc = @Add_b()      : genAddFunc(@nb, @nb)
genAddFunc = @Add_string() : genAddFunc(@nString, @nString)
Last edited by skywalk on Tue Jul 08, 2014 12:30 am, edited 1 time in total.
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
User avatar
Josh
Addict
Addict
Posts: 1183
Joined: Sat Feb 13, 2010 3:45 pm

Re: Can I call a procedure by its pointer?

Post by Josh »

skywalk wrote:My intended use of prototype is to call external DLL functions that modify some of the passed parameters.
The procedure FuncByRef was my attempt to mimic calling an external DLL.
i know, that you will use prototypes for external calls. but i think, it's easier to make correct procedures with byval and byref first, and then you can add the prototypes functionality.
skywalk wrote:Also, if the Global variable 's' was assigned, what more memory is required to allocate?
you write in the variable s the value "1". so this stringvariable has a length of one character. you can't write "Changed" with poke at this pointer. there is no reserved place in memory.
sorry for my bad english
User avatar
skywalk
Addict
Addict
Posts: 4211
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: Can I call a procedure by its pointer?

Post by skywalk »

@Josh,
Yes, you are right about the string variable and I normally set enough space using s = space(somenumberhere).
By external functions, I mean DLL functions I did not write but need to interface with to transfer data.
Forget my lame ByRef functions and please explain if the following is considered correct or incorrect?

I found this on the forum and want to understand why it works for the typed double pointer.


Still, my question is really really similar to this topic...
http://www.purebasic.fr/english/viewtop ... 08#p155208

Code: Select all

; Simple PureBasic example for the LabJack UE9. 
; support@labjack.com 
; Jul 31, 2006 
OpenConsole() 
ConsoleTitle ("LabJackUD PureBasic Example:") 
EnableGraphicalConsole(0) 

lngErrorcode.l 
lngHandle.l 
dblValue.d 
Prototype.d ProtoGetDriverVersion() 
Prototype.l ProtoOpenLabJack(DeviceType.l, ConnectionType.l, Address.s, FirstFound.l, *lngHandle.l) 
Prototype.l ProtoeGetS(pHandle.l, IOType.s, Channel.l, *dblValue.d, x1.l)                     ;<--- Is this correct? 
Prototype.l ProtoeGetSS(pHandle.l, IOType.s, Channel.s, *dblValue.d, x1.l)                  ;<--- *dblValue.d or *dblValue.Double
;The former is used with most basic IOTypes that operate on a particular 
;channel, while the latter is generally used with the put_config/get_config 
;types operating on the device as a whole. 

If OpenLibrary(0,"labjackud.dll") 
  
  fGetDriverVersion.ProtoGetDriverVersion = GetFunction(0, "GetDriverVersion") 
  fOpenLabJack.ProtoOpenLabJack = GetFunction(0, "OpenLabJack") 
  feGetS.ProtoeGetS = GetFunction(0, "eGetS") 
  feGetSS.ProtoeGetSS = GetFunction(0, "eGetSS") 
  
  ;Get the UD driver version. 
  driverVersion.d = fGetDriverVersion() 
  PrintN("GetDriverVersion = "+StrD(driverVersion,2)) 
  
  ;Open the first found USB LabJack UE9. 
  ;DeviceType: U3=3 or UE9=9 
  ;ConnectionType: USB=1 or Ethernet=2 
  lngErrorcode = fOpenLabJack( 9, 1, "1", 1, @lngHandle) 
  PrintN("OpenLabJack errorcode = "+Str(lngErrorcode)) 
  
  ;Read the serial number of the LabJack. 
  lngErrorcode = feGetSS( lngHandle, "LJ_ioGET_CONFIG", "LJ_chSERIAL_NUMBER", @dblValue, 0) 
  PrintN("") 
  PrintN("errorcode = "+Str(lngErrorcode)) 
  PrintN("Serial Number = "+StrD(dblValue,0)) 
  
  ;Get a reading from analog input 0 (AIN0). 
  lngErrorcode = feGetS( lngHandle, "LJ_ioGET_AIN", 0, @dblValue, 0) 
  PrintN("") 
  PrintN("errorcode = "+Str(lngErrorcode)) 
  PrintN("AIN0 = "+StrD(dblValue,6)) 
  
  ;Get a reading from digital input 0 (FIO0). 
  lngErrorcode = feGetS( lngHandle, "LJ_ioGET_DIGITAL_BIT", 0, @dblValue, 0) 
  PrintN("") 
  PrintN("errorcode = "+Str(lngErrorcode)) 
  PrintN("FIO0 = "+StrD(dblValue,0)) 
  
  ;Set analog output 0 (DAC0) to 2.5 volts. 
  dblValue = 2.5 
  lngErrorcode = feGetS( lngHandle, "LJ_ioPUT_DAC", 0, @dblValue, 0) 
  PrintN("") 
  PrintN("errorcode = "+Str(lngErrorcode)) 
  PrintN("DAC0 set to 2.5 volts") 
  
  ;Set digital line 1 (FIO1) to output-low . 
  dblValue = 0 
  lngErrorcode = feGetS( lngHandle, "LJ_ioPUT_DIGITAL_BIT", 1, @dblValue, 0) 
  PrintN("") 
  PrintN("errorcode = "+Str(lngErrorcode)) 
  PrintN("FIO1 set to output-low") 
  
  
Else 
  PrintN("Open Library Failed") 
EndIf 

PrintN("") 
Print ("Press <Enter> to exit: ") 
name$=Input() 

CloseLibrary(0) 
CloseConsole() 
End
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
User avatar
Josh
Addict
Addict
Posts: 1183
Joined: Sat Feb 13, 2010 3:45 pm

Re: Can I call a procedure by its pointer?

Post by Josh »

a *variable is always a pointer from type i. using with simple types makes absolutely no sense. you can use *variables with each structure. if you use *dblValue.Double, its a pointer to the structure Double. you can read your result with dblValue\d.

Code: Select all

  ;Read the serial number of the LabJack. 
  lngErrorcode = feGetSS( lngHandle, "LJ_ioGET_CONFIG", "LJ_chSERIAL_NUMBER", @dblValue, 0) 
  PrintN("") 
  PrintN("errorcode = "+Str(lngErrorcode)) 
  PrintN("Serial Number = "+StrD(dblValue,0)) 
if you using this code, write in the prototype only *dblValue and it should be correct.

generally it's only important that it is a pointer and for this is *variable enough !!!
sorry for my bad english
jamba
Enthusiast
Enthusiast
Posts: 144
Joined: Fri Jan 15, 2010 2:03 pm
Location: Triad, NC
Contact:

Re: Can I call a procedure by its pointer?

Post by jamba »

^Josh is spot on!
skywalk wrote:
I found this on the forum and want to understand why it works for the typed double pointer.
it works because a pointer is a pointer.

regardless of .d or whatever else (which is probably ignored, as it does not make any sense), even .DOUBLE or .STRING .INTEGER, the pointer is still just a pointer to a memory location that contains some value.

debug *dblValue ;some pointer location, stored as integer
debug *dblValue\d ;the double value stored in that location

check this out if you haven't, definitely clears things up a bit:
http://www.xs4all.nl/~bluez/purebasic/p ... d_pointers
-Jon

Fedora user
But I work with Win7
Post Reply