home *** CD-ROM | disk | FTP | other *** search
-
- const stayres_tag: string[90]
- = #0'@(#)CURRENT_FILE LAST_UPDATE TSR support library 1.0'#0;
- #log TSR support library 1.0
-
- {-----------------------------------------------------------------------------}
- { }
- { }
- { " S o r r y, D a v e, I C a n ' t D o T h a t . " }
- { }
- { Arthur C. Clark }
- { " 2 0 0 1 " }
- {-----------------------------------------------------------------------------}
-
- { Stayres Version 3.20i (single include-file version)
-
-
- { Authors: Lane H. Ferris (Stay Resident/Exit Code)
- Neil J. Rubenking (Directory code and ideas)
- Other Public Gurus on whose shoulders we stand.
-
- { PURPOSE: This code will serve as a template to create other "Stay Resident"
- programs in Turbo Pascal(tm). This code intercepts Int 16,
- displacing original Interrupt 16 Vector to User Interrupt 67.
- During execution of other programs, it can be invoked by the
- special key combination specified by "Our_Char" (in this case
- Alt-F10.)
-
- Modifications:
- 7. 7.85 - Replace Windows with a more simple form/less code.
- 7. 8.85 - Replace Window Array with Pointers/Heap form.
- 7.11.85 - Re-issue termination Keyboard Read / pass back to user
- Would like to back up Instruction Ptr by two bytes before
- the Int 16 ($CD16) but it might be a "long call" by
- some other Kbd interceptor (chirp chirp chrIP)... and
- thats "trouble in River City".
- 7.19.85 - Clean up RmWin "incorrect" attribute bugs. If screen
- isnt cleared, we get border attribute, not text attrb.
- - Remove last window at Termination Time (Ctrl-Home).
- 8.26.85 - Version 3.10 Changes
- 1) Save 40 words in StaySave/Rstr to avoid clobbersing
- Dos Stack when entering Dos with Turbo Write(ln) caused
- by Int 21 Function 5 (Writln(Lst,..)) which re-issues
- Int 16.
- 2) Change Int 68 to Int 67 to Avoid collisions with
- Dos 3.1 on an AT.
- 3) Correct "Press a Key..." to accept any "Key..."
- (not just Cr).
- 4) Check Int16 function. Jmp directly to Int16 if not
- a character request. Avoids 40 word Save/Restore
- overhead.
- 9.04.85 - Version 3.20 changes
- 1) When returning to user program, pass back a fake
- "Ctrl-key" scan code to allow immediate re-execution
- of the TSR (Terminate Stay Resident) program. Also
- solves SideKick incessant bird caws.
- 2.14.86 - Version 3.20i changes
- 1) Combined all stay-resident functions into a single
- include file. This simplifies the job of making
- a stay-resident utility based on this package.
- 2) Made a simple stay-resident program that demonstrates
- how the stayres include file is used.
- ***doesnt 3) Added searching for a free interrupt vector. This
- ***work allows you to have more than 1 resident program at
- ***yet!!! a time in memory.
- }
-
-
-
- procedure user_stayres_procedure; forward; {defined later by the user}
-
-
- { * * * * * * * CONSTANTS * * * * * * * * * * * * * * * * * * * * * * }
- const
- Our_Char = 113; {this is the scan code for AltF10}
- Alt_F10 = #113; {Alt F10 Scan Code }
- Ctrl_Home = #119; {Control Home Scan Code }
- Ctrl_End = #117; {Control End Scan Code }
-
- User_Int_Min = $67; {first place to put new interrupt}
- User_Int_Max = $7F; {last place to put new interrupt}
-
- Kybrd_Int = $16; {BIOS keyboard interrupt}
-
-
- { - - - - - - T Y P E D E C L A R A T I O N S - - - - - - - - - - - - }
- Type
- Regtype = record Ax,Bx,Cx,Dx,Bp,Si,Di,Ds,Es,Flags:integer end;
- HalfRegtype = record Al,Ah,Bl,Bh,Cl,Ch,Dl,Dh:byte end;
-
- { - - - - - - - T Y P E D C O N S T A N T S - - - - - - - - - - - - - - -}
- Const
- {regs is defined as a typed constant in order to get it in the code segment}
-
- Regs : regtype = (Ax:0;Bx:0;Cx:0;Dx:0;Bp:0;Si:0;Di:0;Ds:0;Es:0;Flags:0);
-
- OurDseg: integer = 0; {Our Data Segment Value }
- OurSseg: integer = 0; {Our Stack Segment Value }
- DosSseg: integer = 0; {Dos Stack Segment Value }
- Inuse : Boolean = false; {Recursion flag }
-
- { The following two constants *MUST* remain in the IP:CS order }
- { because StaySave uses them as a JMP target }
- User_IntIP : integer = 0; {Pointer to Original IP Int value }
- User_IntCS : integer = 0; {Pointer to Original CS Int value }
-
- User_Int { : integer} = User_Int_Min;
-
- { - - - - - - - V A R I A B L E S - - - - - - - - - - - - - - - - - - - - - -}
- Var
- SaveRegs : regtype;
- HalfRegs : halfregtype absolute regs;
- Terminate_flag : boolean ;
- Old_Xpos,Old_Ypos : integer ;
-
-
- {-----------------------------------------------------------------------------}
- { Stay_Xit Check Terminate Keys }
- { }
- { Clean up the Program, Free the Environment block, the program segment }
- { memory and return to Dos. Programs using this routine, must be the }
- { last program in memory, else, a hole will be left causing Dos }
- { to go GooGoo . }
- {-----------------------------------------------------------------------------}
-
- Procedure Stay_Xit;
- Begin { Block }
- SaveRegs.Ax := $3500 + User_Int;
- MsDos(SaveRegs); {get the original Int 16 Addr }
-
- SaveRegs.Ax := $2500 + Kybrd_Int;
- SaveRegs.Ds := SaveRegs.Es;
- SaveRegs.Dx := SaveRegs.Bx; { Reset the Keyboard interrupt addr }
- MsDos(SaveRegs); { to its original value }
-
- MemW[$00:User_Int * 4] := 0 ; { Clear User Interrupt vector }
- MemW[$00:User_Int * 4 + 2] :=0;
-
- Saveregs.Ax := $4900 + 0 ; { Free Allocated Block function}
- Saveregs.Es := MemW[CSeg:$2C] ; { Free environment block }
- MsDos( Saveregs ) ;
-
- Saveregs.Ax := $4900 + 0 ; { Free Allocated Block function}
- Saveregs.Es := CSeg ; { Free Program }
- MsDos( Saveregs ) ;
-
- Intr($20,Regs) ; { Return to Dos }
-
- End { StayXit };
- {-----------------------------------------------------------------------------}
-
- {----------------------------------------------------------------------------}
- { P R O C E S S I N T E R R U P T }
- { - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - }
- { PURPOSE: This procedure replaces the standard keyboard interrupt. If
- anything but <Alt>-F10 is pressed, the key is passed on to the
- standard keyboard interrupt. B*U*T when <Alt>- F10 is pressed,
- this program takes over. The variable InUse is set to TRUE to
- ensure that this code doesn't try to run "on top of itself " AND to
- indicate to the Inline code to save/restore the original interrupt
- regs.
- }
-
- Procedure Process_Intr;
- Begin
- { K e y b o a r d Interrupt o c c u r s here }
-
- {This Inline routine will save the regs and Stack for Stay resident programs.
- It restores Ds and Ss from the previously saved integer constants "OurDseg"
- and "OurSSeg". This is important since Dos is not re-entrant and any attempt
- to use Interrupt I/O services will clobber the very stack on which the
- Resident Turbo program just saved its regs. Thus, on the final return, you
- and Toto will end up somewhere other than Kansas and without your Ruby Reds.
- }
-
- Inline (
-
- { The following routine avoids the overhead of saving the DOS stack }
- { when the INT 16 function was not for a character request. This happens }
- { often (every four chars) as DOS checks on ^S/^Q/^C/Keypressed ad.nausea }
-
- $80/$FC/$00/ {Cmp Ah,00 If Char request, }
- $74/$07/ {Je ChrRqst enter Staysave code }
- $5D/$5D/ {Pop Bp/Pop Bp Restore Bp }
- $2E/
- $FF/$2E/User_IntIP/ {Jmp Far CS:[User_IntIP] }
-
- {ChrRqst: }
- $FA / { Cli Stop all interrupts }
- { Bp and Sp aready saved at Begin Stmt }
- $55/ {Push Bp Save again for Regpak }
- $BD/Regs/ {Mov Bp,offset REGS}
- $2E/$89/$46/$00/ {CS:Mov [Bp+0],AX}
- $2E/$89/$5E/$02/ {CS:Mov [Bp+2],Bx}
- $2E/$89/$4E/$04/ {CS:Mov [Bp+4],CX}
- $2E/$89/$56/$06/ {CS:Mov [Bp+6],DX}
- $2E/$8F/$46/$08/ {Pop CS:[Bp+8] Fetch Bp from stack }
- $2E/$89/$76/$0A/ {CS:Mov [Bp+A],SI}
- $2E/$89/$7E/$0C/ {CS:Mov [Bp+C],DI}
- $2E/$8C/$5E/$0E/ {CS:Mov [Bp+E],DS}
- $2E/$8C/$46/$10/ {CS:Mov [Bp+10],ES}
- $9C/ {PUSHF put Flags on stack to retrieve }
- $2E/$8F/$46/$12/ {POP CS:[Bp+12]}
-
- { If Current SS := [OurSseg] or Inuse = True, then dont save the stack. }
- { This program is being recursive. }
-
- $2E/$80/$3E/Inuse/$01/ {Cmp CS:[Inuse],1 }
- $74/$57/ {Je ReCurin -J-U-M-P- }
-
-
- $2E/$8C/$16/DosSSeg/ {Mov CS:DosSSeg,SS Save Dos Stack Segment }
- $8C/$D6/ {Mov Si,SS If this is our Stack Seg }
- $8E/$C6/ {Mov Es,Si Get Dos StackSeg }
- $2E/$8E/$16/OurSSeg/ {Mov SS,CS:OurSSeg Get our Stack segment }
- $2E/$8E/$1E/OurDseg/ {Mov Ds,CS:Our_Ds Setup our Data Segment }
-
-
- $2E/$3B/$36/OurSSeg/ {Cmp Si,CS:OurSSeg ..use current Stack ptr }
- $89/$E6/ {Mov Si,Sp ..value..else reset stack }
- $74/$05/ {Je $+5 ..to original Turbo stack }
- $3E/$8B/$36/$74/$01/ {Mov Si,Ds:[174] ..(cf. code at B2B 3.0x) }
-
- $87/$F4/ {Xchg Sp,Si Set new Stack Pointer }
- { Save Dos/User regs for Exit }
- $2E/$FF/$76/$00/ {Push [Bp+0] Save Ax }
- $2E/$FF/$76/$02/ {Push [Bp+2] Save Bx }
- $2E/$FF/$76/$04/ {Push [Bp+4] Save Cx }
- $2E/$FF/$76/$06/ {Push [Bp+6] Save Dx }
- {Push [Bp+8] Save Bp }
- $2E/$FF/$76/$0A/ {Push [Bp+A] Save Si }
- $2E/$FF/$76/$0C/ {Push [Bp+C] Save Di }
- $2E/$FF/$76/$0E/ {Push [Bp+E] Save Ds }
- $2E/$FF/$76/$10/ {Push [Bp+10] Save Es }
-
- { Now save 40 Words from the Dos Stack before performing any }
- { I/O or re-using the Dos stack }
-
- $B9/>$0028/ {Mov Cx,40 Save 40 Dos Stack words for Retn }
- {Restack:}
- $26/$FF/$34/ {Push Es:[Si] Our Stack := Dos Es:Si }
- $46/$46/ {Inc Si/Inc Si Get Next Dos Stack Word }
- $E2/$F9/ {Loop to Restack }
-
- $2E/$8E/$16/OurSSeg/ {Mov SS,CS:OurSSeg Set up our Stack }
- $56/ {Push Si Save bottom of Dos Stack }
- $2E/$8C/$5E/$0E/ {Mov CS:[Bp+E],Ds Set New Data Segmt in regs}
- {Recurin Jump here if Recursion }
- $FB {Sti Enable Interrupts }
-
- ) ;
- {...........................................................................}
-
- { Check the Int 16 request function in Ah reg:
- 0 = read character from Keyboard
- 1 = check character available
- 2 = check shift key values
- }
-
- { HalfRegs.Ah = 0 This is a Character Request because StaySave }
- { doesnt allow an enter here unless it is! }
-
-
- Intr (User_Int, Regs); { Use the DOS replaced interrupt}
- { Get Key from Keyboard }
- If (Halfregs.Ah = Our_Char) { Separate the tests so code }
- { performs efficiently. }
- then if (not InUse) then { Must be OUR key and not busy }
- Begin
- InUse := true; { "dont clobber saved stack"}
- Old_Xpos := WhereX;
- Old_Ypos := WhereY;
-
- user_stayres_procedure; {your program called here}
-
- GotoXY(Old_Xpos,Old_Ypos); { Put Cursor Back }
- Regs.Ax := $1D00; { Give Dummy Ctrl Scan Code to }
- { interrupted program }
-
- InUse := false; { ok to restore interrupted stack }
- End;
-
-
- { Inline Code to restore the stack and regs moved to the Turbo Resident
- Program Stack to allow re-entrancy into the Dos Code for I/O and
- recursion from built-in Turbo functions. Arthor: L.H. Ferris}
-
- inline(
-
- $BD/Regs/ {Mov Bp,offset REGS}
- $2E/$8B/$46/$00/ {CS:Mov Ax,[Bp+0]}
- $2E/$8B/$5E/$02/ {CS:Mov Bx,[Bp+2]}
- $2E/$8B/$4E/$04/ {CS:Mov Cx,[Bp+4]}
- $2E/$8B/$56/$06/ {CS:Mov Dx,[Bp+6]}
-
- $2E/$8B/$76/$0A/ {CS:Mov Si,[Bp+A]}
- $2E/$8B/$7E/$0C/ {CS:Mov Di,[Bp+C]}
- $2E/$8E/$5E/$0E/ {CS:Mov DS,[Bp+E]}
- $2E/$8E/$46/$10/ {CS:Mov ES,[Bp+10]}
- $2E/$FF/$76/$12/ {Push CS:[Bp+12]}
- $9D/ {Popf}
-
- { If [CS:InUse]:= True, then dont restore the stack. This program is }
- { being recursive. Else restore Dos Stack and Program Entry registers }
-
- $2E/$80/$3E/Inuse/$01/ {Cmp byte ptr CS:[Inuse],1 }
- $74/$23/ {Je ReCurOut }
-
- $FA / { Cli ; Stop all interrupts }
-
- { Move 40 words of our stack back to Dos Stack }
-
- $5E/ {Pop Si Bottom of Dos Stack }
- $B9/>$0028/ {Mov Cx,40 Return 40 Dos Stack Words }
- $2E/$8E/$06/DosSSeg/ {Mov ES,CS:DosSSeg Get Dos StackSegment }
- {Restack:}
- $4E/$4E/ {Dec Si/Dec Si Backup Dos Stack }
- $26/$8F/$04/ {Pop Es:[Si] Dos Stack := Our Stack }
- $E2/$F9/ {Loop to Restack }
- $89/$F5/ {Mov Bp,Si Save Dos Sp across Pops }
-
-
- $07/ {Pop Es }
- $1F/ {Pop Ds }
- $5F/ {Pop Di }
- $5E/ {Pop Si }
- $5A/ {Pop Dx }
- $59/ {Pop Cx }
- $5B/ {Pop Bx }
- $44/$44/ {Inc sp/Inc sp Thow old Ax value away }
-
- $89/$EC/ {Mov Sp,Bp Setup Dos Stack Ptr }
- $2E/$8E/$16/DosSSeg/ {Mov SS,CS:DosSSeg Give back Dos Stack }
-
- {RecurOut Clean up the Stack }
-
- $5D/ {Pop Bp Throw away old dos Sp }
-
- $BD/Regs/ {Mov Bp,offset REGS }
- $2E/$FF/$76/$12/ {Push CS:[Bp+12] }
- $9D/ {Popf }
- $5D/ {Pop Bp Retrieve old BP }
-
- $FB/ {Sti Enable interrupts }
- $CA/$02/$00 {Ret Far 002 }
- );
- {.......................................................................}
- End ;{Process_Intr}
-
- {-----------------------------------------------------------------------}
-
- {The main program installs the new interrupt routine and makes it permanently
- resident as the keyboard interrupt. The old keyboard interrupt is addressed
- through #67H, so it can still be used.
-
- The following dos calls are used:
-
- Function 25 - Install interrupt address
- input al = int number,
- ds:dx = address to install
- Function 35 - get interrupt address
- input al = int number
- output es:bx = address in interrupt
- Function 31 - terminate and stay resident
- input dx = size of resident program obtained from the memory
- allocation block at [CS:0 - $10 + 3]
- Function 49 - Free Allocated Memory
- input Es = Block Segment to free
- Interrupt 20 - Return to invoking process
- }
-
-
- {-----------M A I N B L O C K---------------------------------------------}
- procedure stay_resident;
- begin
-
- InUse := false;
- OurDseg:= Dseg; { Save the Data Segment Address for Interrupts }
- OurSseg:= Sseg; { Save our Stack Segment for Interrupts }
-
-
- Terminate_Flag := false ;
-
- {now install the interrupt routine, searching for a free vector}
-
- repeat
- SaveRegs.Ax := $3500 + User_Int;
- Intr($21,SaveRegs); {Check to make sure int not already used}
-
- { if SaveRegs.Es <> $00 then
- User_Int := User_Int + 1; }
-
- until (SaveRegs.Es = 0) or (User_Int > User_Int_max);
-
-
- if SaveRegs.Es <> 0 then
- WriteLn ('Interrupt ',User_Int,' in use -- can''t install Resident Code')
- else
-
- begin
-
- SaveRegs.Ax := $3500 + Kybrd_Int;
- Intr($21,SaveRegs); {get the address of keyboard interrupt }
-
- SaveRegs.Ax := $2500 + User_Int;
- SaveRegs.Ds := SaveRegs.Es;
- SaveRegs.Dx := SaveRegs.Bx;
- Intr($21,SaveRegs); { set the user-interrupt address to point
- { to the keyboard interrupt address }
-
- SaveRegs.Ax := $2500 + Kybrd_Int;
- SaveRegs.Ds := CSeg;
- SaveRegs.Dx := Ofs(Process_Intr);
- Intr ($21,SaveRegs); { set the keyboard interrupt to point to
- "Process-Intr" above}
-
- User_IntIP := MemW[0:User_Int * 4 ]; { Location of User Interrupt IP }
- User_IntCS := MemW[0:User_Int * 4 +2];{ Location of User Interrupt CS }
-
- {now terminate and stay resident}
- SaveRegs.Ax := $3100 + 0 ; { Terminate and Stay Resident }
- SaveRegs.Dx := MemW [CSeg-1:0003] ; { Prog_Size from Allocation Blk}
- Intr ($21,SaveRegs);
-
- end;
- { END OF RESIDENCY CODE }
- end;