home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / STAYRESP.ZIP / CLKRES.410 < prev    next >
Encoding:
Text File  |  1986-06-18  |  26.3 KB  |  558 lines

  1. {$C-}
  2. {$R+}
  3. {-----------------------------------------------------------------------------}
  4. {         "  I Feel Better Now, Dave "                                        }
  5. {                                                          Arthur C. Clark    }
  6. {                                                           " 2001 "          }
  7. {-----------------------------------------------------------------------------}
  8. { Stayres Version 4.10 }
  9. {
  10.   Copyright (C) LaneFerris 1985,1986.
  11.   Distributed to the Public Domain for use without Profit.
  12.  
  13.   A  Turbo  "stay-resident" program clobbers the Dos register stack.  It
  14.   jumps over the Turbo run-time initialization code that would set up the
  15.   program registers  and environment.   Secondly,  a  Turbo TSR (Terminate
  16.   and stay-resident) could not ordinarily issue file I/O since that would
  17.   clobber Dos interrupt registers.
  18.  
  19.   Therefore,  the following code proposes an inline solution, recovering the
  20.   Turbo entry  stack  for  "stay-resident" programs  and allowing those
  21.   programs to issue Dos I/O and other interrupts.
  22.  
  23.   This Turbo stay-resident demo has been put together to perform both Dos I/O
  24.   and Bios interrupts. It has been tested for re-entrancy and recursiveness
  25.   on an IBM PC with PCDOS 2.0, 2.1, 3.0, 3.1 .
  26.  
  27.   R_U_N   I_N_S_T_R_U_C_T_I_O_N_S
  28.   Separate the include files, compile to a COM file using STAYRES.410 (or the
  29.   current release level) as the  Main file. Then execute the command file
  30.   from the DOS prompt.
  31.  
  32.   Use the Turbo Compiler Options window to set the Maximum free dynamic
  33.   memory  between 300-400 paragraphs. If you get $FF runtine errors or
  34.   "allocation error", "cannot load Command.Com", then adjust the mAximum free
  35.   value to something reasonable but less than your maximum memory (minus
  36.   20K). This program can ONLY run as a COM file.
  37.  
  38.    Activate with the default hotkey (Alt-F9).  Stayres will also free its
  39.    memory and return to Dos with the Cntl-F9 key at the last "Press a key"
  40.    prompt (Illustrated in the Stayxit routine).
  41.  
  42.  
  43.                                                  The Hunter's Helper
  44.  
  45.                                                   Lane Ferris
  46.                                                   4268 26th St
  47.                                                   San Francisco,Ca. 94131
  48.                                                   Compuserv 70357,2716
  49.  
  50.  If you find this program useful, $15 will aid in its evolution and upkeep.
  51.  
  52. }
  53. { Authors: Lane  Ferris   (Stay Resident/Exit Code)         }
  54. {          Neil J. Rubenking (Directory code and ideas)     }
  55. {          Karson W. Morrison (Stay Resident modifications) }
  56. {          Lynn A. Canning (Windo coding revisions)         }
  57. {          Bela Lubkin (INT24 processing)                   }
  58. {          Other Public Gurus on whose shoulders we stand.  }
  59. {
  60.  PURPOSE:
  61.        This code will serve as a template to create other "Stay  Resident"
  62.        programs  in  Turbo  Pascal(tm).   This  code  intercepts  Int  16,
  63.        (or INT 9) displacing the original Interrupt Vector  to a Turbo inline
  64.        service procecure. During  execution  of  other  programs,  it  can be
  65.        invoked by the special key combination  specified  by  "Our_HotKey"
  66.        (in  this  case Alt-F9.) }
  67.  
  68. {
  69.  Modifications:
  70.           7.85 - Replace Windows with a more simple form/less code.
  71.                     Replace Window Array with Pointers/Heap form.
  72.                     Re-issue termination Keyboard Read / pass back to user
  73.                     Would like to back up Instruction Ptr by two bytes before
  74.                     the Int 16 ($CD16) but it might be a "long call" by
  75.                     some other Kbd interceptor (chirp chirp chrip)... and
  76.                     thats "trouble in River City".
  77.                     Clean up RmWin "incorrect" attribute bugs. If screen
  78.                     isnt cleared, we get border attribute, not text attrb.
  79.                     Remove last window at Termination Time (Ctrl-Home).
  80.           8.85 - Version 3.10 Changes
  81.                     1) Save 40 words in StaySave/Rstr to avoid clobbering
  82.                        Dos Stack when entering Dos with Turbo Write(ln) caused
  83.                        by Int 21 Function 5  (Writln(Lst,..)) which re-issues
  84.                        Int 16.
  85.                     2) Change Int 68 to Int 67 to Avoid collisions with
  86.                        Dos 3.1 on an AT.
  87.                     3) Correct "Press a Key..." to accept any "Key..."
  88.                        (not just Cr).
  89.                     4) Check Int16 function. Jmp directly to Int16 if not
  90.                        a character request. Avoids 40 word Save/Restore
  91.                        overhead.
  92.           9.85 - Version 3.20 changes
  93.                     When returning to user program, pass back a fake
  94.                     "Ctrl-key" scan code to allow immediate re-execution
  95.                     of the TSR (Terminate Stay Resident) program. Also
  96.                     solves SideKick incessant bird caws.
  97.           9.85 - Version 3.2C
  98.                     When saving/restoring the stack, save 40 words or less
  99.                     depending on stack size (0-Sp = stack size) to avoid
  100.                     overflowing into SS:0 when stack is less than 40 words.
  101.                     Put back the "wait for user key logic" at Demo end.
  102.                     Beep like SuperKick if Key is OurKey
  103.           9.85   Version 3.31
  104.                     Futz around with the "wait for user key logic", allow
  105.                     the Our_key to pass, but beep user to show we aint
  106.                     gonna activate, cuz our InUse bit is still set.
  107.                     Clean up the documentation and duplicate instructions in
  108.                     StaySave/Rstr.
  109.                     Change Int67 to Int60 for Fun and Profit and get around
  110.                     Mark Stanock's use of those locations.
  111.           9.85   Version 3.32
  112.                     Changes made by Karson W. Morrison
  113.                     Modified the STAYRES.331 version to remove all coding
  114.                     that was not necessary for the stayres routines.
  115.                     The coding associated with the demo was put into
  116.                     seperate include files.  The coding for a revised windo.inc
  117.                     file was placed into the stayres program.  The windo
  118.                     routines were changes to allow background and forground
  119.                     colors and to allow borders of one line, two lines, or
  120.                     no lines.  Read the doc info. in the windo.inc file.
  121.                     Revisions for the windo.inc file were made by
  122.                     Lynn A. Canning.  The windo routine will now allow a
  123.                     window of 1,1,80,25.
  124.          10.85   Version 3.33     l.ferris
  125.                     Correct inverted parameters in Stay Windo include file
  126.                     Delete unused variables and code in demo code.
  127.                     Rename files to keep with Version/Release/Modification
  128.                     numbering scheme.
  129.                     Remove necessity for using User Interrupt locations in
  130.                     low storage. Use Far calls to original interrupt.
  131.                     Change Alt-F10 to Alt-F9 to avoid common conflicts.
  132.                     Change Cntl-Home to Cntl-F9 keys to avoid common conflicts.
  133.          12.85    Version 3.40   l.ferris
  134.                     Clean up Window errors, add 3rd window options. Correct
  135.                     Alpa/Beta errors. Say Thanks to Neil once again.
  136.           4.86    Version 4.00
  137.                     Rewrite stay-resident interface. Avoid manipulating
  138.                     DOS or Users interrupted stack.
  139.                     Intercepts Interrupts 9, 8, 13, 21, 28
  140.           6.86      Replace INT 9 processing with an INT 16 equivalent.
  141.                     Works better with mutitasking environments. Leave
  142.                     INT 9 as an option.
  143.                   Version 4.10
  144.                     Addition of Neil RubenKing's Clock Demonstration.
  145.                     Great work Neil. Thanks! Corrections from beta tests.
  146.                     Documentation cleanup.
  147.                     Enable interrupts within INT21 service routine.
  148. }
  149. Program Stay_Resident;
  150.  
  151. { * * * * * * * CONSTANTS * * * * * * * * * * * * * * * * * * * * * * }
  152.   const
  153. {      the next field is needed for the windo.inc routines }
  154.     MaxWin          = 2;       { Max number of windows open at one time }
  155.     Esc             = #27;     {character equivalent of Escape Key}
  156.     Alt_F9          = #112;    {Alt Function 9 Scan code        }
  157.     Ctrl_F9         = #229;    {Ctl-F9 (#102+127)  Key  code    }
  158.     Quit_Key        = Ctrl_F9; {Quit and Release Memory}
  159.  
  160.     Alt             = 08;      {Shift bits at 40:17 }
  161.     Ctrl            = 04;
  162.     Left_Shift      = 02;
  163.     Rght_Shift      = 01;
  164.  
  165.     BIOSI8          = 8;       {Bios Timer interrupt}
  166.     BIOSI16         = $16;     {Bios Keyboard interrupt}
  167.     BIOSI13         = $13;     {Bios Disk interrupt}
  168.     DOSI21          = $21;     {DOS service router interrupt}
  169.     DOSI28          = $28;     {DOS Idle interrupt}
  170. {------------- T Y P E    D E C L A R A T I O N S ----------------------}
  171.   Type
  172.     Regtype     = record Ax,Bx,Cx,Dx,Bp,Si,Di,Ds,Es,Flags:integer  end;
  173.     HalfRegtype = record Al,Ah,Bl,Bh,Cl,Ch,Dl,Dh:byte              end;
  174.     filename_type = string[64];
  175.     Vector   = record             { Interrupt Vector type   }
  176.        IP,CS :integer ;
  177.           end ;
  178.  
  179. {-------------- T Y P E D   C O N S T A N T S --------------------------}
  180.   Const
  181.  
  182.     Our_HotKey   : byte = 112; { scan code for Alt-F9}
  183.  
  184.       { This table marks those INT 21 functions which must be passed     }
  185.       { without modification. They either never return, fetch parameters }
  186.       { from the stack, or may be interrupted by a TSR                   }
  187.  
  188.       Functab    : array[0..$6F] of byte =
  189.                    (1,1,1,1, 1,1,1,1, 1,1,1,1, 1,0,0,0,  {0-C}
  190.                     0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
  191.                     0,0,0,0, 0,0,1,0, 0,0,0,0, 0,0,0,1,  {26,2F}
  192.                     0,1,1,1, 1,1,0,0, 0,0,0,0, 0,0,0,0,  {31-35}
  193.                     0,0,0,0, 0,0,0,0, 1,1,1,1, 1,1,0,0,  {48-4D}
  194.                     1,1,1,1, 0,1,0,0, 1,0,0,0, 0,1,1,1,  {50-53,55,58,5D-5F}
  195.                     1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1); {60-62}
  196.  
  197.       Intr_Flags : byte = 0;           {Active interrupts flags}
  198.          INT13_on  =  04;               {Disk  interrupt is active}
  199.          INT21_on  =  08;               {DOS Service router is active}
  200.       Status     : byte = 0;           {Status of current TSR activity}
  201.          Hotkey_on =  01;               {Received the HotKey}
  202.          Inuse     =  02;               {TSR is active}
  203.          Foxs      = $FF;               {workaround for inline hex FF}
  204.       DosVersion : byte = 0;           {Current Version of DOS}
  205.       WaitCount  : byte = 0;           {Wait to activate count}
  206.       UserProgram :integer = 0;        {Offset to Users Program Code}
  207.  
  208.       OurDSeg: integer = 0;            {Turbo Data Segment Value  }
  209.       OurSSeg: integer = 0;            {Turbo Stack Segment Value   }
  210.  
  211.       DosDSeg: integer = 0;            {Dos Datasegment value     }
  212.       DosSSeg: integer = 0;            {Dos Stack Segment Value   }
  213.       DosSPtr: integer = 0;            {Dos Stack pointer value   }
  214.       OurPSP : integer = 0;
  215.  
  216.  
  217.     { The following  constants *MUST* remain in the IP:CS order.   }
  218.     { StaySave uses them as  JMP targets                           }
  219.  
  220.       BIOS_INT8   : vector = (IP:0;CS:0);  {BIOS Timer Interrupt Vector }
  221.       BIOS_INT16  : vector = (IP:0;CS:0);  {BIOS Keyboard Interrupt Vector }
  222.       BIOS_INT13  : vector = (IP:0;CS:0);  {BIOS Disk Interrupt Vector    }
  223.       DOS_INT21   : vector = (IP:0;CS:0);  {DOS Sevice Interrupt Vector}
  224.       DOS_INT28   : vector = (IP:0;CS:0);  {DOS idle Service interrupt Vector}
  225.       DOSStat1    : vector = (IP:0;CS:0);  {Pointer to INDOS byte}
  226.       DOSStat2    : vector = (IP:0;CS:0);  {Pointer to CRITICAL byte}
  227.  
  228.       Version  :string[4] = '4.10';      { Current Version number }
  229.  
  230.  {-------------- V A R I A B L E S ----------------------------------------}
  231.     Var
  232.  
  233.       Regs       : regtype;
  234.       HalfRegs   : halfregtype absolute regs;
  235.       Keychr     : char ;
  236.       Bytecount  : integer;
  237.  
  238.       SavedPSP   : integer;          { Program Segment Prefix pointers }
  239.       Error      : integer;          { I/O results }
  240.       Good       : boolean;          { I/O results switch }
  241.  
  242.       OurDTA   :Array [1..2] Of integer; {Local DTA pointer}
  243.       SavedDTA :Array [1..2] of integer; {Interrupted DTA pointer}
  244.  
  245. {-----------------------------------------------------------------------------}
  246. {                 W  I  N  D  O  W     R  O  U  T  I  N  E                    }
  247. {---------------------------------------------------------------------------- }
  248.  
  249. {$I STAYWNDO.341}
  250.  
  251. {----------------------------------------------------------------------}
  252. {            S  T  A  Y  E  X  I  T                                    }
  253. {----------------------------------------------------------------------}
  254. {$I STAYXIT.410}
  255.  
  256. {*****************************************************************************}
  257. {-----------------------------------------------------------------------------}
  258. {            THE FOLLOWING ARE THE USER INCLUDE ROUTINES                      }
  259. {-----------------------------------------------------------------------------}
  260. {*****************************************************************************}
  261. {$I STAYSUBS.410}
  262. {----------------------------------------------------------------------------}
  263. {                  S T A Y D E M         Demo Routines                       }
  264. {----------------------------------------------------------------------------}
  265. {$I ClkDem.410}
  266.     (* Substitute the following lines for the Clock Demo by Neil Rubenking.
  267.        Comment or remove the $I STAYDEM.... line above
  268.        See additional comment at interrupt 8 inline procedure Stay_INT8.
  269.     {----------------------------------------------------------------------------}
  270.     {                  C L O C K D E M O       Demo Routines                     }
  271.     {----------------------------------------------------------------------------}
  272.     {$I CLKDEM.410}
  273.     *)
  274. {*****************************************************************************}
  275. {-----------------------------------------------------------------------------}
  276. {            THE ABOVE ARE THE USER INCLUDE ROUTINES                          }
  277. {-----------------------------------------------------------------------------}
  278. {*****************************************************************************}
  279.  
  280. {-----------------------------------------------------------------------------}
  281. {              P R O C E S S   I N T E R R U P T                              }
  282. { - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - }
  283.  
  284.  
  285. {  PURPOSE:
  286.       This  procedure  replaces  the  standard  keyboard interrupts.
  287.       If anything but "Our_HotKey" is pressed,  the key is  passed
  288.       to the standard  keyboard service routine.  B_U_T,  when Our
  289.       HotKey is recognized, a hotkey bit is set.
  290.  
  291.       Do not put Variables or Constants in this Procedure. It will
  292.       cause registers to be clobbered during the Interrupt routine
  293.       when Turbo attempts to allocate  storage for local variables
  294.       or parameters.
  295.  
  296. }
  297.  
  298. Procedure STAY_INT16;       {Keyboard Interrupt 16 Service Routine}
  299. Begin
  300. {$I Stayi16.410}
  301. End; {STAY_INT16}
  302.  
  303. Procedure STAY_INT13;       {BIOS Disk interrupt  Routine}
  304. Begin
  305. {$I Stayi13.410}
  306. End; {STAY_INT13}
  307.  
  308. Procedure STAY_INT21;       {DOS interrupt 21 Service Routine}
  309. Begin
  310. {$I Stayi21.410}
  311. End; {STAY_INT21}
  312.  
  313. Procedure Stay_INT8;        {Timer Interrupt 8 Service Routine}
  314. Begin
  315. (* add the following include for the Clock Demonstration by Neil Rubenking
  316.    {$I ClkI8.410}
  317. *)
  318. {$I ClkI8.410}
  319. {$I Stayi8.410}
  320. End;{Stay_Int8}
  321.  
  322. Procedure Stay_INT28;       {Idle Interrupt 28 Service Routine}
  323. Begin
  324. {$I Stayi28.410}
  325. End;{Stay_Int28}
  326.  
  327. Procedure StaySave;         {Prolog to Resident Turbo Code}
  328. Begin
  329. {$I StaySave.410}
  330. {**************************************************************************}
  331. {--------------------------------------------------------------------------}
  332. {                       INVOKE USER PROCEDURE HERE                         }
  333. {--------------------------------------------------------------------------}
  334. {**************************************************************************}
  335.  
  336.    GetDTA(SavedDTA[1],SavedDTA[2]);         {Save callers DTA address}
  337.  
  338.    GetPSP(SavedPSP);                        {Save callers PSP Segment}
  339.    SetPSP(OurPSP);                          {Set our PSP Segment}
  340.  
  341.    SetDTA(OurDTA[1],OurDTA[2]);             {Set our DTA address}
  342.    NewCtlc[2] := CSeg;
  343.       NewCtlc[1] := Ofs(IRET);
  344.    GetCtlC(SavedCtlc); SetCtlC(NewCtlc);    {Get/Save the users Ctrl-C vector}
  345.  
  346.    INT24On;                                 {Trap Dos Critical Errors}
  347.  
  348. {            .
  349.              .
  350.              .  Your
  351.              .      Program
  352.              .             Goes
  353.              .                 Here
  354.              .
  355. }
  356.         Demo ;  {Replace Demo with your procedures}
  357.  
  358. {**************************************************************************}
  359. {--------------------------------------------------------------------------}
  360. {                       END USER PROCEDURE HERE                            }
  361. {--------------------------------------------------------------------------}
  362. {**************************************************************************}
  363.  
  364.    SetPSP(SavedPSP);                   { Restore Callers PSP Segment}
  365.  
  366.    SetDTA(SavedDTA[1],SavedDTA[2]);    { Restore the users DTA}
  367.    SetCtlC(SavedCtlC);                 { Restore the users Ctrl-C Vector}
  368.  
  369.    INT24Off;                           { Remove Our Critical Error routine}
  370.  
  371. {---------------------------------------------------------------------------}
  372. {             BEGINNING OF THE STAYRSTR ROUTINE                             }
  373. {---------------------------------------------------------------------------}
  374. {$I Stayrstr.410}      { RETURN TO CALLER }
  375. {---------------------------------------------------------------------------}
  376. {            END OF THE STAYRSTR ROUTINE                                    }
  377. {---------------------------------------------------------------------------}
  378.  
  379. End ;{StaySave}
  380.  
  381. {-------------------------------------------------------------------------}
  382. {                             M  A  I  N                                  }
  383. {-------------------------------------------------------------------------}
  384.           { The main program installs the new interrupt routine }
  385.           { and makes it permanently resident as the keyboard   }
  386.           { interrupt.  The old keyboard interrupt Vector is    }
  387.           { stored in Variables , so they can be used in Far    }
  388.           { Calls.                                              }
  389.           {                                                     }
  390.           { The following dos calls are used:                   }
  391.           { Function 25 - Install interrupt address             }
  392.           {               input al = int number,                }
  393.           {               ds:dx = address to install            }
  394.           { Function 35 - get interrupt address                 }
  395.           {               input al = int number                 }
  396.           {               output es:bx = address in interrupt   }
  397.           { Function 31 - terminate and stay resident           }
  398.           {               input dx = size of resident program   }
  399.           {               obtained from the memory              }
  400.           {               allocation block at [Cs:0 - $10 + 3]  }
  401.           { Function 49 - Free Allocated Memory                 }
  402.           {               input Es = Block Segment to free      }
  403.           {-----------------------------------------------------}
  404. Begin                                  {**main**}
  405.  
  406.   Writeln('Turbo Stayres Version ',Version,' initializing.');
  407.  
  408.   OurDseg:= Dseg;           { Save the Data Segment Address for Interrupts }
  409.   OurSseg:= Sseg;           { Save our Stack Segment for Interrupts        }
  410.   GetPSP(OurPSP);           { Local PSP Segment             }
  411.  
  412.  
  413.   GetDTA(OurDTA[1],OurDTA[2]); { Record our DTA address }
  414.  
  415.   UserProgram:=Ofs(Staysave); {Set target of call instruction}
  416.  
  417.  
  418.            { Initialize Your Progam Here since you wont get   }
  419.            { control again until the HotKey  is entered from  }
  420.            { the Keyboard.                                    }
  421.  
  422.       Regs.Ax := $3000 ;            {Obtain the DOS Version number}
  423.       Intr(DosI21,Regs);
  424.       DosVersion := Halfregs.Al;    { 0=1+, 2=2.0+, 3=3.0+ }
  425.  
  426.                                     {Obtain the DOS Indos status location}
  427.         Regs.Ax := $3400;
  428.         Intr(DosI21,Regs);
  429.         DosStat1.IP  := Regs.BX;
  430.         DosStat1.CS  := Regs.ES;
  431.         DosStat2.CS  := Regs.ES;
  432.  
  433.  
  434.       Bytecount := 0;                  { Search for INT 28 instruction }
  435.       While (Bytecount < $7000)
  436.          and (Memw[DosStat2.CS:Bytecount] <> $28CD)
  437.             do Bytecount := Succ(Bytecount);
  438.  
  439.       If Bytecount = $7000 then begin   { Couldn't find INT 28 instruction }
  440.          Writeln('StayRes incompatiblity with Operating System');
  441.          Writeln('StayRes will not install correctly..Halting');
  442.          Halt; end;
  443.  
  444.          { Search for the DOS Critical Status Byte address.       }
  445.          { Bytecount contains offset from DosStat1.CS of the      }
  446.          { INT 28 instruction. Critical byte address is somewhere }
  447.          { above that location for different version of DOS.      }
  448.  
  449.       If Memw[DosStat2.CS:Bytecount-7] = $3E80
  450.          then DosStat2.IP := Memw[DosStat2.CS:Bytecount-5];
  451.       If Memw[DosStat2.CS:Bytecount-12] = $06F6
  452.          then DosStat2.IP := Memw[DosStat2.CS:Bytecount-10];
  453.       If DosStat2.IP = 0 then begin
  454.          Writeln('Cannot Find Dos Critical byte...Halting');
  455.          Halt;
  456.          end;
  457.  
  458.   Inline($FA);                           {Disable interrupts}
  459.  
  460.             { Setup Our Keyboard Interrupt Service Routine  }
  461.  
  462.       Regs.Ax := $3500 + BIOSI16;
  463.       Intr(DosI21,Regs);            {get the address of keyboard interrupt }
  464.       BIOS_Int16.IP := Regs.BX;            { Location of DOS Interrupt Ip }
  465.       BIOS_Int16.CS := Regs.Es;            { Location of DOS Interrupt Cs }
  466.  
  467.       Regs.Ax := $2500 + BIOSI16;   { set the keyboard interrupt to point to}
  468.       Regs.Ds := Cseg;              {  "Process-Intr" above}
  469.       Regs.Dx := Ofs(Stay_INT16);
  470.       Intr (DosI21,Regs);
  471.  
  472.             { Setup Our Timer Interrupt Service Routine  }
  473.  
  474.       Regs.Ax := $3500 + BIOSI8;
  475.       Intr(DosI21,Regs);            {get the address of Timer interrupt }
  476.       BIOS_Int8.IP := Regs.BX;            { Location of DOS Interrupt Ip }
  477.       BIOS_Int8.CS := Regs.ES;            { Location of DOS Interrupt Cs }
  478.  
  479.       Regs.Ax := $2500 + BIOSI8;
  480.       Regs.Ds := Cseg;
  481.       Regs.Dx := Ofs(Stay_INT8);
  482.       Intr (DosI21,Regs);
  483.  
  484.             { Setup Our Disk Interrupt Service Routine  }
  485.  
  486.       Regs.Ax := $3500 + BIOSI13;
  487.       Intr(DosI21,Regs);            {get the address of Disk interrupt }
  488.       BIOS_Int13.IP := Regs.BX;   { Location of DOS Interrupt Ip }
  489.       BIOS_Int13.CS := Regs.Es;   { Location of DOS Interrupt Cs }
  490.  
  491.       Regs.Ax := $2500 + BIOSI13;
  492.       Regs.Ds := Cseg;
  493.       Regs.Dx := Ofs(Stay_INT13);
  494.       Intr (DosI21,Regs);
  495.  
  496.             { Setup Our DOS 21 Interrupt Service Routine  }
  497.  
  498.       Regs.Ax := $3500 + DOSI21;
  499.       Intr(DosI21,Regs);            {Get address of DOS Router interrupt }
  500.       DOS_Int21.IP := Regs.BX;    { Location of DOS Interrupt Ip }
  501.       DOS_Int21.CS := Regs.Es;    { Location of DOS Interrupt Cs }
  502.  
  503.       Regs.Ax := $2500 + DOSI21;
  504.       Regs.Ds := Cseg;
  505.       Regs.Dx := Ofs(Stay_INT21);
  506.       Intr (DosI21,Regs);
  507.  
  508.         { Setup Our DOS 28 Interrupt Service Routine  }
  509.  
  510.       Regs.Ax := $3500 + DOSI28;
  511.       Intr(DosI21,Regs);         { Get address of Idle interrupt }
  512.       DOS_Int28.IP := Regs.BX;    { Location of DOS Interrupt Ip }
  513.       DOS_Int28.CS := Regs.Es;    { Location of DOS Interrupt Cs }
  514.  
  515.       Regs.Ax := $2500 + DOSI28;
  516.       Regs.Ds := Cseg;
  517.       Regs.Dx := Ofs(Stay_INT28);
  518.       Intr (DosI21,Regs);
  519.  
  520.       Inline($FB);                        {Re-enable interrupts}
  521. {****************************************************************************}
  522. {----------------------------------------------------------------------------}
  523. {                INITIALIZE YOUR PROGRAM HERE                                }
  524. {----------------------------------------------------------------------------}
  525. {****************************************************************************}
  526.       { Initialize Your Progam Here since you wont get control again
  527.         until "Our_HotKey" is entered from the Keyboard.               }
  528.  
  529.       Writeln(' Author: The Hunter''s Helper');
  530.       Writeln('   LaneFerris, Compuserv 70357,2716');
  531.       Writeln('     Alt-F9 activates : Ctrl-F9 deactivates');
  532. {****************************************************************************}
  533. {----------------------------------------------------------------------------}
  534. {               END OF INITALIZE PROGRAM CODE                                }
  535. {----------------------------------------------------------------------------}
  536. {****************************************************************************}
  537. {
  538.       Now terminate and stay resident.   The following Call utilizes the
  539.       new Terminate & Stay Resident function.  We get the amount of
  540.       memory by fetching the memory allocation paragraphs from the Memory
  541.       Control Block.  This was set by Turbo initialization during Int
  542.       21/function 4A (shrink block), calculated from mInimum and mAximum
  543.       options menu. The MCB sits one paragraph above the PSP.
  544.  
  545. }
  546.                                           { Pass return code of zero    }
  547.       Regs.Ax := $3100 ;                  { Terminate and Stay Resident }
  548.       Regs.Dx := MemW [Cseg-1:0003]+1 ;   { Prog_Size from Allocation Blk}
  549.       Write('      Using ',Regs.Dx /64 :4:1,'K');
  550.       Write('  Code:',(Dseg-Cseg)/64 :4:1,'K');
  551.       Write('  Data:',(SSeg-Dseg)/64 :4:1,'K');
  552.       Write('  Heap:',(Cseg+Regs.Dx-SSeg)/64 :4:1,'K');
  553.      Intr (DosI21,Regs);
  554.  
  555.  
  556.        { END OF RESIDENCY CODE }
  557. end.
  558.