D O S S H E L LSee Next Page36 FEBRUARY/MARCH 1994 Visual Basic Programmer’s JournalD O S S H E L LSHELL Shinesin DOS WindowAn assembly-language routine lets you SHELL to a predefined window formaximum control of your DOS user interface.B Y T O N Y E L L I O T; DOSWIN.ASM - Listing 1; DOS windowing routine for use during a SHELL; Copyright (C) 1993 EllTech Development, Inc.; Written by Tony Elliott - August 1993f you’re like most programmers, you; Requires MASM 6.0x or later to reassemble. This routine; is compatible with QB/PDS/VBDOS, and PowerBasic 3.0x.create polished user interfaces. YouI.Model Medium, Basicmake sure that the colors are well bal-.Codeanced and pleasing to the eye, and that; Variable Declaration Areaanything the user needs to do is only a key press;; We're going to store our local variables in the code; segment in order to avoid any impact on DGroup.or mouse click away. It’s frustrating to losecontrol of your meticulously handcrafted screenOrigInt10 LABEL DWord ;A "far" label pointing todisplays when you SHELL out to a DOS (orOrigInt10Ofs dw 0 ; interrupt 10h's originalother) command-line utility. During the SHELL,OrigInt10Seg dw 0 ; vector.OrigInt29 LABEL DWord ;A "far" label pointing tothese utilities can cause your display to wrapOrigInt29Ofs dw 0 ; interrupt 29h's originalaround and scroll, temporarily destroying all ofOrigInt29Seg dw 0 ; vector.your hard work. Wouldn’t it be great if youTopRow db 0 ;When the programmercould confine the output of such utilities to aLeftCol db 0 ; defines the windowBottomRow db 0 ; coordinates and colorpredefined window on the screen during aRightCol db 0 ; attribute, they areSHELL? After hearing several programmersColorAttr db 0 ; stored here.complain about this problem, I created a solu-LineWrap db 0tion. The DosWindow routine described hereScrnRows db 25 ;The current displayScrnCols db 0 ; parameters will belets you control the screen display during aScrnPage db 0 ; stored here.SHELL and add a first-class professional touch; Define Macrosto your applications.VideoInt Macro ;Some BIOS can destroyBefore I discuss how this routine works, Push bp ; the BP register. Using Int 10h ; this macro, we make sureconsider the organization of operating system Pop bp ; that BP is alwayssoftware and ROM BIOS services. There areEndm ; preserved.at least three software layers in every PC:; Procedure AreaBIOS, DOS, and application programs.DosWindow proc uses DS, TopR:Word, LeftC:Word, BottomR:Word, RightC:Word, Colr:Word, LWrap:WordAt the lowest level, there’s the system hard-; On entry to this routine, let's get some informationware. This includes all the IC chips and circuit; about the current video adapter.boards that make up your computer. Generally Cmp cs:OrigInt10Seg,0 ;Are we already installed?speaking, there can be literally hundreds of Jz @f ;If not, continue Call RemoveDosWindow ;If so, deinstall first@@: Push csTony Elliott is Vice President and General Pop ds ;Point ds to code segmentManager of EllTech Development Inc. and Assume ds:@Codeauthor of several add-ons for Basic, including Mov ah,0fh ;Get video modeCONTINUED ON NEXT PAGE.E-Tree Plus, Printer Plus, Compression Plus,and Fax Plus. He can be contacted at 4374LISTING 1Hooking an Interrupt. This complete assembly-language routine allows you to createShallowford Industrial Parkway, Marietta,a predefined window while SHELLing from QB, PDS, VBDOS, or PB. Making thisGeorgia, 30066, or on CompuServe atroutine work requires intercepting all calls made to interrupt &H29 and &H10 during the SHELL.76220,2575.Visual Basic Programmer’s Journal FEBRUARY/MARCH 1994 37D O S S H E L Lmachine-language instructions required just toput a single character on your video display.LISTING 1. CONTINUED FROM PREVIOUS PAGE.And to make matters more complicated, these VideoInt ;Call the video BIOSsteps can vary from one hardware configura- Dec ah ;Make screen cols base 0tion to another. Realizing this early on, IBM Mov ScrnCols,ah ;Screen colums Mov ScrnPage,bh ;Active display pagecreated the specifications for a group of soft- Xor ax,axware subroutines called Basic Input Output Mov es,ax ;Point es to BIOS dataSystem, or BIOS. Mov al,byte ptr es:[484h] ;Rows, if EGA/VGAThe BIOS specification defines the inter- Cmp al,42 ;43 line mode? (base 0) Jz RowsOk ;If so, continuerupt numbers and parameters used to control Cmp al,49 ;50 line mode?everything from disk I/O and printer services to Jz RowsOk ;If so, continuekeyboard handling and screen display. Manu- Mov al,24 ;Assume 25 line modefacturers that want to produce PC-compatibleRowsOk: Mov ScrnRows,al ;Store rows in our varmotherboards, video cards, and other types of; Now, load and evaluate the window coordinates providedhardware must also include a set of BIOS; by the Basic program.functions, usually stored in ROM or a device Mov ax,TopR ;TopRow% into axdriver, that conform to the IBM specifications. Dec al ;Make it base 0 Cmp al,ScrnRows ;Greater than ScrnRows?These functions act as the software layer be- Ja BadParam ;Exit if sotween the operating system and the hardware. Mov bx,LeftC ;LeftCol% into bxFor example, if I want to switch the current Dec bl ;Make it base 0video adapter into the 80-by-25 color mode Cmp bl,ScrnCols ;Greater than ScrnCols? Ja BadParamfrom assembly language, I don’t need to know Mov cx,BottomR ;BottomRow% into cxall the low-level steps required by the specific Dec cl ;Make it base 0video card I’m using; I simply use BIOS inter- Cmp cl,al ;Less than TopRow%?rupt &H10 service. The video card manufac- Jb BadParam ;If so, exit Cmp cl,ScrnRows ;Greater than ScrnRows?turer has provided a group of interrupt &H10 Ja BadParam ;If so, exitfunctions designed specifically for his card. Mov dx,RightC ;RightCol% into dxThis approach makes life much easier. Dec dl ;Make it base 0The software layer above the BIOS is the Cmp dl,bl ;Less than LeftCol%? Jb BadParam ;If so, exitoperating system: DOS. DOS provides memory Cmp dl,ScrnCols ;Greater than ScrnCols?management, file and directory organization, Ja BadParam ;If so, exitprogram loading and termination services, and; All of the coordinates seem to be ok. Load them intomuch more. For example, the BIOS provides; our internal variables along with the remaining; two parameters.services for reading and writing individual Mov TopRow,alsectors on a hard disk, and DOS provides the Mov LeftCol,blhigher-level organization that keeps track of Mov BottomRow,clwhere on disk the files are stored, and so forth. Mov RightCol,dl Mov ax,Colr ;Color attribute into axIn other words, when manipulation of hard- Mov ColorAttr,al ;Store itware devices is necessary, DOS functions will Mov ax,LWrap ;LineWrap% into axusually call BIOS routines instead of manipu- Mov LineWrap,al ;Store itlating the hardware directly. This approach; All of the parameters are now stored in our internal; variables. Let's now clear the window area using theprevents DOS from becoming dependent on; specified color and position the cursor to the upper-one specific brand of hardware. The software; left corner of the window.layer above DOS is an application program. Mov ax,600h ;Scroll up 0 lines (clear)Application programs can use DOS and even Mov bh,ColorAttr ;Color attribute into bh Mov ch,TopRow ;Window coordinates intoBIOS services to handle keyboard input, screen Mov cl,LeftCol ;CX and DX.I/O, file I/O, and other operations. Mov dh,BottomRowKnowing the sequence of events that tran- Mov dl,RightColspire when an application prints a string allows VideoInt ;Call the video BIOS Mov ah,2 ;Set cursor position tous to write a routine like DosWindow. For Mov bh,ScrnPage ; the upper-left cornerexample, when most DOS command-line utili- Mov dh,TopRow ; of our window.ties want to print a character, they use the DOS Mov dl,LeftCol“fast put character” function (interrupt &H29). VideoInt; The window is clear and the cursor is positioned. NowThis function simply writes a character to the; get interrupt 10h's current vector and store it. Thenscreen at the current cursor location and moves; point int 10h to our handler so we can take control.the cursor to the next character position. It also Mov ax,3510h ;Get the current vectorprocesses the carriage return (ASCII 10) and Int 21h ; for interrupt 10h. Mov OrigInt10Seg,es ;Store it for laterline feed (ASCII 13) characters, and manipu- Mov OrigInt10Ofs,bxlates the cursor accordingly when these charac- Mov ax,3529h ;Get current vector forters are encountered. Interrupt &H29 doesn’t Int 21h ; interrupt 29h.access the video hardware directly. It makes Mov OrigInt29Seg,es ;Store it for later Mov OrigInt29Ofs,bxcalls to the video BIOS interrupt &H10 ser- Mov ax,2510h ;Point the int 10h vectorvices to get the current cursor location, print the Mov dx,offset OurInt10 ; to our codecharacter, move the cursor to the next position, Int 21hand to scroll the screen when necessary. Mov ax,2529h ;Point Int 29h to our code Mov dx,offset OurInt29In order to make the DosWindow routineCONTINUED ON NEXT PAGE.work, you must intercept all calls made to38 FEBRUARY/MARCH 1994 Visual Basic Programmer’s JournalD O S S H E L LLISTING 1. CONTINUED FROM PREVIOUS PAGE. Int 21h cmp al,0ah ;Is it a line feed? Xor ax,ax ;Return 0 (successful) jnz CheckBounds ;If not, continueDosWindowExit: mov bx,-1 ;If so, set both flags Ret ;Back to Basic Inc dh ;Point to the next lineBadParam: ;If we detected a badCheckBounds: ;Check cursor bounds Mov ax,-1 ; parameter, return -1. Cmp dl,LeftCol ;Position < LeftCol? jmp short DosWindowExit Jae CheckRightCol ;If not, continueDosWindow endp Mov bl,-1 ;Set "reset cursor" flag; Our Interrupt 10h Handler Mov dl,LeftCol ;New column for cursor; When an interrupt 10h hits, we check to see if it is Jmp short CheckRow ;No need to checktheRightCol; "scroll zero" function. This is used to clear aCheckRightCol:; rectangular area of the screen (or the entire screen). Cmp dl,RightCol ;Position > RightCol?; DOS and command line utilities use this service to Jbe CheckRow ;If not, continue; perform a CLS operation. If a scroll zero request is Cmp LineWrap,0; detected, we redefine the coordinates to include only jnz @f; our window. Anything else, we pass right through to Mov bh,-1; the original int 10h handler. jmp short CheckRowOurInt10 proc far@@: Mov bl,-1 ;Set cursor pos flag Assume ds:Nothing, cs:@code Mov dl,LeftCol ;Cursor back to LeftCol Sti ;Enable interrupts Inc dh ;And move to next row Push ds ;Preserve dsCheckRow: Cmp ax,600h ;A scroll up 0? (CLS) Cmp dh,TopRow ;Above TopRow? jz ScrollZero ;If so, process it Jae CheckBottomRow ;If not, continue cmp ah,9 ;Multiple char TTY? Mov bl,-1 ;Set cursor repos flag jz CharPrint Mov dh,TopRow ;New row to set cursor to cmp ah,0eh ;Or single char TTY Jmp short FixUp ;Don't check BottomRow jz CharPrint ;Process themCheckBottomRow: Jmp ChainToOrigInt10 ;If no of above, chain Cmp dh,BottomRow ;Below BottomRow?CharPrint: ;If function 9 or E Jbe Fixup ;If not, continue mov bl,cs:ColorAttr ; use this attribute. Mov bl,-1 ;Reset cursor flag Jmp ChainToOrigInt10 ;Chain to orig int 10h Mov dh,BottomRow; If we get here, we need to scroll the window up aScrollZero: ;If a scroll zeroline Push cs ; Push bx ;Save our control flags Pop ds ;Point ds to code Push dx ;And new cursor position Assume ds:@code Mov ax,601h ;Scroll up one line Mov ch,TopRow ;Override the requested Mov bh,ColorAttr ;Load registers with Mov cl,LeftCol ; CLS area (whole screen) Mov ch,TopRow ; coordinates of Mov dh,BottomRow ; with the coordinates Mov cl,LeftCol ; window and color Mov dl,RightCol ; and color defined for Mov dh,BottomRow ; attribute. Mov bh,ColorAttr ; our window. Mov dl,RightColChainToOrigInt10: VideoInt Pop ds ;Restore ds Pop dx ;Restore the registers Jmp Dword Ptr cs:OrigInt10 ;Chain orig int 10h Pop bxOurInt10 endpFixUp: ;Adjust cursor pos, if; Our Interrupt 29h Handler Push bx ; needed.; When an interrupt 29h (DOS "Fast PutChar") function Or bl,bl ;Reset the cursor pos?; hits, we check the cursor position and make sure it is Jz @f ;If not, continue; within our window. If it is outside the window, we Mov ah,2; either wrap to the next line, or scroll the window up. Mov bh,ScrnPageOurInt29 proc far VideoInt Sti ;Turn interrupts back on@@: Pop bx ;Restore flags again Push ds ;Save these registers Or bh,bh ;Skip printing this char? Push ax Pop dx Push bx Pop cx Push cx Pop bx ;Restore these registers Push dx Pop ax Push cs Pop ds Pop ds ;Point ds to code segment jnz @f ;If skip print, return Assume ds:@Code Jmp DWord Ptr cs:OrigInt29 ;Otherwise, chain Mov ah,3 ;Get current cursor pos@@: Iret Mov bh,ScrnPage ;Returned in DH/DLOurInt29 endp VideoInt;————————————————————————————; As we qualify the output, BH and BL are used asRemoveDosWindow proc uses ds; control flags. If BH is set, then the current; From Basic:; character is not printed (CR, BL, or if past right; DECLARE SUB RemoveDosWindow (); border of window when the LineWrap flag is clear).; Unhooks the DosWindow routine from int 10h and resets; BL is set when the cursor position needs to be; our internal variables.; updated (line wrap or carriage return). Push cs Xor bx,bx ;Clear our control flag Pop ds ;Point ds to codeCheckCR: Assume ds:@Code cmp al,0dh ;A carriage return? Cmp OrigInt10Seg,0 ;Are we installed? jnz CheckLF ;If not, continue Jz RemoveExit ;If not, exit Mov dl,LeftCol ;If so, set left col to Mov ax,2510h ;Set vector for int 10h Mov bx,-1 ; left side of window and Mov dx,OrigInt10Ofs ;Offset of orig handler jmp short CheckBounds ; set "update cursor Mov bx,OrigInt10Seg ;Seg of handler in bxflag" Mov OrigInt10Seg,0 ;Reset our "flag"CheckLF:CONTINUED ON NEXT PAGE.Visual Basic Programmer’s Journal FEBRUARY/MARCH 1994 39D O S S H E L LBack% and Fore% represent a set of BasicLISTING 1. CONTINUED FROM PREVIOUS PAGE.background and foreground color values (as Mov ds,bx ;Seg of orig handler in dsused with the COLOR statement), Colr% can Assume ds:nothingbe calculated as follows: Int 21h ;Call DOS Mov ax,2529h ;Restore original int 29h Mov dx,cs:OrigInt29OfsColr% = (Back% OR (Fore% AND 16) \ 2 )_ Mov bx,cs:OrigInt29Seg* 16 + (Fore% AND 15) Mov ds,bx Int 21hRemoveExit:The LineWrap% parameter is used to deter- Ret ;We're finishedmine if the DosWindow routine wraps or trun-RemoveDosWindow endpcates a line that’s wider than the defined win-enddow. Truncating generally provides a moren'TESTWIN.BAS - LISTING 2readable display within a DosWindow. Pass aDEFINT A-Zvalue of -1 to wrap text or 0 to truncate text.DECLARE SUB RemoveDosWindow()Once the routines are declared, all you haveDECLARE FUNCTION DosWindow% (BYVAL TopRow%, _to do is invoke the DosWindow% function BYVAL LeftCol%, BYVAL BottomRow%, _immediately before your SHELL statement and BYVAL RightCol%, BYVAL Colr%, _ BYVAL LWrap%)call RemoveDosWindow immediately upon'PB3 users, unrem the following line:returning from the SHELL. Listing 2 contains'$link "dosbox2.obj"a small example program called'Clear the screen to black on whiteDWTEST.BAS.COLOR 0,7CLSRemember, the DosWindow routine can'Dress up the screen a little with an instruction barcontrol the output of programs only when they'above and below our Dos window area.use DOS or BIOS services to display data.COLOR 7,1Because Basic’s PRINT statement uses directLOCATE 2,10: PRINT SPC(61)LOCATE 2,28: PRINT "** Dos Shell In Progess **"video writes instead of BIOS and DOS servicesLOCATE 24,10: PRINT SPC(61);(direct writes are faster), DosWindow will notLOCATE 24,25: PRINT "Type 'Exit' to return to Basic";be able to control its output. There is a way'Set up and call the DosWindow routinearound this: instead of using a regular PRINTTopRow% = 4: LeftCol% = 8: 'Upper left cornerBottomRow% = 22: RightCol% = 72 'Lower rightstatement in a program you want to SHELL,Colr% = 3: LineWrap% = 0 'Color and wrapOPEN the CON (console) device and printStatus% = DosWindow%(TopRow%, LeftCol%, BottomRow%,_through it. For example: RightCol%, Colr%, LineWrap%)IF Status% THENOPEN "CON" FOR OUTPUT AS #1 PRINT "Bad coordinates were passed to DosWindow!" ENDPRINT #1, "This text is routine _END IFthrough the BIOS and"SHELL 'Now, we're ready to shell!PRINT #1, "is trapable by the _'Don't forget this! Failure to call this routine beforeDosWindow routine!"'ending your program can result in a crash.Call RemoveDosWindowCLOSE #1'Clear the screen to white on black and end.COLOR 7,0There you have it. Once you’ve integratedCLSENDthe DosWindow routine with your application,you can SHELL to the predefined window andmaintain control of your user interface. ToLISTING 2Polish Your Shell. This sample program generates screen output to test yourdownload the this code, call my BBS at 404-image when SHELLing to a pre-defined window.928-7111 and download a file calledDOSWIN.EXE. It is a self-extracting archiveinterrupt &H29 and interrupt &H10 during theDeclare Function DosWindow% ( BYVAL_that contains everything you need. nSHELL. The interception of an interrupt ser-TopRow%, BYVAL LeftCol%, _vice is referred to as “hooking an interrupt.”BYVAL BottomRow%, BYVAL _While these interrupts are hooked, theRightCol%, BYVAL Colr%, _DosWindow routine makes sure that all cursorBYVAL LineWrap% )positioning requests are kept within the boundsDeclare Function RemoveDosWindow ()of a predefined window, that the desired colorattribute is used to display data within theIf you are using PowerBasic 3.0, you’ll needwindow, and that attempts to clear (CLS) orone additional line:scroll the screen affect only the contents of thewindow (Listing 1). If an application requests$Link “DOSWIN.OBJ”an interrupt &H10 service that my routine isn’tprepared to handle, the original interrupt &H10When declaring the routines, don’t forgetservice routine will handle it.the BYVALs! If you leave them out, unpredict-It’s easy to use the DosWindow routineable results will occur!from Quick Basic, Basic PDS, VBDOS, orThe parameters TopRow%, LeftCol%,PowerBasic 3.0. Just add the following declara-BottomRow%, and RightCol% define the up-tions to the top of the Basic program moduleper-left and bottom-right corners of the win-that will be calling the DosWindow routines:dow. Colr% defines the color attribute usedwhen displaying data within the window. When40 FEBRUARY/MARCH 1994 Visual Basic Programmer’s Journal