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.20
-
- { 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 .
-
- Separate the include files, compile to a COM file and execute with the
- Alt-F10 key. It will also free its memory and return to Dos with the
- Ctrl-Home key at the "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 raised the mAximum
- free value. This program can only run as a COM file.
-
- The Hunters Helper
-
- Lane Ferris
- 4268 26th St
- San Francisco,Ca. 94131
- [ 70357,2716 ] }
- {-----------------------------------------------------------------------------}
- { This code has been tested/used on an IBM PC using PC-DOS 2.10 }
- {-----------------------------------------------------------------------------}
-
-
- { 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.
- }
- Program Stay_Resident;
-
- { * * * * * * * CONSTANTS * * * * * * * * * * * * * * * * * * * * * * }
- const
- Our_Char = 113; {this is the scan code for AltF10}
- Ctrl_Home = #119; {Control Home Scan Code }
- Quit_Key = #119;
- Ctrl_End = #117; {Control End Scan Code }
- User_Int = $67; {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;
- 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 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 }
-
- { - - - - - - - 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 ;
- x,y : integer ;
-
-
- { - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - }
- {$I Nwindo.300} { W i n d o w M a k e r }
- { - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - }
- { Check Terminate Keys
- { - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - }
- {$I StayXit.320} {Check for Exit to Dos }
- {-----------------------------------------------------------------------------}
- { G E T F I L E }
- {-----------------------------------------------------------------------------}
- Procedure Get_file;
- {$I staysubs.300}
- var
- Trash : char;
- attribyte,
- OldAttribute : byte;
- Xcursor : integer ;
- Ycursor : integer ;
- {----------------------------------------------------------------------------}
- begin
-
- filename := '*.*' ;
- attribyte := 255 ;
- OldAttribute := attribyte;
-
- Xcursor := 2 ;
- Ycursor := 1 ;
- GotoXy(Xcursor,Ycursor) ;
-
- Find_First(attribyte,filename,Retcode);
- If Retcode = 0 then
- begin
- write(Filename);
- Ycursor := Ycursor +1 ;
- end;
- {Now we repeat Find_Next until an error occurs }
-
- repeat
- Find_Next(attribyte,filename,Retcode);
- if Retcode = 0 then
- begin
- GotoXY(Xcursor,Ycursor);
- Write(filename) ;
- Ycursor := Ycursor + 1 ;
-
- if WhereY >= 14 then
- begin
- Xcursor := Xcursor + 16 ;
- Ycursor := 1 ;
- end;
-
- if (Xcursor >= 50) and (Ycursor = 13 ) then
- begin
- Ycursor := Ycursor + 1;
- GotoXY(Xcursor,Ycursor);
-
- Get_Abs_Cursor(x,y); { Box up More msg..}
- MkWin(x,y,x+9,y+3,Cyan); Gotoxy(1,1);
- Write ('More...');
-
- While (Not Keypressed) do;
- Read(Kbd,trash) ;
- RmWin; { Remove "More" window }
-
- clrscr ;
- Xcursor := 2 ;
- Ycursor := 1 ;
- end;
- end;
- until Retcode <> 0;
- { Make a little Window and hold for }
- { user to give us a goose..or whatever}
- GotoXY(Xcursor,Ycursor);
- Get_Abs_Cursor(x,y); { Get Absolute Cursor Position }
- MkWin(x,y,x+12,y+3,Cyan); { Put Window at Cursor }
- GotoXY(1,1);
- Write('Press a key . . .');
-
- While (Not Keypressed) do; { Pause until Key pressed }
- While Keypressed do { Get Ctrl-Home maybe }
- Read(Kbd,KeyChr); { Read the users Key }
- RmWin ; { Remove the Window }
- If KeyChr = Quit_Key then { If Terminate Key then }
- Stay_Xit ; { remove ourself from Memory }
- end;
-
- {-----------------------------------------------------------------------------}
- { D E M O }
- {-----------------------------------------------------------------------------}
- Procedure Demo ; { Give Demonstration of Code }
-
- begin
- KeyChr := #0;
- MkWin(5,5,75,20,Cyan);
- TextColor(White);
- Clrscr;
- Get_file;
-
- RmWin;
-
- end; { Demo }
-
-
- {----------------------------------------------------------------------------}
- { 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 <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.
- }
- Begin
- { K e y b o a r d Interrupt o c c u r s here }
- {----------------------------------------------------------------------}
- {$I Staysave.320}
- {----------------------------------------------------------------------}
- { 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 { Demo }
- InUse := true; { "dont clobber saved stack"}
- { .
- .
- . Your
- . Program
- . Goes
- . Here
- .
- } { Get current Cursor Position }
- Old_Xpos := WhereX; Old_Ypos := WhereY;
- Demo ;
- { Writeln(Lst,'That''s all Folks');{ Test Printer Output if you like }
- 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; { Demo }
-
- {$I Stayrstr.310} { Return to Caller }
- 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---------------------------------------------}
- Begin {**main**}
-
- 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}
-
- SaveRegs.Ax := $35 shl 8 + User_Int;
- Intr($21,SaveRegs); {Check to make sure int not already used}
-
- if SaveRegs.Es <> $00 then
- WriteLn ('Interrupt in use -- can''t install Resident Turbo Code')
- else
- begin
-
- { Initialize Your Progam Here since you wont get control again
- until "Our_Char" is entered from the Keyboard. }
-
- SaveRegs.Ax := $35 shl 8 + Kybrd_Int;
- Intr($21,SaveRegs); {get the address of keyboard interrupt }
-
- SaveRegs.Ax := $25 shl 8 + 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 := $25 shl 8 + 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 }
-
- Writeln(' Turbo Stay-Resident Demo: Press Alt-F10');
-
- {now terminate and stay resident}
- { Pass return code of zero }
- SaveRegs.Ax := $31 shl 8 + 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.