home *** CD-ROM | disk | FTP | other *** search
- {$R+}
- {$C-}
- {-----------------------------------------------------------------------------}
- { " Look, Dave, I know you're trying to be helpful. But }
- { the fault is either in the ... system - or in YOUR }
- { test procedures. My information processing is perfectly }
- { normal. " }
- { Arthur C. Clark - " 2001 " }
- {-----------------------------------------------------------------------------}
- { Stayres Version 4.15 }
- {
- Copyright (C) LaneFerris 1985,1986.
- Distributed to the Public Domain for use without Profit.
-
- A Turbo "stay-resident" program clobbers the Dos register stack. It
- jumps over the Turbo run-time initialization code that would set up the
- program registers and environment. Secondly, a Turbo TSR (Terminate
- and stay-resident) could not ordinarily issue file I/O since that would
- clobber Dos interrupt registers.
-
- Therefore, the following code proposes an inline solution, recovering the
- Turbo entry stack for "stay-resident" programs and allowing those
- programs to issue Dos I/O and other interrupts.
-
- This Turbo stay-resident demo has been put together to perform both Dos I/O
- and Bios interrupts. It has been tested for re-entrancy and recursiveness
- on an IBM PC with PCDOS 2.0, 2.1, 3.0, 3.1 .
-
- R_U_N I_N_S_T_R_U_C_T_I_O_N_S
- Separate the include files, compile to a COM file using STAYRES.420 (or the
- current release level) as the Main file. Then execute the command file
- from the DOS prompt.
-
- Use the Turbo Compiler Options window to set the Maximum free dynamic
- memory between 300-400 paragraphs. If you get $FF runtine errors or
- "allocation error", "cannot load Command.Com", then adjust the mAximum free
- value to something reasonable but less than your maximum memory (minus
- 20K). This program can ONLY run as a COM file.
-
- Activate with the default hotkey (Alt-F9). Stayres will also free its
- memory and return to Dos with the Cntl-F9 key at the last "Press a key"
- prompt (Illustrated in the Stayxit routine).
-
-
- The Hunter's Helper
-
- Lane Ferris
- 4268 26th St
- San Francisco,Ca. 94131
- Compuserv 70357,2716
-
- If you find this program useful, $15 will aid in its evolution and upkeep.
-
- }
- { Authors: Lane Ferris (Stay Resident/Exit Code) }
- { Neil J. Rubenking (Directory code and ideas) }
- { Karson W. Morrison (Stay Resident modifications) }
- { Lynn A. Canning (Window coding revisions) }
- { Bela Lubkin (INT24 processing) }
- { 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,
- (or INT 9) displacing the original Interrupt Vector to a Turbo inline
- service procedure. During execution of other programs, it can be
- invoked by the special key combination specified by "Our_HotKey"
- (in this case Alt-F9.) }
-
- {
- Modifications:
- 7.85 - Replace Windows with a more simple form/less code.
- Replace Window Array with Pointers/Heap form.
- 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".
- 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.85 - Version 3.10 Changes
- 1) Save 40 words in StaySave/Rstr to avoid clobbering
- 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.85 - Version 3.20 changes
- 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.
- 9.85 - Version 3.2C
- When saving/restoring the stack, save 40 words or less
- depending on stack size (0-Sp = stack size) to avoid
- overflowing into SS:0 when stack is less than 40 words.
- Put back the "wait for user key logic" at Demo end.
- Beep like SuperKick if Key is OurKey
- 9.85 - Version 3.31
- Futz around with the "wait for user key logic", allow
- the Our_key to pass, but beep user to show we aint
- gonna activate, cuz our InUse bit is still set.
- Clean up the documentation and duplicate instructions in
- StaySave/Rstr.
- Change Int67 to Int60 for Fun and Profit and get around
- Mark Stanock's use of those locations.
- 9.85 - Version 3.32
- Changes made by Karson W. Morrison
- Modified the STAYRES.331 version to remove all coding
- that was not necessary for the stayres routines.
- The coding associated with the demo was put into
- seperate include files. The coding for a revised windo.inc
- file was placed into the stayres program. The windo
- routines were changed to allow background and forground
- colors and to allow borders of one line, two lines, or
- no lines. Read the doc info. in the windo.inc file.
- Revisions for the windo.inc file were made by
- Lynn A. Canning. The windo routine will now allow a
- window of 1,1,80,25.
- 10.85 - Version 3.33 l.ferris
- Correct inverted parameters in Stay Windo include file
- Delete unused variables and code in demo code.
- Rename files to keep with Version/Release/Modification
- numbering scheme.
- Remove necessity for using User Interrupt locations in
- low storage. Use Far calls to original interrupt.
- Change Alt-F10 to Alt-F9 to avoid common conflicts.
- Change Cntl-Home to Cntl-F9 keys to avoid common conflicts.
- 12.85 - Version 3.40 l.ferris
- Clean up Window errors, add 3rd window options. Correct
- Alpa/Beta errors. Say Thanks to Neil once again.
- 4.86 - Version 4.00
- Rewrite stay-resident interface. Avoid manipulating
- DOS or Users interrupted stack.
- Intercepts Interrupts 9, 8, 13, 21, 28
- 6.86 - Replace INT 9 processing with an INT 16 equivalent.
- Works better with mutitasking environments. Leave
- INT 9 as an option.
- - Version 4.10
- Addition of Neil RubenKing's Clock Demonstration.
- Great work Neil. Thanks! Corrections from beta tests.
- Documentation cleanup.
- Enable interrupts within INT21 service routine.
- 7.26 - Version 4.11 Stayi8 missing ES:Lodsb instr
- - Version 4.12 Special for NJR/TRG/LTW
- 7.28 - Version 4.13 Stayi8 change Add to OR
- BP not being protected from BIOS usage
- 8.02 - Version 4.14 Attempt to solve Exit Crashes
- Exit thru stack restore, not INT $20
- Correct Ctlc-C crashes. INT23 was set to zeros
- Change SetCtlc,GetCtlc parameters to call-by-name
- 8.04 - Version 4.15 Save Indos Primary stack for recursive
- entries to DOS functions [0..C] (Writeln(LST or AUX))
- Rework Staysave,Stayrstr
- 8.14 - Version 4.20 Public Release of 4.1.+ fixes
- }
- Program Stay_Resident;
-
- { * * * * * * * CONSTANTS * * * * * * * * * * * * * * * * * * * * * * }
- const
- { the next field is needed for the windo.inc routines }
- MaxWin = 2; { Max number of windows open at one time }
- Esc = #27; {character equivalent of Escape Key}
- Alt_F9 = #112; {Alt Function 9 Scan code }
- Ctrl_F9 = #229; {Ctl-F9 (#102+127) Key code }
- Quit_Key = Ctrl_F9; {Quit and Release Memory}
-
- Alt = 08; {Shift bits at 40:17 }
- Ctrl = 04;
- Left_Shift = 02;
- Rght_Shift = 01;
-
- BIOSI8 = 8; {Bios Timer interrupt}
- BIOSI16 = $16; {Bios Keyboard interrupt}
- BIOSI13 = $13; {Bios Disk interrupt}
- DOSI21 = $21; {DOS service router interrupt}
- DOSI28 = $28; {DOS Idle 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;
- filename_type = string[64];
- Vector = record { Interrupt Vector type }
- IP,CS :integer ;
- end ;
-
- {-------------- T Y P E D C O N S T A N T S --------------------------}
- Const
-
- Our_HotKey : byte = 112; { scan code for Alt-F9}
-
- { This table marks those INT 21 functions which must be passed }
- { without modification. They either never return, fetch parameters }
- { from the stack, or may be interrupted by a TSR }
-
- Functab : array[0..$6F] of byte =
- (1,1,1,1, 1,1,1,1, 1,1,1,1, 1,0,0,0, {0-C}
- 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
- 0,0,0,0, 0,0,1,0, 0,0,0,0, 0,0,0,1, {26,2F}
- 0,1,1,1, 1,1,0,0, 0,0,0,0, 0,0,0,0, {31-35}
- 0,0,0,0, 0,0,0,0, 1,1,1,1, 1,1,0,0, {48-4D}
- 1,1,1,1, 0,1,0,0, 1,0,0,0, 0,1,1,1, {50-53,55,58,5D-5F}
- 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1); {60-62}
-
- Intr_Flags : byte = 0; {Active interrupts flags}
- INT13_on = 04; {Disk interrupt is active}
- INT21_on = 08; {DOS Service router is active}
- Status : byte = 0; {Status of current TSR activity}
- Hotkey_on = 01; {Received the HotKey}
- Inuse = 02; {TSR is active}
- Foxs = $FF; {workaround for inline hex FF}
- DosVersion : byte = 0; {Current Version of DOS}
- WaitCount : byte = 0; {Wait to activate count}
- UserProgram :integer = 0; {Offset to Users Program Code}
-
- OurDSeg: integer = 0; {Turbo Data Segment Value }
- OurSSeg: integer = 0; {Turbo Stack Segment Value }
-
- DosDSeg: integer = 0; {Dos Datasegment value }
- DosSSeg: integer = 0; {Dos Stack Segment Value }
- DosSPtr: integer = 0; {Dos Stack pointer value }
- DosSsiz: integer = 0; {Dos Stack size in words }
-
- UsrDSeg: integer = 0; {Interrupted Datasegment value }
- UsrSSeg: integer = 0; {Interrupted Stack Segment Value }
- UsrSPtr: integer = 0; {Interrupted Stack pointer value }
- OurPSP : integer = 0;
-
-
- { The following constants *MUST* remain in the IP:CS order. }
- { StaySave uses them as JMP targets }
-
- BIOS_INT8 : vector = (IP:0;CS:0); {BIOS Timer Interrupt Vector }
- BIOS_INT16 : vector = (IP:0;CS:0); {BIOS Keyboard Interrupt Vector }
- BIOS_INT13 : vector = (IP:0;CS:0); {BIOS Disk Interrupt Vector }
- DOS_INT21 : vector = (IP:0;CS:0); {DOS Sevice Interrupt Vector}
- DOS_INT28 : vector = (IP:0;CS:0); {DOS idle Service interrupt Vector}
- DOSStat1 : vector = (IP:0;CS:0); {Pointer to INDOS byte}
- DOSStat2 : vector = (IP:0;CS:0); {Pointer to CRITICAL byte}
-
- Version :string[4] = '4.15'; { Current Version number }
-
- {-------------- V A R I A B L E S ----------------------------------------}
- Var
-
- Regs : regtype;
- HalfRegs : halfregtype absolute regs;
- Keychr : char ;
- Bytecount : integer;
-
- SavedPSP : integer; { Program Segment Prefix pointers }
- Error : integer; { I/O results }
- Good : boolean; { I/O results switch }
- Terminate : boolean; { Exit stayRes Flag }
-
- OurDTA :Array [1..2] Of integer; {Local DTA pointer}
- SavedDTA :Array [1..2] of integer; {Interrupted DTA pointer}
-
- {-----------------------------------------------------------------------------}
- { W I N D O W R O U T I N E }
- {---------------------------------------------------------------------------- }
- {$I STAYWNDO.341}
- {----------------------------------------------------------------------}
- { S T A Y E X I T }
- {----------------------------------------------------------------------}
- {$I STAYXIT.420}
- {*****************************************************************************}
- {-----------------------------------------------------------------------------}
- { THE FOLLOWING ARE THE USER INCLUDE ROUTINES }
- {-----------------------------------------------------------------------------}
- {*****************************************************************************}
- {$I STAYSUBS.420}
- {-------------------------------------------------------------}
- { S T A Y D E M Demo Routines }
- {-------------------------------------------------------------}
- { comment out the next line to use the Rubenking Background Clock }
- (****{$I STAYDEM.420}***)
- {-------------------------------------------------------------}
- { C L O C K D E M O Demo Routines }
- {-------------------------------------------------------------}
- { Substitute the following lines for the Clock Demo by Neil Rubenking.
- Comment or remove the $I STAYDEM.... line above
- See additional comment at interrupt 8 inline procedure Stay_INT8.}
- {$I CLKDEM.420}
- {-----------------------------------------------------------------------------}
- { THE ABOVE ARE THE USER INCLUDE ROUTINES }
- {-----------------------------------------------------------------------------}
-
- {-----------------------------------------------------------------------------}
- { P R O C E S S I N T E R R U P T }
- {-----------------------------------------------------------------------------}
- { PURPOSE:
- The following procedures displace standard interrupts.
-
- Do not put Variables or Constants in this Procedure. It will
- cause registers to be clobbered during the Interrupt routine
- when Turbo attempts to allocate storage for local variables
- or parameters.
-
- }
-
- Procedure STAY_INT16; {Keyboard Interrupt 16 Service Routine}
- {
- If anything but "Our_HotKey" is pressed, the key is passed
- to the standard keyboard service routine. B_U_T, when Our
- HotKey is recognized, a hotkey bit is set.
- }
- Begin
- {$I Stayi16.410}
- End; {STAY_INT16}
-
- Procedure STAY_INT13; {BIOS Disk interrupt Routine}
- Begin {Sets a flag while disk is active}
- {$I Stayi13.410}
- End; {STAY_INT13}
-
- Procedure STAY_INT21; {DOS interrupt 21 Service Routine}
- Begin {Sets a flag while INT 21 is active}
- {$I Stayi21.410}
- End; {STAY_INT21}
-
-
- Procedure Stay_INT8; {Timer Interrupt 8 Service Routine}
- {Activates Stayres during pgm execution}
- Begin {when safe to do so.}
- { add the following include for the Clock Demonstration by Neil Rubenking }
- {$I ClkI8.410}
-
- {$I Stayi8.420}
- End;{Stay_Int8}
-
- Procedure Stay_INT28; {Idle Interrupt 28 Service Routine}
- Begin {Invokes Stayres from the DOS prompt}
- {$I Stayi28.410} {and allows background activity to }
- End;{Stay_Int28} {continue}
-
- Procedure StaySave; {Prolog to Resident Turbo Code}
- Begin
- {$I StaySave.420}
-
- GetDTA(SavedDTA[1],SavedDTA[2]); {Save callers DTA address}
-
- GetPSP(SavedPSP); {Save callers PSP Segment}
- SetPSP(OurPSP); {Set our PSP Segment}
-
- SetDTA(OurDTA[1],OurDTA[2]); {Set our DTA address}
-
- NewCtlc[2] := CSeg;
- NewCtlc[1] := Ofs(IRET);
- GetCtlC(SavedCtlc); SetCtlC(NewCtlc); {Get/Save the users Ctrl-C vector}
-
- INT24On; {Trap Dos Critical Errors}
-
- {-------------------------------------------------------}
- { INVOKE USER PROCEDURE HERE }
- {-------------------------------------------------------}
- { .
- .
- . Your
- . Program
- . Goes
- . Here
- .
- }
- Demo ; {Replace Demo with your procedures}
-
- (*** Writeln(Lst,'.... Demonstrate auxilary device usage ....'); ***)
-
- {----------------------------------------------------------}
- { END USER PROCEDURE HERE }
- {----------------------------------------------------------}
-
- SetPSP(SavedPSP); { Restore Callers PSP Segment}
-
- SetDTA(SavedDTA[1],SavedDTA[2]); { Restore the users DTA}
- SetCtlC(SavedCtlC); { Restore the users Ctrl-C Vector}
-
- INT24Off; { Remove Our Critical Error routine}
- If (Terminate = true) then Stay_Xit;{ If exit key, restore Int Vectors }
- {---------------------------------------------------------------------------}
- { BEGINNING OF THE STAYRSTR ROUTINE }
- {---------------------------------------------------------------------------}
- {$I Stayrstr.420} { RETURN TO CALLER }
- {---------------------------------------------------}
- { END OF THE STAYRSTR ROUTINE }
- {---------------------------------------------------}
-
- End ;{StaySave}
-
- {-------------------------------------------------------------------------}
- { M A I N }
- {-------------------------------------------------------------------------}
- { The main program installs the new interrupt routine }
- { and makes it permanently resident as the keyboard }
- { interrupt. The old keyboard interrupt Vector is }
- { stored in Variables , so they can be used in Far }
- { Calls. }
- { }
- { 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 }
- {-----------------------------------------------------}
- Begin {**main**}
-
- Writeln('Turbo Stayres Version ',Version,' initializing.');
-
- OurDseg:= Dseg; { Save the Data Segment Address for Interrupts }
- OurSseg:= Sseg; { Save our Stack Segment for Interrupts }
- GetPSP(OurPSP); { Local PSP Segment }
-
-
- GetDTA(OurDTA[1],OurDTA[2]); { Record our DTA address }
-
- UserProgram:=Ofs(Staysave); {Set target of call instruction}
- Regs.Ax := $3000 ; {Obtain the DOS Version number}
- Intr(DosI21,Regs);
- DosVersion := Halfregs.Al; { 0=1+, 2=2.0+, 3=3.0+ }
-
- {Obtain the DOS Indos status location}
- Regs.Ax := $3400;
- Intr(DosI21,Regs);
- DosStat1.IP := Regs.BX;
- DosStat1.CS := Regs.ES;
- DosStat2.CS := Regs.ES;
- DosSSeg := Regs.ES;
-
- Bytecount := 0; { Search for CMP [critical flag],00 instruction }
- While (Bytecount < $2000) { then Mov SP,stackaddr instruction }
- and (Memw[DosStat2.CS:Bytecount] <> $3E80)
- do Bytecount := Succ(Bytecount);
-
- If Bytecount = $2000 then begin { Couldn't find critical flag addr }
- Writeln('StayRes incompatiblity with Operating System');
- Writeln('StayRes will not install correctly..Halting');
- Halt; end;
-
- { Search for the DOS Critical Status Byte address. }
- { Bytecount contains offset from DosStat1.CS of the }
- { CMP [critical flag],00 }
- { JNZ .... }
- { Mov SP,indos stack address }
-
- If Mem[DosStat2.CS:Bytecount+7] = $BC {MOV SP,xxxx}
- then BEGIN
- DosStat2.IP := Memw[DosStat2.CS:Bytecount+2];
- DosSptr := Memw[DosStat2.CS:bytecount+8]; {INDOS Stack address}
- END
- else BEGIN
- Writeln('Cannot Find Dos Critical byte...Halting');
- Halt;
- end;
-
- Inline($FA); {Disable interrupts}
-
- { Setup Our Interrupt Service Routines }
-
- Setup_Interrupt(BIOSI16, BIOS_Int16, Ofs(Stay_INT16)); {keyboard}
- Setup_Interrupt(BIOSI8, BIOS_Int8, Ofs(Stay_INT8)); {timer}
- Setup_Interrupt(BIOSI13, BIOS_Int13, Ofs(Stay_INT13)); {disk}
- Setup_Interrupt(DOSI21, DOS_Int21, Ofs(Stay_INT21)); {DOSfunction}
- Setup_Interrupt(DOSI28, DOS_Int28, Ofs(Stay_INT28)); {DOS idle}
-
- Inline($FB); {Re-enable interrupts}
- {****************************************************************************}
- {----------------------------------------------------------------------------}
- { INITIALIZE YOUR PROGRAM HERE }
- {----------------------------------------------------------------------------}
- {****************************************************************************}
- { Initialize Your Progam Here since you wont get control again
- until "Our_HotKey" is entered from the Keyboard. }
-
- Terminate := false; { Clear the program exit flags }
- Writeln(' Author: The Hunter''s Helper');
- Writeln(' LaneFerris, Compuserv 70357,2716');
- Writeln(' Alt-F9 activates : Ctrl-F9 deactivates');
- {------------------------------------------------------------}
- { END OF INITALIZE PROGRAM CODE }
- {------------------------------------------------------------}
- {
- Now terminate and stay resident. The following Call utilizes the
- DOS Terminate & Stay Resident function. We get the amount of
- memory by fetching the memory allocation paragraphs from the Memory
- Control Block. This was set by Turbo initialization during Int
- 21/function 4A (shrink block), calculated from the mInimum and mAximum
- options menu. The MCB sits one paragraph above the PSP.
-
- }
- { Pass return code of zero }
- Regs.Ax := $3100 ; { Terminate and Stay Resident }
- Regs.Dx := MemW [Cseg-1:0003]+1 ; { Prog_Size from Allocation Blk}
- Write(' Using ',Regs.Dx /64 :4:1,'K');
- Write(' Code:',(Dseg-Cseg)/64 :4:1,'K');
- Write(' Data:',(SSeg-Dseg)/64 :4:1,'K');
- Write(' Heap:',(Cseg+Regs.Dx-SSeg)/64 :4:1,'K');
- Intr (DosI21,Regs);
-
-
- { END OF RESIDENCY CODE }
- end.