Home | Reviews | GUIpedia | Forum | Fun500


trollyFunction pointer
Hi, Do you know if there is a trick to make a function pointer in qb? i would like to implement callback function for button click
2013-01-048:43 AM

sbRe:Function pointer
You couldnt do it through the ide, because the code is being interpreted.

What you could do is have a function in basic that calls a far assembler function, then you could grab the cs:ip from the stack. It would be convoluted but do able.

(Sorry dont have qbasic to test so proabbly writing crap basic code, what you get by programming in java all day)

sub test()
static firstTime as integer

if firstTime=0 then
firstTime=1
globalTestFunction&=getFunctionPTR()+(how ever many bytes to skip over jmp call to end if, probably 2 or 3)
else
'actual code here
end if
end sub

Then in your assembler code you would duplicate the last 4 bytes on the stack to return.

I believe this would work, but I am only speculating at this point.

The other thing is I cant remember if bc.exe creates public symbols or not, but if its always a known name you could just call the function. If not I swear one version of bc.exe will generate asm code with a switch like /a, and you could just edit it?
You could always have a util program make the mods to the asm code if needed too, you will need masm though, as I think it generates masm specific code.
2013-01-046:32 PM

DickRe:Function pointer
yeah, bc.exe program.bas /a program.obj program.asm I believe, that should give you asm listing. I think you would have to link an asm library with your QB code to be able to find and use function pointers, not sure if you are willing to do that.
2013-01-051:38 AM

trollyRe:Function pointer
What i would like to do is, for example; sub MyCallBackSub() ... do stuff ... end sub and get a pointer to this sub: MyPointer = GetSubPointer(MyCallBackSub) Call Absolute(MyPointer) if i can find a way to do that, i will be able to bind a sub to a button click event. btn.CallBack = GetSubPointer(MyCallBackSub) in the Button.Manage sub, it will automaticaly call the callback after a click
2013-01-077:10 AM

HorvatMRe:Function pointer
I've come up with a way to get a pointer to a procedure in the same program. I don't know how procedures in libraries are called (which is probably what you want), so this is only a proof of concept. I've only tested it with the following example program, but it should work with FUNCTIONs too. I used QB 4.5, and the example takes advantage of the compiler's way of generating IF blocks. 'QB procedure pointer example 'by Matej Horvat (http://matejhorvat.si/) 'January 7, 2013 'Please credit me if you use this. DECLARE SUB Callback () 'Our callback procedure 'Assembly language procedures DECLARE FUNCTION GetProcPtr% () 'Gets pointer to procedure DECLARE SUB CallProc (BYVAL ProcPtr%) 'Calls a procedure, given a pointer CONST TRUE = -1 CONST FALSE = 0 DIM SHARED LastProcPtr AS INTEGER 'Pointer returned by GetProcPtr% DIM SHARED WantProcPtr AS INTEGER 'Whether we want the pointer; see below 'Before calling a procedure by pointer, set WantProcPtr to TRUE and call the 'procedure normally. WantProcPtr = TRUE Callback 'LastProcPtr (or any other SHARED INTEGER; see the Callback procedure) will 'now contain the address which can be given to CallProc to call it. 'Then, when you want to call the procedure, simply use CallProc and give it 'the pointer returned by GetProcPtr%. CallProc LastProcPtr SUB Callback 'This is the procedure that will be called by pointer. 'Any procedure you want to call with CallProc MUST begin with the following 'IF block: IF WantProcPtr THEN 'The following must be the first statement in the IF block. 'You can replace LastProcPtr with any other SHARED INTEGER variable. LastProcPtr = GetProcPtr% 'The following can be omitted, but remember to set WantProcPtr to FALSE 'before you call such a procedure. WantProcPtr = FALSE EXIT SUB END IF 'When the procedure is called with CallProc (WantProcPtr must be FALSE), the 'following code will be executed. PRINT "Hello World!" END SUB The example requires the following assembly language library (this one is written in NASM): ; QB library to call procedures by pointer ; by Matej Horvat (http://matejhorvat.si/) ; January 7, 2013 ; Please credit me if you use this. GLOBAL GetProcPtr GLOBAL CallProc GROUP DGROUP SECTION CODE GetProcPtr: ; Gets the IP of the calling procedure. See the QB example code for details. mov bx, sp mov ax, [bx] ; Get caller's IP sub ax, 8 ; Subtract 8 bytes, so we point to the jump over the END IF retf ; Return the pointer CallProc: ; Calls a BASIC procedure given an address. ; Stack on entry: ; [caller's IP][BASIC CS][IP of procedure to call] ; ^SP ; This procedure changes it to: ; [IP of procedure to call][BASIC CS][caller's IP] ; ^SP mov bx, sp mov ax, [bx+4] ; Get IP of procedure to call mov cx, [bx+0] ; Get IP of caller mov [bx+4], cx ; Store IP of caller mov [bx+0], ax ; Store IP of procedure to call retf ; "Far call" to procedure ; The called procedure will exit with a RET, which will get our caller's ; address. Note: this will only work in compiled programs. It will crash the IDE.
2013-01-0711:36 AM

sbRe:Function pointer
Trolly, remember for call absolute it uses the current def seg as the cs segment, call absolute is passed the offset (IP), so you will need to alter def seg as well, then alter it back. You might want to make a function that does just that, or just makes a far call.
2013-01-096:48 PM

sbRe:Function pointer
ok you will need masm 5.1 for this and I used vbdos, but qb45 or pds 7 should work fine

sub.asm
.model medium,basic .stack .code subip proc num:word push ds push bx mov ax,[num] mov bx,@data mov ds,bx mov bx,offset subptrs add bx,ax add bx,ax add bx,ax add bx,ax mov ax,[bx] pop bx pop ds ret subip endp subcs proc num:word push ds push bx mov ax,[num] mov bx,@data mov ds,bx mov bx,offset subptrs add bx,ax add bx,ax add bx,ax add bx,ax add bx,2 mov ax,[bx] pop bx pop ds ret subcs endp .data EXTRN sub1:far EXTRN sub2:far subptrs dd sub1 dd sub2 END sub1.bas
'$include:'vbdos.bi' declare function subip(byval ptr%) as integer declare function subcs(byval ptr%) as integer declare sub callsub(cs as integer,ip as integer) cs%=subcs(0) ip%=subip(0) print cs%,ip% call callsub (cs%,ip%) cs%=subcs(1) ip%=subip(1) print cs%,ip% call callsub (cs%,ip%) sub callsub(cs as integer,ip as integer) def seg=cs call absolute(ip) def seg end sub SUB sub1 () PRINT "sub1" END SUB SUB sub2 () PRINT "sub2" END SUB
do.bat
masm sub,,,,, bc /o sub1,,,,, link sub1+sub,,,,, run sub1.exe
2013-01-1411:26 PM

sbRe:Function pointer
In assembly, you can create pointers to your functions in basic, since it doesnt create the pointer till link time.

You extrn all the names of your functions, so that masm tells the linker to fill in the info, and then create pointers using dd, this is where they get filled in.

In basic you retrieve the cs and ip separately, (this is just easier to deal with separately).

Then you call the subs as needed.

You will want to adapt this code as needed though.
2013-01-1411:33 PM

BASIC Programming Help


2021 Brandon Cornell