Page 1 of 1
Can I call a procedure by its pointer?
Posted: Mon Jun 14, 2010 8:35 am
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:
Re: Can I call a procedure by its pointer?
Posted: Mon Jun 14, 2010 8:39 am
by Josh
1) CallFunctionFast (deprecated)
2) Prototype
3) Maybe: Interfaces using with VTables
Re: Can I call a procedure by its pointer?
Posted: Mon Jun 14, 2010 8:42 am
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)
Re: Can I call a procedure by its pointer?
Posted: Mon Jun 14, 2010 8:45 am
by clover
Oh, thank you very much, Josh & Comtois.
I was nearly forgot it, what a useful function -- CallCFunctionFast()!
Re: Can I call a procedure by its pointer?
Posted: Mon Jun 14, 2010 2:24 pm
by netmaestro
Just remember that CallCFunctionFast is limited to long parameters. For more power and flexibility use a prototype or ImportC.
Re: Can I call a procedure by its pointer?
Posted: Mon Jun 14, 2010 4:34 pm
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
Re: Can I call a procedure by its pointer?
Posted: Mon Jun 14, 2010 6:11 pm
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
where you have allocated memory for this?
i think it's better, you make correct procedures without prototypes first
Re: Can I call a procedure by its pointer?
Posted: Mon Jun 14, 2010 7:00 pm
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.
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)
Re: Can I call a procedure by its pointer?
Posted: Mon Jun 14, 2010 7:50 pm
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)
Re: Can I call a procedure by its pointer?
Posted: Mon Jun 14, 2010 8:11 pm
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.
Re: Can I call a procedure by its pointer?
Posted: Mon Jun 14, 2010 11:14 pm
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
Re: Can I call a procedure by its pointer?
Posted: Tue Jun 15, 2010 12:47 am
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 !!!
Re: Can I call a procedure by its pointer?
Posted: Tue Jun 15, 2010 1:18 am
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