Using Assembler to Save and Restore Text Mode Screens in QB (37422)
The information in this article applies to:
- Microsoft QuickBASIC 4.0
- Microsoft QuickBASIC 4.0b
- Microsoft QuickBASIC 4.5
- Microsoft BASIC Compiler for MS-DOS and OS/2 6.0
- Microsoft BASIC Compiler for MS-DOS and OS/2 6.0b
- Microsoft Basic Professional Development System for MS-DOS 7.0
This article was previously published under Q37422 SUMMARY
This article contains a sample program that demonstrates how to save
and restore text screens using an assembly language routine called
from compiled Basic.
This information applies to Microsoft QuickBasic versions 4.00, 4.00b,
and 4.50 for MS-DOS; to the Microsoft Basic Compiler versions 6.00 and
6.00b for MS-DOS; and to Microsoft Basic PDS Version 7.00 for MS-DOS.
MORE INFORMATION
The method (below) calls an assembly-language routine to store the
screen in an array, then restore it. This method is similar to the
graphics mode GET and PUT statements. The October 27, 1987, issue of
"PC Magazine" has an example of an assembly-language routine that does
this; however, the code needs to be modified for QuickBasic version
4.00. The modified programs are as follows:
The following is DEMO.BAS, that demonstrates saving and restoring the
text mode screen by calling two assembly language routines from
QuickBasic:
Defint A-Z
'$Dynamic
Dim Storage(1999)
FirstLine = 1
LastLine = 5
Cls
For X = 1 To 15
Color X
Print String$(80, X + 64);
Next
Locate 20
Print "Press a key to save the screen";
While Inkey$ = "" : Wend
'Call Ptr86(Segment, Address, Varptr(Storage(0))) ' For QB 3.00.
Segment=VARSEG(Storage(0)) ' For QB 4.00
Address=VARPTR(Storage(0)) ' For QB 4.00
Call ScrnSave(FirstLine, LastLine, Segment, Address)
Cls
Print "Press a key to restore the top";
While Inkey$ = "" : Wend
'Call Ptr86(Segment, Address, Varptr(Storage(0))) ' For QB 3.00.
Segment=VARSEG(Storage(0)) ' For QB 4.00
Address=VARPTR(Storage(0)) ' For QB 4.00
Call ScrnRest(FirstLine, LastLine, Segment, Address)
The following is SCRNSAVE.ASM, an assembly language routine.
SCRNSAVE.ASM saves a portion of the text screen in QuickBasic:
Code Segment Byte Public 'Code'
Assume CS:Code
Public ScrnSave
ScrnSave Proc Far
Begin: Push BP ;save registers for Basic
;* Push DS DELETE THIS LINE
Mov BP,SP ;locate stack to get variable
;addresses later
PUSH DS ;* SAVE THE DATA SEGMENT
PUSH ES ;* SAVE THE EXTRA SEGMENT
Mov DX,0 ;look at low memory using ES
Mov ES,DX
Mov BX,0B000h ;assume monochrome screen segment for
;now
Mov AL,ES:[410h] ;get the equipment list
And AL,48 ;just look at the monitor type
Cmp AL,48 ;is it monochrome?
JZ Get_Params ;if yes, skip over adding 800h
Add BX,800h ;if no, adjust for color-screen memory
Mov AL,ES:[487h] ;if an EGA is present, AL will not be
;zero
Cmp AL,0 ;is it an EGA?
JNZ Get_Params ;if yes, leave DX set to zero as a
;flag for later
Mov DX,3DAh ;if no, specify the port to check for
;retrace
Get_Params: Push BX ;save the screen segment for later
;* Mov SI,[BP+08] ;get the starting address of the
;storage array
;* change to BP+6
Mov SI,[BP+06] ;get the starting address of the
;storage array
Mov DI,[SI] ;and put it into DI
;* Mov SI,[BP+10] ;get the segment for the array
;* change to BP+8
Mov SI,[BP+8] ;get the segment for the array
Mov ES,[SI] ;and assign it to ES
;* Mov SI,[BP+12] ;get the address for LastLine
;* change to BP+10
Mov SI,[BP+10] ;get the address for LastLine
Mov AL,[SI] ;and put it into AL
Mov CL,160 ;prepare to multiply times 160
Mul CL ;now AX holds the last screen address to
;save
Mov BX,AX ;save it in BX for later
;* Mov SI,[BP+14] ;get the address for FirstLine
;* change to BP+12
Mov SI,[BP+12] ;get the address for FirstLine
Mov AL,[SI] ;put it into AL
Dec AL ;adjust 1-25 to 0-24
Mul CL ;calculate actual starting address on
;screen
Mov SI,AX ;now SI points to the source address
Sub BX,AX ;calculate the number of bytes to copy
Mov CX,BX ;put it into CX for Rep or Loop below
Shr CX,1 ;divide CX by 2 to obtain the number of
;words
Pop DS ;retrieve the screen segment saved
;earlier
Cld ;all data moves below will be forward
Cmp DL,0 ;are we doing monochrome or EGA?
JZ Mono ;if monochrome, skip over the retrace
No_Retrace: In AL,DX ;get the video-status byte
Test AL,1 ;test just the horizontal retrace part
JNZ No_Retrace ;if doing a retrace, wait until it is
;not
Retrace: In AL,DX ;get the status byte again
Test AL,1 ;are we currently doing a retrace?
JZ Retrace ;if no, wait until we are
Lodsw ;now get the word from the screen
Stosw ;and put it into the array
Loop No_Retrace ;loop until done
Jmp Exit ;skip over the monochrome routine and
;exit
Mono: Rep Movsw ;move the data in one operation
Exit: POP ES ;* ADD THIS LINE
Pop DS ;restore registers for Basic
Pop BP
Ret 8 ;return skipping the passed parameters
ScrnSave Endp
Code Ends
End ;* REMOVE THE LABEL Begin
The following is SCRNREST.ASM, which restores a portion of the text
screen in the QuickBasic program:
Code Segment Byte Public 'Code'
Assume CS:Code
Public ScrnRest
ScrnRest Proc Far
Begin: Push BP ;save registers for Basic
;* Push DS DELETE THIS LINE
Mov BP,SP ;locate stack to get variable addresses
;later
PUSH DS ;* ADD THIS LINE
PUSH ES ;* ADD THIS LINE
Mov DX,0 ;look at low memory using ES
Mov ES,DX
Mov BX,0B000h ;assume monochrome screen segment for
;now
Mov AL,ES:[410h];get the equipment list
And AL,48 ;just look at the monitor type
Cmp AL,48 ;is it monochrome?
JZ Get_Params ;if yes, skip over adding 800h
Add BX,800h ;if no, adjust for color-screen memory
Mov AL,ES:[487h];if an EGA is present, AL will not be
;zero
Cmp AL,0 ;is it an EGA?
JNZ Get_Params ;yes, leave DX set to zero as flag for
;later
Mov DX,3DAh ;no, specify the port to check for
;retrace
Get_Params: Mov ES,BX ;set ES to the appropriate screen
;segment
;* Mov DI,[BP+12] ;get the address for LastLine
;* change to BP+10
Mov DI,[BP+10] ;get the address for LastLine
Mov AL,[DI] ;and put it into AL
Mov CL,160 ;prepare to multiply times 160
Mul CL ;now AX holds last screen address to
;restore
Mov BX,AX ;save it in BX for later
;* Mov DI,[BP+14] ;get the address for FirstLine
;* change to BP+12
Mov DI,[BP+12] ;get the address for FirstLine
Mov AL,[DI] ;put it into AL
Dec AL ;adjust 1-25 to 0-24
Mul CL ;calculate actual starting address on
;screen
Mov DI,AX ;now DI points to the destination
;address
Sub BX,AX ;calculate the number of bytes to copy
Mov CX,BX ;put it into CX for Rep or Loop below
Shr CX,1 ;divide CX by 2 to obtain the number of
;words
;* Mov SI,[BP+10] ;get the segment of the storage
array
;* change BP + 8
Mov SI,[BP+8] ;get the segment of the storage array
Mov AX,[SI] ;and save it in AX for a moment
;* Mov SI,[BP+08] ;get the address of the first array
;element
;* change to BP+6
Mov SI,[BP+06] ;get the address of the first array
;element
Mov SI,[SI] ;and put it into SI
Mov DS,AX ;okay to change DS after getting all
;variables
Cld ;all data moves below will be forward
Cmp DL,0 ;are we doing monochrome or EGA?
JZ Mono ;if monochrome, skip over the retrace
No_Retrace: In AL,DX ;get the video status byte
Test AL,1 ;test just the horizontal retrace part
JNZ No_Retrace ;if doing a retrace, wait until it is
;not
Retrace: In AL,DX ;get the status byte again
Test AL,1 ;are we currently doing a retrace?
JZ Retrace ;if no, wait until we are
Lodsw ;now get the word from the screen
Stosw ;and put it into the array
Loop No_Retrace ;loop until done
Jmp Exit ;skip over the monochrome routine and
;exit
Mono: Rep Movsw ;move the data in one operation
Exit: POP ES ;* ADD THIS LINE
Pop DS ;restore registers for Basic
Pop BP
Ret 8 ;return skipping the passed parameters
ScrnRest Endp
Code Ends
End ;* REMOVE THE LABEL Begin
Modification Type: | Minor | Last Reviewed: | 8/16/2005 |
---|
Keywords: | KB37422 |
---|
|