home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS 1992 June
/
SIMTEL_0692.cdr
/
msdos
/
turbopas
/
stay42.arc
/
CLKRES.430
< prev
next >
Wrap
Text File
|
1986-08-14
|
26KB
|
516 lines
{$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.