For those who might be interested, here is a code skeleton that
demonstrates some of the techniques required for writing an ISR that
hooks into the interrupt chain for Int 21h, does some handling, then
passes control to the next interrupt handler in the chain - all in
PowerBASIC, using inline ASM.
'----------------------------------------------------------------------
' ISRDEMO.BAS - demonstrates how to write an ISR that traps Int 21h
' then chains to the old Int 21h interrupt afterward.
'
' This demo calls a SUB that resets the Interrupt vector table to point
' to a new interrupt handler written in inline ASM code. This ISR
' looks at every call to Int 21h.
'
' If the Int 21h call is for service 3Bh (the set directory service) the
' handler calls the BIOS to print the new directory being set. (You can't
' call PB's PRINT statement or a DOS service to do the printing.) After
' the ISR finishes, it chains to the old Int 21h handler.
'
' Once the new ISR is in place, the demo program shells. As long as you
' are in the shell, the ISR is operational. As soon as you leave the shell
' the demo removes the ISR and restores Int 21h as it was before.
'________________________________________________________________________
$LIB ALL OFF
DECLARE SUB SetInt21InterruptVector ()
DECLARE SUB RestoreInt21InterruptVector ()
DIM Old21Segment AS SHARED WORD
DIM Old21Offset AS SHARED WORD
'================ START OF MAIN CODE ====================
SetInt21InterruptVector
SHELL
RestoreInt21InterruptVector
END
'================ END OF MAIN CODE ====================
'================================
SUB SetInt21InterruptVector ()
'================================
HandlerSegment?? = CODESEG(DOSHandler)
HandlerOffset?? = CODEPTR(DOSHandler)
ASM Push DS
ASM Push ES
ASM Push AX
ASM Push BX
ASM Mov AX, &H3521 ; get vector for DOS interrupt &H21
ASM Int &H21
ASM Mov Old21Address[0], BX ; put the old 3B vector address in ISR
ASM Mov Old21Offset, BX ; save it in the global variable, too
ASM Mov BX, ES
ASM Mov Old21Address[2], BX ; put into the ISR
ASM Mov Old21Segment, BX ; save it in the global variable, too
ASM Mov DX, HandlerOffset?? ; point DS:DX at new handler
ASM Mov AX, HandlerSegment??
ASM Mov DS, AX
ASM Mov AX, &H2521 ; set new vector for DOS interrupt &H21
ASM Int &H21 ; now the table points to our ISR code
ASM Pop BX
ASM Pop AX
ASM Pop ES
ASM Pop DS
EXIT SUB
' The following ISR code is called any time DOS is called
DOSHandler:
ASM PushF ; we must save what we might trash!
ASM Push BP
ASM Push ES
ASM Push DS
ASM Push AX
ASM Cmp AH, &H3B ; is "set dir" service being requested?
ASM Je SetDirRequested ; if so, go handle it
ASM Pop AX ; otherwise, pop everything we pushed
ASM Pop DS
ASM Pop ES
ASM Pop BP
ASM PopF ; and prepare to chain to old int 21h code
Chain2OldInt:
ASM DB &H0EA ; this opcode for JMP FAR is treated as code, not data
Old21Address:
ASM DD 0 ; chain to the old Int 21h address
SetDirRequested: ; here we intervene whenever 3Bh is called
ASM Push DX ; save everything we might trash!
ASM Push CX
ASM Push BX
ASM Push DI
ASM Push SI
'here is where the meat of the ISR code goes:
GOSUB BiosPrint ' in this case, it's just one GOSUB
ASM Pop SI ; pop everything that was pushed
ASM Pop DI
ASM Pop BX
ASM Pop CX
ASM Pop DX
ASM Pop AX
ASM Pop DS
ASM Pop ES
ASM Pop BP
ASM PopF
ASM Jmp Chain2OldInt
'--------------- END OF MAIN ISR CODE -------------------
' We GOSUB to BiosPrint from inside the ISR. The Pushes at the start are
' redundant -- these same registers have alreay been pushed in the ISR.
' They are inserted here just for the sake of showing "good form".
BiosPrint:
ASM Push AX ; we arrive here with DS:DX pointing to the name
ASM Push BX ; of the directory that will be set by DOS
ASM Push CX
ASM Push SI
ASM Mov AH, &H0E ; ask for BIOS service 0Eh - teletype printing
ASM Mov BH, 0 ; assumes screen page zero is active
ASM Mov SI, DX ; set DS:SI to the same as DS:DX
Loop1:
ASM Mov CX, 1 ; this loop prints each char until the the null char
ASM Lodsb ; loads one char from DS:SI into AL
ASM Or AL, AL ; see if it is the terminal null char
ASM Jz ExitLoop1 ; if it is, stop the loop
ASM Int &H10 ; call BIOS interrupt 10h, for service 0Eh
ASM Jmp Loop1
>>> Continued to next message
* SLMR 2.1a * MAXLIB For PB v1.2 - Access arrays and files in EMS/XMS!
--- WILDMAIL!/WC v4.12
---------------
* Origin: Com-Dat BBS - Hillsboro, OR. HST DS (1:105/314.0)
|