home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / INFO / TURBOPAS / TUR6_102.ZIP / STAYRES.340 < prev    next >
Encoding:
Text File  |  1986-02-22  |  22.1 KB  |  408 lines

  1. {$C-}
  2. {-----------------------------------------------------------------------------}
  3. {         "  S o r r y ,  D a v e,   I   C a n ' t   D o   T h a t .  "       }
  4. {                                                          Arthur C. Clark    }
  5. {                                                           " 2 0 0 1 "       }
  6. {-----------------------------------------------------------------------------}
  7. { Stayres Version 3.40 }
  8.  
  9. {  A  Turbo  "stay-resident" program clobbers the Dos register stack.  It
  10.   jumps over the Turbo run-time initialization code that would set up the
  11.   program registers  and environment.   Secondly,  a  stay-resident  program
  12.   could not ordinarily issue file I/O since that would clobber Dos interrupt
  13.   registers.  Therefore,  the following code proposes an inline solution,
  14.   providing a Turbo entry  stack  for  "stay-resident"  programs  and allowing
  15.   those programs to issue Dos I/O and other interrupts.
  16.  
  17.   This Turbo stay-resident demo has been put together to perform both Dos I/O
  18.   and Bios interrupts. It has been tested for re-entrancy and recursiveness
  19.   on an IBM PC with PCDOS 2.1, 3.1 .
  20.  
  21.   R_U_N   I_N_S_T_R_U_C_T_I_O_N_S
  22.   Separate the include files, compile to a COM file using STAYRES.??? as the
  23.   Main file. Then execute the command file and activate with the default
  24.   Alt-F9 key. It will also free its memory and return to Dos with the
  25.   Cntl-F9 key at the last "Press a key" prompt (Illustrated in the Stayxit
  26.   file). Maximum free dynamic memory should be between 300-400 paragraphs
  27.   since this demo uses a recursive stack. If you get $FF runtine errors or
  28.   "allocation error", "cannot load Command.Com", then adjust the mAximum
  29.   free value to something reasonable but less than your maximum memory -
  30.   20K. This program can ONLY run as a COM file.
  31.  
  32.   The use of user interrupt locations in low memory has been removed as of
  33.   Version 3.33.
  34.  
  35.                                                  The Hunter's Helper
  36.  
  37.                                                   Lane Ferris
  38.                                                   4268 26th St
  39.                                                   San Francisco,Ca. 94131
  40.                                                   [ 70357,2716 ]
  41.  
  42.  If you find this program useful, $15 would be appeciated to help in its
  43.  evolution and upkeep.
  44.  
  45. }
  46. {-----------------------------------------------------------------------------}
  47. {     This code has been tested/used on an IBM PC using PC-DOS 2.1/3.1        }
  48. {-----------------------------------------------------------------------------}
  49. { Authors: Lane  Ferris   (Stay Resident/Exit Code)       }
  50. {          Neil J. Rubenking (Directory code and ideas)   }
  51. {          Karson W. Morrison (Stay Resident modifications}
  52. {          Lynn A. Canning (Windo coding revisions)       }
  53. {          Other Public Gurus on whose shoulders we stand.}
  54. {
  55.  PURPOSE:  This code will serve as a template to create other "Stay  Resident"
  56.            programs  in  Turbo  Pascal(tm).   This  code  intercepts  Int  16,
  57.            displacing original Interrupt  16  Vector  to  "Intr_Process" below.
  58.            During  execution  of  other  programs,  it  can  be invoked by the
  59.            special key combination  specified  by  "Our_Char"  (in  this  case
  60.            Alt-F9.)
  61.  
  62.  Modifications:
  63.           7. 7.85 - Replace Windows with a more simple form/less code.
  64.           7. 8.85 - Replace Window Array with Pointers/Heap form.
  65.           7.11.85 - Re-issue termination Keyboard Read / pass back to user
  66.                     Would like to back up Instruction Ptr by two bytes before
  67.                     the Int 16 ($CD16) but it might be a "long call" by
  68.                     some other Kbd interceptor (chirp chirp chrip)... and
  69.                     thats "trouble in River City".
  70.           7.19.85 - Clean up RmWin "incorrect" attribute bugs. If screen
  71.                     isnt cleared, we get border attribute, not text attrb.
  72.                   - Remove last window at Termination Time (Ctrl-Home).
  73.           8.26.85 - Version 3.10 Changes
  74.                     1) Save 40 words in StaySave/Rstr to avoid clobbering
  75.                        Dos Stack when entering Dos with Turbo Write(ln) caused
  76.                        by Int 21 Function 5  (Writln(Lst,..)) which re-issues
  77.                        Int 16.
  78.                     2) Change Int 68 to Int 67 to Avoid collisions with
  79.                        Dos 3.1 on an AT.
  80.                     3) Correct "Press a Key..." to accept any "Key..."
  81.                        (not just Cr).
  82.                     4) Check Int16 function. Jmp directly to Int16 if not
  83.                        a character request. Avoids 40 word Save/Restore
  84.                        overhead.
  85.           9.04.85 - Version 3.20 changes
  86.                     When returning to user program, pass back a fake
  87.                     "Ctrl-key" scan code to allow immediate re-execution
  88.                     of the TSR (Terminate Stay Resident) program. Also
  89.                     solves SideKick incessant bird caws.
  90.           9.18.85 - Version 3.2C
  91.                     When saving/restoring the stack, save 40 words or less
  92.                     depending on stack size (0-Sp = stack size) to avoid
  93.                     overflowing into SS:0 when stack is less than 40 words.
  94.                     Put back the "wait for user key logic" at Demo end.
  95.                     Beep like SuperKick if Key is OurKey
  96.                     Version 3.31
  97.           9.19.85   Futz around with the "wait for user key logic", allow
  98.                     the Our_key to pass, but beep user to show we aint
  99.                     gonna activate, cuz our InUse bit is still set.
  100.                     Clean up the documentation and duplicate instructions in
  101.                     StaySave/Rstr.
  102.                     Change Int67 to Int60 for Fun and Profit and get around
  103.                     Mark Stanock's use of those locations.
  104.           9.29.85   Version 3.32
  105.                     Changes made by Karson W. Morrison
  106.                     Modified the STAYRES.331 version to remove all coding
  107.                     that was not necessary for the stayres routines.
  108.                     The coding associated with the demo was put into
  109.                     seperate include files.  The coding for a revised windo.inc
  110.                     file was placed into the stayres program.  The windo
  111.                     routines were changes to allow background and forground
  112.                     colors and to allow borders of one line, two lines, or
  113.                     no lines.  Read the doc info. in the windo.inc file.
  114.                     Revisions for the windo.inc file were made by
  115.                     Lynn A. Canning.  The windo routine will now allow a
  116.                     window of 1,1,80,25.
  117.          10.30.85   Version 3.33     l.ferris
  118.                     Correct inverted parameters in Stay Windo include file
  119.                     Delete unused variables and code in demo code.
  120.                     Rename files to keep with Version/Release/Modification
  121.                     numbering scheme.
  122.                     Remove necessity for using User Interrupt locations in
  123.                     low storage. Use Far calls to original interrupt.
  124.                     Change Alt-F10 to Alt-F9 to avoid common conflicts.
  125.                     Change Cntl-Home to Cntl-F9 keys to avoid common conflicts.
  126.          12.6.85    Version 3.40   l.ferris
  127.                     Clean up Window errors, add 3rd window options. Correct
  128.                     Alpa/Beta errors. Say Thanks to Neil once again.
  129. }
  130. Program Stay_Resident;
  131.  
  132. { * * * * * * * CONSTANTS * * * * * * * * * * * * * * * * * * * * * * }
  133.   const
  134. {      the next field is needed for the windo.inc routines }
  135.     MaxWin          = 2;       { Max number of windows open at one time }
  136.     Esc             = #27;     {character equivalent of Escape Key}
  137.     Alt_F9          = #112;    {Alt Function 9 Scan code        }
  138.     Ctrl_F9         = #102;    {Control Function 9 Scan code    }
  139.     Ctrl_Home       = #119;    {Control Home Scan Code          }
  140.     Ctrl_End        = #117;    {Control End Scan Code           }
  141.     Kybrd_Int       = $16;     {BIOS keyboard interrupt}
  142.     Our_Char        = 112;     {this is the scan code for Alt-F9}
  143.     Quit_Key        = Ctrl_F9; {Quit and Release Memory}
  144.  
  145. {------------- T Y P E    D E C L A R A T I O N S ----------------------}
  146.   Type
  147.     Regtype     = record Ax,Bx,Cx,Dx,Bp,Si,Di,Ds,Es,Flags:integer  end;
  148.     HalfRegtype = record Al,Ah,Bl,Bh,Cl,Ch,Dl,Dh:byte              end;
  149.     filename_type = string[64];
  150.  
  151. {-------------- T Y P E D   C O N S T A N T S --------------------------}
  152.   Const
  153.    {regs is defined as a typed constant to get it in the code segment}
  154.      Regs : regtype = (Ax:0;Bx:0;Cx:0;Dx:0;Bp:0;Si:0;Di:0;Ds:0;Es:0;Flags:0);
  155.  
  156.       OurDseg: integer = 0;            {Our Data Segment Value             }
  157.       OurSseg: integer = 0;            {Our Stack Segment Value            }
  158.       DosSseg: integer = 0;            {Dos Stack Segment Value            }
  159.       Inuse  : Boolean = false;        {Recursion flag                     }
  160.   { The following two constants *MUST* remain in the IP:CS order        }
  161.   { because StaySave uses them as a JMP target                          }
  162.       DOS_IntIP : integer = 0;        {Pointer to Original IP Int value   }
  163.       DOS_IntCs : integer = 0;        {Pointer to Original Cs Int value   }
  164.       StackSize  : integer = 0;        {Current User/or Dos Stack word size}
  165.  {-------------- V A R I A B L E S ----------------------------------------}
  166.     Var
  167.       SaveRegs                      : regtype;
  168.       HalfRegs                      : halfregtype absolute regs;
  169.       Terminate_flag                : boolean ;
  170.       Keychr                        : char ;
  171.       Old_Xpos,Old_Ypos             : integer ;
  172.       I                             : integer;
  173.  
  174. {-----------------------------------------------------------------------------}
  175. {                 W  I  N  D  O  W     R  O  U  T  I  N  E                    }
  176. {---------------------------------------------------------------------------- }
  177.  
  178. {$I STAYWNDO.340}
  179.  
  180. {-----------------------------------------------------------------------------}
  181. {            S  T  A  Y  E  X  I  T                                           }
  182. {-----------------------------------------------------------------------------}
  183. {$I STAYXIT.340}
  184. {----------------------------------------------------------------------}
  185. {            C a l l    O r i g i n a l    I n t e r r u p t           }
  186. {----------------------------------------------------------------------}
  187. Procedure CallOriginalIntr(Var RegAx: Integer);
  188.                                {Invoke the original DOS interrupt and  }
  189.    Begin                       {Return the value in parameter          }
  190.    inline(
  191.       $B4/$00/                 {Mov Ah,Read function                   }
  192.       $9C/                     {Push Flags                             }
  193.       $2E/$FF/$1E/DOS_IntIP/  {Call Far [DOS_IntIP]                  }
  194.       $C4/$BE/RegAx/           {Les Di,KeyChr[Bp]                      }
  195.       $AB                      {StosW          Stuff in new KeyChr     }
  196.          );
  197.    End; {CallOriginalIntr}
  198. {----------------------------------------------------------------------}
  199. {           K e y i n   :   R e a d  K e a b o a r d                   }
  200. {----------------------------------------------------------------------}
  201. Function Keyin: char;          { Get a key from the Keyboard           }
  202.    Var Ch : char;              { If extended key, fold above 127       }
  203.    Begin                       {---------------------------------------}
  204.       Repeat until Keypressed;
  205.       Read(Kbd,Ch);
  206.       if (Ch = Esc) and KeyPressed then
  207.          Begin
  208.          Read(Kbd,Ch);
  209.          Ch := Char(Ord(Ch) + 127);
  210.          End;
  211.       Keyin := Ch;
  212.    End;  {Keyin}
  213. {----------------------------------------------------------------------}
  214. {          B e e p   :  S o u n d  t h e  H o r n                      }
  215. {----------------------------------------------------------------------}
  216. Procedure Beep(N :integer); {------------------------------------------}
  217.    Begin                    {  This routine sounds a tone of frequency }
  218.       Sound(n);             {  N for approximately 100 ms              }
  219.       Delay(100);           {------------------------------------------}
  220.       Sound(n div 2);
  221.       Delay(100);
  222.       Nosound;
  223.       End {Beep} ;
  224.  
  225. {*****************************************************************************}
  226. {-----------------------------------------------------------------------------}
  227. {            THE FOLLOWING ARE THE USER INCLUDE ROUTINES                      }
  228. {-----------------------------------------------------------------------------}
  229. {*****************************************************************************}
  230.  
  231. {----------------------------------------------------------------------}
  232. {            G  E  T  F  I  L  E                                       }
  233. {----------------------------------------------------------------------}
  234. Procedure Get_file;
  235. {$I STAYSUBS.340}
  236. {$I STAYDEM.340 }
  237.  
  238. {*****************************************************************************}
  239. {-----------------------------------------------------------------------------}
  240. {            THE ABOVE ARE THE USER INCLUDE ROUTINES                          }
  241. {-----------------------------------------------------------------------------}
  242. {*****************************************************************************}
  243.  
  244. {-----------------------------------------------------------------------------}
  245. {              P R O C E S S   I N T E R R U P T                              }
  246. { - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - }
  247. Procedure Process_Intr;
  248.  
  249. {  PURPOSE:  This  procedure  replaces  the  standard  keyboard  interrupt.
  250.       If anything but "Our_Char" is pressed,  the key is  passed  on  to
  251.       the standard  keyboard  interrupt.  B*U*T  when "Our_Char" is pressed,
  252.       this program takes over.  The variable <InUse>  is  set  TRUE  to
  253.       ensure that this code doesn't try to run "on top of itself " AND to
  254.       indicate  to the Inline code to save/restore the original interrupt
  255.       regs.
  256. }
  257.            { Do not put Variables or Contants in this Procedure.}
  258.            { It will cause registers to be clobbered during the }
  259.            { Interrupt routine when Turbo attempts to allocate  }
  260.            { storage for local variables or parameters.         }
  261.  
  262. Begin
  263.           { K e y b o a r d    Interrupt   o c c u r s   here }
  264. {----------------------------------------------------------------------}
  265. {           START OF STAYSAVE ROUTINE                                  }
  266. {----------------------------------------------------------------------}
  267. {$I StaySave.340}
  268. {---------------------------------------------------------------------------}
  269. {           END OF THE STAYSAVE REGISTER ROUTINE                            }
  270. {---------------------------------------------------------------------------}
  271.            {    Int 16 request function in Ah reg:         }
  272.            {       0 = read character from Keyboard        }
  273.            {       1 = check character available           }
  274.            {       2 = check shift key values              }
  275.  
  276.            { HalfRegs.Ah = Our_Char because StaySave  }
  277.            { doesnt enter here unless it is!          }
  278.  
  279.      If  (not InUse) then               { Must be OUR key and NOT busy  }
  280.         Begin { Demo }
  281.         InUse := true;                  { "dont clobber saved stack"}
  282.  
  283. {**************************************************************************}
  284. {--------------------------------------------------------------------------}
  285. {                       INVOKE USER PROCEDURE HERE                         }
  286. {--------------------------------------------------------------------------}
  287. {**************************************************************************}
  288. {            .
  289.              .
  290.              .  Your
  291.              .      Program
  292.              .             Goes
  293.              .                 Here
  294.              .
  295. }
  296.         Demo ;
  297.  
  298. {
  299. {
  300.         For I := 1 to 10 do
  301.         Writeln(Lst,'That''s all Folks');  }
  302.                       { Test Printer Output if you like }
  303.  
  304. {**************************************************************************}
  305. {--------------------------------------------------------------------------}
  306. {                       END USER PROCEDURE HERE                            }
  307. {--------------------------------------------------------------------------}
  308. {**************************************************************************}
  309.         { Because INUSE is still TRUE, the next read will pass  }
  310.         { back OurChar, if you press it, to the interrupted pgm.}
  311.         { We'll beep for the time being. Mr Pavlov would love it}
  312.  
  313.         CallOriginalIntr(Regs.Ax);      { Get input key for the users     }
  314.          If HalfRegs.Ah = Ord(Our_Char) then Beep(650);
  315.  
  316.         InUse := false;                  { ok to restore interrupted stack }
  317.         End;  { Demo }
  318. {---------------------------------------------------------------------------}
  319. {             BEGINNING OF THE STAYRSTR ROUTINE                             }
  320. {---------------------------------------------------------------------------}
  321. {$I StayRstr.340 }      { RETURN TO CALLER }
  322. {---------------------------------------------------------------------------}
  323. {            END OF THE STAYRSTR ROUTINE                                    }
  324. {---------------------------------------------------------------------------}
  325.  
  326. End ;{Process_Intr}
  327.  
  328. {-------------------------------------------------------------------------}
  329. {                             M  A  I  N                                  }
  330. {-------------------------------------------------------------------------}
  331.           { The main program installs the new interrupt routine }
  332.           { and makes it permanently resident as the keyboard   }
  333.           { interrupt.  The old keyboard interrupt Vector is    }
  334.           { stored in Variables Dos_IntCS and IP, so it can     }
  335.           { be used in Far Calls.                               }
  336.           {                                                     }
  337.           { The following dos calls are used:                   }
  338.           { Function 25 - Install interrupt address             }
  339.           {               input al = int number,                }
  340.           {               ds:dx = address to install            }
  341.           { Function 35 - get interrupt address                 }
  342.           {               input al = int number                 }
  343.           {               output es:bx = address in interrupt   }
  344.           { Function 31 - terminate and stay resident           }
  345.           {               input dx = size of resident program   }
  346.           {               obtained from the memory              }
  347.           {               allocation block at [Cs:0 - $10 + 3]  }
  348.           { Function 49 - Free Allocated Memory                 }
  349.           {               input Es = Block Segment to free      }
  350.           { Interrupt 20 - Return to invoking process           }
  351.           {-----------------------------------------------------}
  352. Begin                                  {**main**}
  353.  
  354.   InUse  := false;          { Turn off the Inuse flag in case we do a write}
  355.   OurDseg:= Dseg;           { Save the Data Segment Address for Interrupts }
  356.   OurSseg:= Sseg;           { Save our Stack Segment for Interrupts        }
  357.  
  358.  
  359.   Terminate_Flag := false;  { Havent received a Kill key yet   }
  360.   SaveRegs.Es := 00;        { Clear for Dos 3.0 bug            }
  361.                             { now install the interrupt routine}
  362.  
  363.            { Initialize Your Progam Here since you wont get }
  364.            { control again until "Our_Char" is entered from }
  365.            { the Keyboard.                                  }
  366.  
  367.       SaveRegs.Ax := $3500 + Kybrd_Int;
  368.       Intr($21,SaveRegs);            {get the address of keyboard interrupt }
  369.  
  370.       DOS_IntIp := SaveRegs.BX;            { Location of DOS Interrupt Ip }
  371.       DOS_IntCs := SaveRegs.Es;            { Location of DOS Interrupt Cs }
  372.  
  373.       SaveRegs.Ax := $2500 + Kybrd_Int;
  374.       SaveRegs.Ds := Cseg;
  375.       SaveRegs.Dx := Ofs(Process_Intr);
  376.       Intr ($21,SaveRegs);        { set the keyboard interrupt to point to
  377.                                   "Process-Intr" above}
  378.  
  379.  
  380. {****************************************************************************}
  381. {----------------------------------------------------------------------------}
  382. {                INITIALIZE YOUR PROGRAM HERE                                }
  383. {----------------------------------------------------------------------------}
  384. {****************************************************************************}
  385.       { Initialize Your Progam Here since you wont get control again
  386.         until "Our_Char" is entered from the Keyboard.               }
  387.  
  388.       Writeln(' Turbo Stay-Resident Demo(3.40): Press Alt-F9');
  389.  
  390. {****************************************************************************}
  391. {----------------------------------------------------------------------------}
  392. {               END OF INITALIZE PROGRAM CODE                                }
  393. {----------------------------------------------------------------------------}
  394. {****************************************************************************}
  395.   { Now terminate and stay resident The following Call utilizes the new     }
  396.   { Terminate & Stay Resident function by passing the program allocation    }
  397.   { set in the Memory Control Block when Turbo prolog issued Int 21/function}
  398.   { 4A (shrink block), calculated from mInimum and mAximum options menu.    }
  399.   { The MCB sits one paragraph above the PSP.                               }
  400.                                               { Pass return code of zero    }
  401.       SaveRegs.Ax := $3100 ;                  { Terminate and Stay Resident }
  402.       SaveRegs.Dx := MemW [Cseg-1:0003] ;     { Prog_Size from Allocation Blk}
  403.       Intr ($21,SaveRegs);
  404.  
  405.  
  406.        { END OF RESIDENCY CODE }
  407. end.
  408.