Microsoft KB Archive/37422

From BetaArchive Wiki
Knowledge Base


Using Assembler to Save and Restore Text Mode Screens in QB

Article ID: 37422

Article Last Modified on 8/16/2005



APPLIES TO

  • Microsoft QuickBasic 4.0
  • Microsoft QuickBASIC 4.0b
  • Microsoft QuickBasic 4.5 for MS-DOS
  • Microsoft BASIC Compiler 6.0
  • Microsoft BASIC Compiler 6.0b
  • Microsoft BASIC Professional Development System 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
                


Additional query words: QuickBas BasicCom

Keywords: KB37422