Feel free to correct me as it has been a while but as far as I remember, QBasic 1.1 and QB4.5 store all variables (integers, doubles, etc) on a single 64kb segment and all strings on another. If you ever use them up you either get an 'out of string space' or 'out of memory' error. So all your assembly routine needs to know is the address of that segment which you can get with VARSEG(num%) of any variable or VARSEG(str$). Then you simply can simply pass VARPTR(num2%) or SADD(str2$) and these are called short pointers, since, of course, it would be infeasible to always pass BYVAL. With QB7.1 and VB for DOS, you can actually use the entire 1 MB memory for your variables requiring the use of long pointers.
Here are some fun excerpts of mine of mixing assembly and QB with an actual assembler and LINK.EXE (
http://matejhorvat.si/en/software/nasmqb.htm), you can see the use of VARPTR, VARSEG, SEG, SADD, BYVAL, etc.
fget and fput are a specialized variant of GET and PUT requiring access to both vga memory and QB program memory where the images are stored, printf (print font) is similar
asm:
global mouse
global printf
global fget
global fput
global setdta
global ffile
group dgroup
section code
mouse:
push bp
mov bp,sp
mov ax,[bp+12]
int 33h
mov si,[bp+10]
mov [si],bx
mov si,[bp+8]
mov [si],cx
mov si,[bp+6]
mov [si],dx
pop bp
retf 8
printf:
push bp
mov bp,sp
push es
mov ax,0a000h
mov fs,ax
les di,[bp+6]
mov dx,[bp+12] ;y
mov ax,80
mul dx
mov si,[bp+14] ;x
shr si,3
add si,ax
mov bx,[bp+10]
mov cx,[bx]
mov bx,[bx+2]
label:
push di
mov ax,[bx]
sub ax,32
mov dl,11
mul dl
add di,ax
push cx
push si
mov cx,11
label1:
mov al,[es:di]
mov [fs:si],al
add si,80
inc di
loop label1
pop si
pop cx
pop di
inc bx
inc si
loop label
pop es
pop bp
retf 10
fget:
push bp
mov bp,sp
push ds
push es
mov dx,80
mov ax,[bp+14] ;y
mov cx,[bp+10] ;y1
sub cx,ax
mul dx
mov si,[bp+16] ;x
mov dx,[bp+12] ;x1
sub dx,si
shr dx,3
shr si,3
add si,ax
inc dx
inc cx
les di,[bp+6]
mov [es:di],dx
mov [es:di+2],cx
add di,4
mov ax,0a000h
mov ds,ax
label3:
push cx
push si
mov cx,dx
rep movsb
;shr cx,1
;rep movsw
;adc cx,cx
;rep movsb
pop si
pop cx
add si,80
loop label3
pop es
pop ds
pop bp
retf 12
fput:
push bp
mov bp,sp
push ds
push es
mov dx,80
mov ax,[bp+10] ;y
mul dx
mov di,[bp+12] ;x
shr di,3
add di,ax
lds si,[bp+6]
mov dx,[si]
mov cx,[si+2]
add si,4
mov ax,0a000h
mov es,ax
label4:
push cx
push di
mov cx,dx
rep movsb
;shr cx,1
;rep movsw
;adc cx,cx
;rep movsb
pop di
pop cx
add di,80
loop label4
pop es
pop ds
pop bp
retf 8
setdta:
push bp
mov bp,sp
push ds
lds dx,[bp+6]
mov ax,01a00h
int 21h
pop ds
pop bp
retf 4
ffile:
push bp
mov bp,sp
mov dx,[bp+6]
mov cx,[bp+8]
mov si,[bp+10]
mov ax,[si]
int 21h
mov [si],ax
pop bp
retf 6
qb:
DEFINT A-Z
DECLARE SUB mouse (BYVAL ax, mb, mx, my)
DECLARE SUB printf (BYVAL x, BYVAL y, s$, SEG addr AS ANY)
DECLARE SUB fget (BYVAL x, BYVAL y, BYVAL x1, BYVAL y1, SEG addr AS ANY)
DECLARE SUB fput (BYVAL x, BYVAL y, SEG addr AS ANY)
DECLARE SUB setdta (SEG dta AS ANY)
DECLARE SUB ffile (ax, BYVAL cx, BYVAL dx)
DECLARE FUNCTION getfiles (q$, arr() AS STRING)
DIM SHARED font(520)
DEF SEG = VARSEG(font(0))
BLOAD "font.dat", VARPTR(font(5)) + 1
DEF SEG
DIM SHARED fol(1190)
DIM SHARED exe(1190)
DIM SHARED fil(1190)
DEF SEG = VARSEG(fol(0))
BLOAD "fol.bsv", VARPTR(fol(0))
DEF SEG = VARSEG(exe(0))
BLOAD "exe.bsv", VARPTR(exe(0))
DEF SEG = VARSEG(fil(0))
BLOAD "fil.bsv", VARPTR(fil(0))
DEF SEG = 0
TYPE dtatype
reserved AS STRING * 21
a AS STRING * 1
time AS INTEGER
date AS STRING * 2
size AS LONG
n AS STRING * 13
END TYPE
DIM SHARED dta AS dtatype
setdta dta
DIM SHARED mb, mx, my
DIM SHARED fs(500) AS STRING 'files
DIM SHARED sf(30, 1) AS STRING 'selected files, active select
DIM SHARED sfn(1) 'number of selected files (active select)
DIM SHARED sff 'selected file flag (1=cut/move, 2=copy)
DIM SHARED sft 'selected file tab
DIM SHARED sab 'active file selection array
'...
FUNCTION getfiles (q$, arr() AS STRING)
p$ = q$ + "*.*" + CHR$(0)
ax = &H4E00
ffile ax, 16, SADD(p$)
FOR i = 0 TO UBOUND(arr) - 1
ax = &H4F00
ffile ax, 0, 0
IF ax AND &HF <> 0 THEN EXIT FOR
arr(i) = LEFT$(dta.n, INSTR(dta.n, CHR$(0)) - 1) + CHR$(32 + (dta.a = CHR$(16)) * -60)
NEXT
getfiles = i
END FUNCTION
and of course, all can be done with CALL ABSOLUTE on QB 1.1. Here is a simple mouse routine:
push bp
mov bp,sp
mov si,[bp+12]
mov ax,[si]
int 33h
mov si,[bp+10]
mov [si],bx
mov si,[bp+8]
mov [si],cx
mov si,[bp+6]
mov [si],dx
pop bp
retf 8
DEFINT A-Z
DECLARE SUB mouse (ax, mb, mx, my)
DIM SHARED m(7) AS LONG
m(0) = &H8BE58955
m(1) = &H48B0C76
m(2) = &H768B33CD
m(3) = &H8B1C890A
m(4) = &HC890876
m(5) = &H8906768B
m(6) = &H8CA5D14
SCREEN 12
mouse 0, mb, mx, my 'reset mouse driver
mouse 1, mb, mx, my 'show mouse cursor
DO
'get mouse state
mouse 3, mb, mx, my
'print mouse coordinates
LOCATE 1, 1: PRINT mb, mx, my
LOOP UNTIL INP(&H60) = 1
SYSTEM
SUB mouse (ax, mb, mx, my)
DEF SEG = VARSEG(m(0))
CALL absolute(ax, mb, mx, my, VARPTR(m(0)))
END SUB
It's fun to revisit old school QB, I think it has really hardened a generation of programmers for the better. Now you'd probably be insane to hand code x86 assembly