home *** CD-ROM | disk | FTP | other *** search
- {$C-}
- {-----------------------------------------------------------------------------}
- { " 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.40 }
-
- { 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 stay-resident program
- could not ordinarily issue file I/O since that would clobber Dos interrupt
- registers. Therefore, the following code proposes an inline solution,
- providing a 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.1, 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.??? as the
- Main file. Then execute the command file and activate with the default
- Alt-F9 key. It 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
- file). Maximum free dynamic memory should be between 300-400 paragraphs
- since this demo uses a recursive stack. 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 -
- 20K. This program can ONLY run as a COM file.
-
- The use of user interrupt locations in low memory has been removed as of
- Version 3.33.
-
- The Hunter's Helper
-
- Lane Ferris
- 4268 26th St
- San Francisco,Ca. 94131
- [ 70357,2716 ]
-
- If you find this program useful, $15 would be appeciated to help in its
- evolution and upkeep.
-
- }
- {-----------------------------------------------------------------------------}
- { This code has been tested/used on an IBM PC using PC-DOS 2.1/3.1 }
- {-----------------------------------------------------------------------------}
- { 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) }
- { 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 "Intr_Process" below.
- During execution of other programs, it can be invoked by the
- special key combination specified by "Our_Char" (in this case
- Alt-F9.)
-
- 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 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.04.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.18.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
- Version 3.31
- 9.19.85 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.29.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.30.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.6.85 Version 3.40 l.ferris
- Clean up Window errors, add 3rd window options. Correct
- Alpa/Beta errors. Say Thanks to Neil once again.
- }
- 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 = #102; {Control Function 9 Scan code }
- Ctrl_Home = #119; {Control Home Scan Code }
- Ctrl_End = #117; {Control End Scan Code }
- Kybrd_Int = $16; {BIOS keyboard interrupt}
- Our_Char = 112; {this is the scan code for Alt-F9}
- Quit_Key = Ctrl_F9; {Quit and Release Memory}
-
- {------------- 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];
-
- {-------------- T Y P E D C O N S T A N T S --------------------------}
- Const
- {regs is defined as a typed constant 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 }
- DOS_IntIP : integer = 0; {Pointer to Original IP Int value }
- DOS_IntCs : integer = 0; {Pointer to Original Cs Int value }
- StackSize : integer = 0; {Current User/or Dos Stack word size}
- {-------------- V A R I A B L E S ----------------------------------------}
- Var
- SaveRegs : regtype;
- HalfRegs : halfregtype absolute regs;
- Terminate_flag : boolean ;
- Keychr : char ;
- Old_Xpos,Old_Ypos : integer ;
- I : integer;
-
- {-----------------------------------------------------------------------------}
- { W I N D O W R O U T I N E }
- {---------------------------------------------------------------------------- }
-
- {$I STAYWNDO.340}
-
- {-----------------------------------------------------------------------------}
- { S T A Y E X I T }
- {-----------------------------------------------------------------------------}
- {$I STAYXIT.340}
- {----------------------------------------------------------------------}
- { C a l l O r i g i n a l I n t e r r u p t }
- {----------------------------------------------------------------------}
- Procedure CallOriginalIntr(Var RegAx: Integer);
- {Invoke the original DOS interrupt and }
- Begin {Return the value in parameter }
- inline(
- $B4/$00/ {Mov Ah,Read function }
- $9C/ {Push Flags }
- $2E/$FF/$1E/DOS_IntIP/ {Call Far [DOS_IntIP] }
- $C4/$BE/RegAx/ {Les Di,KeyChr[Bp] }
- $AB {StosW Stuff in new KeyChr }
- );
- End; {CallOriginalIntr}
- {----------------------------------------------------------------------}
- { K e y i n : R e a d K e a b o a r d }
- {----------------------------------------------------------------------}
- Function Keyin: char; { Get a key from the Keyboard }
- Var Ch : char; { If extended key, fold above 127 }
- Begin {---------------------------------------}
- Repeat until Keypressed;
- Read(Kbd,Ch);
- if (Ch = Esc) and KeyPressed then
- Begin
- Read(Kbd,Ch);
- Ch := Char(Ord(Ch) + 127);
- End;
- Keyin := Ch;
- End; {Keyin}
- {----------------------------------------------------------------------}
- { B e e p : S o u n d t h e H o r n }
- {----------------------------------------------------------------------}
- Procedure Beep(N :integer); {------------------------------------------}
- Begin { This routine sounds a tone of frequency }
- Sound(n); { N for approximately 100 ms }
- Delay(100); {------------------------------------------}
- Sound(n div 2);
- Delay(100);
- Nosound;
- End {Beep} ;
-
- {*****************************************************************************}
- {-----------------------------------------------------------------------------}
- { THE FOLLOWING ARE THE USER INCLUDE ROUTINES }
- {-----------------------------------------------------------------------------}
- {*****************************************************************************}
-
- {----------------------------------------------------------------------}
- { G E T F I L E }
- {----------------------------------------------------------------------}
- Procedure Get_file;
- {$I STAYSUBS.340}
- {$I STAYDEM.340 }
-
- {*****************************************************************************}
- {-----------------------------------------------------------------------------}
- { THE ABOVE ARE THE USER INCLUDE ROUTINES }
- {-----------------------------------------------------------------------------}
- {*****************************************************************************}
-
- {-----------------------------------------------------------------------------}
- { P R O C E S S I N T E R R U P T }
- { - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - }
- Procedure Process_Intr;
-
- { PURPOSE: This procedure replaces the standard keyboard interrupt.
- If anything but "Our_Char" is pressed, the key is passed on to
- the standard keyboard interrupt. B*U*T when "Our_Char" is pressed,
- this program takes over. The variable <InUse> is set 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.
- }
- { Do not put Variables or Contants 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. }
-
- Begin
- { K e y b o a r d Interrupt o c c u r s here }
- {----------------------------------------------------------------------}
- { START OF STAYSAVE ROUTINE }
- {----------------------------------------------------------------------}
- {$I StaySave.340}
- {---------------------------------------------------------------------------}
- { END OF THE STAYSAVE REGISTER ROUTINE }
- {---------------------------------------------------------------------------}
- { Int 16 request function in Ah reg: }
- { 0 = read character from Keyboard }
- { 1 = check character available }
- { 2 = check shift key values }
-
- { HalfRegs.Ah = Our_Char because StaySave }
- { doesnt enter here unless it is! }
-
- If (not InUse) then { Must be OUR key and NOT busy }
- Begin { Demo }
- InUse := true; { "dont clobber saved stack"}
-
- {**************************************************************************}
- {--------------------------------------------------------------------------}
- { INVOKE USER PROCEDURE HERE }
- {--------------------------------------------------------------------------}
- {**************************************************************************}
- { .
- .
- . Your
- . Program
- . Goes
- . Here
- .
- }
- Demo ;
-
- {
- {
- For I := 1 to 10 do
- Writeln(Lst,'That''s all Folks'); }
- { Test Printer Output if you like }
-
- {**************************************************************************}
- {--------------------------------------------------------------------------}
- { END USER PROCEDURE HERE }
- {--------------------------------------------------------------------------}
- {**************************************************************************}
- { Because INUSE is still TRUE, the next read will pass }
- { back OurChar, if you press it, to the interrupted pgm.}
- { We'll beep for the time being. Mr Pavlov would love it}
-
- CallOriginalIntr(Regs.Ax); { Get input key for the users }
- If HalfRegs.Ah = Ord(Our_Char) then Beep(650);
-
- InUse := false; { ok to restore interrupted stack }
- End; { Demo }
- {---------------------------------------------------------------------------}
- { BEGINNING OF THE STAYRSTR ROUTINE }
- {---------------------------------------------------------------------------}
- {$I StayRstr.340 } { RETURN TO CALLER }
- {---------------------------------------------------------------------------}
- { END OF THE STAYRSTR ROUTINE }
- {---------------------------------------------------------------------------}
-
- End ;{Process_Intr}
-
- {-------------------------------------------------------------------------}
- { 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 Dos_IntCS and IP, so it 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 }
- { Interrupt 20 - Return to invoking process }
- {-----------------------------------------------------}
- Begin {**main**}
-
- InUse := false; { Turn off the Inuse flag in case we do a write}
- OurDseg:= Dseg; { Save the Data Segment Address for Interrupts }
- OurSseg:= Sseg; { Save our Stack Segment for Interrupts }
-
-
- Terminate_Flag := false; { Havent received a Kill key yet }
- SaveRegs.Es := 00; { Clear for Dos 3.0 bug }
- { now install the interrupt routine}
-
- { Initialize Your Progam Here since you wont get }
- { control again until "Our_Char" is entered from }
- { the Keyboard. }
-
- SaveRegs.Ax := $3500 + Kybrd_Int;
- Intr($21,SaveRegs); {get the address of keyboard interrupt }
-
- DOS_IntIp := SaveRegs.BX; { Location of DOS Interrupt Ip }
- DOS_IntCs := SaveRegs.Es; { Location of DOS Interrupt Cs }
-
- 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}
-
-
- {****************************************************************************}
- {----------------------------------------------------------------------------}
- { INITIALIZE YOUR PROGRAM HERE }
- {----------------------------------------------------------------------------}
- {****************************************************************************}
- { Initialize Your Progam Here since you wont get control again
- until "Our_Char" is entered from the Keyboard. }
-
- Writeln(' Turbo Stay-Resident Demo(3.40): Press Alt-F9');
-
- {****************************************************************************}
- {----------------------------------------------------------------------------}
- { END OF INITALIZE PROGRAM CODE }
- {----------------------------------------------------------------------------}
- {****************************************************************************}
- { Now terminate and stay resident The following Call utilizes the new }
- { Terminate & Stay Resident function by passing the program allocation }
- { set in the Memory Control Block when Turbo prolog issued 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 }
- SaveRegs.Ax := $3100 ; { Terminate and Stay Resident }
- SaveRegs.Dx := MemW [Cseg-1:0003] ; { Prog_Size from Allocation Blk}
- Intr ($21,SaveRegs);
-
-
- { END OF RESIDENCY CODE }
- end.