home *** CD-ROM | disk | FTP | other *** search
- {$C-}
- {$R+}
- {-----------------------------------------------------------------------------}
- { " I Feel Better Now, Dave " }
- { Arthur C. Clark }
- { " 2001 " }
- {-----------------------------------------------------------------------------}
- { Stayres Version 4.10 }
- {
- 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.410 (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 (Windo 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 procecure. 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 changes 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.
- }
- 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 }
- 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.10'; { 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 }
-
- 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.410}
-
- {*****************************************************************************}
- {-----------------------------------------------------------------------------}
- { THE FOLLOWING ARE THE USER INCLUDE ROUTINES }
- {-----------------------------------------------------------------------------}
- {*****************************************************************************}
- {$I STAYSUBS.410}
- {----------------------------------------------------------------------------}
- { S T A Y D E M Demo Routines }
- {----------------------------------------------------------------------------}
- {$I ClkDem.410}
- (* 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.
- {----------------------------------------------------------------------------}
- { C L O C K D E M O Demo Routines }
- {----------------------------------------------------------------------------}
- {$I CLKDEM.410}
- *)
- {*****************************************************************************}
- {-----------------------------------------------------------------------------}
- { THE ABOVE ARE THE USER INCLUDE ROUTINES }
- {-----------------------------------------------------------------------------}
- {*****************************************************************************}
-
- {-----------------------------------------------------------------------------}
- { P R O C E S S I N T E R R U P T }
- { - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - }
-
-
- { PURPOSE:
- This procedure replaces the standard keyboard interrupts.
- 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.
-
- 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}
- Begin
- {$I Stayi16.410}
- End; {STAY_INT16}
-
- Procedure STAY_INT13; {BIOS Disk interrupt Routine}
- Begin
- {$I Stayi13.410}
- End; {STAY_INT13}
-
- Procedure STAY_INT21; {DOS interrupt 21 Service Routine}
- Begin
- {$I Stayi21.410}
- End; {STAY_INT21}
-
- Procedure Stay_INT8; {Timer Interrupt 8 Service Routine}
- Begin
- (* add the following include for the Clock Demonstration by Neil Rubenking
- {$I ClkI8.410}
- *)
- {$I ClkI8.410}
- {$I Stayi8.410}
- End;{Stay_Int8}
-
- Procedure Stay_INT28; {Idle Interrupt 28 Service Routine}
- Begin
- {$I Stayi28.410}
- End;{Stay_Int28}
-
- Procedure StaySave; {Prolog to Resident Turbo Code}
- Begin
- {$I StaySave.410}
- {**************************************************************************}
- {--------------------------------------------------------------------------}
- { INVOKE USER PROCEDURE HERE }
- {--------------------------------------------------------------------------}
- {**************************************************************************}
-
- 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}
-
- { .
- .
- . Your
- . Program
- . Goes
- . Here
- .
- }
- Demo ; {Replace Demo with your procedures}
-
- {**************************************************************************}
- {--------------------------------------------------------------------------}
- { 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}
-
- {---------------------------------------------------------------------------}
- { BEGINNING OF THE STAYRSTR ROUTINE }
- {---------------------------------------------------------------------------}
- {$I Stayrstr.410} { 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}
-
-
- { Initialize Your Progam Here since you wont get }
- { control again until the HotKey is entered from }
- { the Keyboard. }
-
- 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;
-
-
- Bytecount := 0; { Search for INT 28 instruction }
- While (Bytecount < $7000)
- and (Memw[DosStat2.CS:Bytecount] <> $28CD)
- do Bytecount := Succ(Bytecount);
-
- If Bytecount = $7000 then begin { Couldn't find INT 28 instruction }
- 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 }
- { INT 28 instruction. Critical byte address is somewhere }
- { above that location for different version of DOS. }
-
- If Memw[DosStat2.CS:Bytecount-7] = $3E80
- then DosStat2.IP := Memw[DosStat2.CS:Bytecount-5];
- If Memw[DosStat2.CS:Bytecount-12] = $06F6
- then DosStat2.IP := Memw[DosStat2.CS:Bytecount-10];
- If DosStat2.IP = 0 then begin
- Writeln('Cannot Find Dos Critical byte...Halting');
- Halt;
- end;
-
- Inline($FA); {Disable interrupts}
-
- { Setup Our Keyboard Interrupt Service Routine }
-
- Regs.Ax := $3500 + BIOSI16;
- Intr(DosI21,Regs); {get the address of keyboard interrupt }
- BIOS_Int16.IP := Regs.BX; { Location of DOS Interrupt Ip }
- BIOS_Int16.CS := Regs.Es; { Location of DOS Interrupt Cs }
-
- Regs.Ax := $2500 + BIOSI16; { set the keyboard interrupt to point to}
- Regs.Ds := Cseg; { "Process-Intr" above}
- Regs.Dx := Ofs(Stay_INT16);
- Intr (DosI21,Regs);
-
- { Setup Our Timer Interrupt Service Routine }
-
- Regs.Ax := $3500 + BIOSI8;
- Intr(DosI21,Regs); {get the address of Timer interrupt }
- BIOS_Int8.IP := Regs.BX; { Location of DOS Interrupt Ip }
- BIOS_Int8.CS := Regs.ES; { Location of DOS Interrupt Cs }
-
- Regs.Ax := $2500 + BIOSI8;
- Regs.Ds := Cseg;
- Regs.Dx := Ofs(Stay_INT8);
- Intr (DosI21,Regs);
-
- { Setup Our Disk Interrupt Service Routine }
-
- Regs.Ax := $3500 + BIOSI13;
- Intr(DosI21,Regs); {get the address of Disk interrupt }
- BIOS_Int13.IP := Regs.BX; { Location of DOS Interrupt Ip }
- BIOS_Int13.CS := Regs.Es; { Location of DOS Interrupt Cs }
-
- Regs.Ax := $2500 + BIOSI13;
- Regs.Ds := Cseg;
- Regs.Dx := Ofs(Stay_INT13);
- Intr (DosI21,Regs);
-
- { Setup Our DOS 21 Interrupt Service Routine }
-
- Regs.Ax := $3500 + DOSI21;
- Intr(DosI21,Regs); {Get address of DOS Router interrupt }
- DOS_Int21.IP := Regs.BX; { Location of DOS Interrupt Ip }
- DOS_Int21.CS := Regs.Es; { Location of DOS Interrupt Cs }
-
- Regs.Ax := $2500 + DOSI21;
- Regs.Ds := Cseg;
- Regs.Dx := Ofs(Stay_INT21);
- Intr (DosI21,Regs);
-
- { Setup Our DOS 28 Interrupt Service Routine }
-
- Regs.Ax := $3500 + DOSI28;
- Intr(DosI21,Regs); { Get address of Idle interrupt }
- DOS_Int28.IP := Regs.BX; { Location of DOS Interrupt Ip }
- DOS_Int28.CS := Regs.Es; { Location of DOS Interrupt Cs }
-
- Regs.Ax := $2500 + DOSI28;
- Regs.Ds := Cseg;
- Regs.Dx := Ofs(Stay_INT28);
- Intr (DosI21,Regs);
-
- 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. }
-
- 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
- new 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 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.