home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / lan / spy / source / tsr.doc < prev    next >
Text File  |  1989-10-03  |  11KB  |  230 lines

  1. {$A+,B-,D-,E-,F+,I-,L-,N-,O-,R-,S-,V+}
  2. Unit Tsr;
  3. { TSR.PAS - Terminate and Stay Resident background processing for Turbo Pascal,
  4.   Version 5.  This unit and its associated object file support unrestricted
  5.   background processes written in Pascal.  This unit requires DOS 3.1 or later.
  6.   You must use the $M compiler directive in the main program or the
  7.   SetFreeHeap procedure (see below) to limit the memory occupied by the TSR
  8.   before calling BeginTSR.  The default heap max limit of 640k will cause a
  9.   DOS crash immediately after the TSR is goes resident.
  10.  
  11.   See TSRDEMO.PAS for example use.
  12.  
  13.   For more comprehensive TSR support oriented toward pop-up utilities, please
  14.   refer to TPTSR by Turbo Power Software (ask on CompuServ BORPRO), and the
  15.   TESSERACT project (ask on CompuServ, CLM332).
  16.  
  17.   Copyright 1989 by Edwin T. Floyd
  18.   All rights reserved.
  19.   Non-commercial use Ok.
  20.   Use at your own risk.
  21.  
  22.   Author:  Edwin T. Floyd [76067,747]
  23.            #9 Adams Park Court
  24.            Columbus, GA 31909
  25.            (404) 322-0076 }
  26.  
  27. Interface
  28.  
  29. Type
  30.   TsrRoutineType = Procedure;
  31.  
  32.   KeyControlType = Record
  33.     CharCode : Char; { Character from BIOS status }
  34.     ScanCode : Byte; { Scan code from BIOS status }
  35.     FuncCode : Byte; { Function request to BIOS }
  36.     Action : (KeyUnavailable, KeySubstitute, KeyInsert, KeyFlush);
  37.   End;
  38.  
  39.   KeyRoutineType = Procedure(Var Key : KeyControlType);
  40.   { If KeyReq then KeyRoutine is called each time a BIOS Int 16h function
  41.     (00h, 01h, 10h, 11h) is requested and the current keystroke (if any) has
  42.     not been examined by KeyRoutine before.  On entry, Action=KeyUnavailable
  43.     indicates no keystroke is waiting to process, CharCode and ScanCode are
  44.     invalid; Action=KeySubstitute indicates a keystroke is waiting.
  45.     Regardless of the value of FuncCode on entry, once KeyRoutine has set or
  46.     defaulted Action=KeySubstitute or KeyInsert, KeyRoutine will not be
  47.     called again until after the keystroke has been passed to the application
  48.     via a BIOS GetKey function (00h or 10h). }
  49.  
  50. Var
  51.   BackReq : Boolean; { If False, no background }
  52.   TickReq : Boolean; { If False, no clock tick call }
  53.   KeyReq : Boolean;  { If False, no keyboard routine call }
  54.   Emul87 : Boolean;  { If True, 80x87 emulation interrupts are swapped }
  55.   Real87 : Boolean;  { If True, 80x87 registers are swapped }
  56.   ReleaseEMS : Boolean; { If True, Overlay EMS is released on exit }
  57.   { Set ReleaseEMS := True if OvrInitEMS is successful }
  58.  
  59. Procedure BeginTSR(Background : TsrRoutineType; Code : Word);
  60.   { Set up interrupts, Terminate and Stay Resident with exit code. If
  61.   successful, this procedure will not return.  "Background" specifies the
  62.   procedure to be executed in background.  Background may use any standard
  63.   Turbo Pascal facility, including DOS files, overlays and 80x87 (real or
  64.   emulated).  When the Background procedure returns, the TSR is stopped.
  65.   Background should return control periodically to the foreground process by
  66.   calling TsrWait (see below). }
  67.  
  68. Procedure RemoveTSR;
  69.   { Call from Background to remove the TSR from memory at the next opportunity.
  70.   If BeginTSR has been called, this routine will not return and Background will
  71.   not receive control again.  Call RemoveTSR ONLY from Background, not from
  72.   and interrupt handler. }
  73.  
  74. Procedure TsrWait(Ticks : Word);
  75.   { Return control to foreground process.  Background is continued at the
  76.   next opportunity after "Ticks" timer ticks (55ms each) with the instruction
  77.   following the call to TsrWait.  Call this procedure ONLY from Background, not
  78.   from an interrupt handler. }
  79.  
  80. Procedure WakeBackground;
  81.   { Prematurely expire the TsrWait "Ticks" timer and set BackReq := True.  The
  82.   background process will be continued at the next opportunity.  WakeBackground
  83.   is safe to call from an interrupt handler. }
  84.  
  85. Function CallBackground : Boolean;
  86.   { Use this from an interrupt handler to attempt to return control to the
  87.   background routine.  Background will receive control if DOS is safe and
  88.   the TsrWait time has expired (BackReq is ignored).  CallBackground returns
  89.   TRUE if background received control.  CallBackground can sometimes improve
  90.   performance by restarting background without waiting for the next Int 28h
  91.   or Int 8h clock tick.  CallBackground returns immediately if control could
  92.   not be returned to background, otherwise CallBackground does not return until
  93.   background calls TsrWait. }
  94.  
  95. Procedure SetTickRoutine(TickProc : TsrRoutineType);
  96.   { Establish a timer tick routine.  TickProc receives control with interrupts
  97.   disabled, once each clock tick (55ms) as long as TickReq is TRUE.  DOS is NOT
  98.   safe inside TickProc; TickProc should be used only to inc/dec counters or set
  99.   flags.  TickProc should be compiled with stack and error checking disabled
  100.   ($S-,R-).  SetTickRoutine is safe to call from an interrupt handler. }
  101.  
  102. Procedure SetKeyRoutine(KeyProc : KeyRoutineType);
  103.   { Establish a keystroke filter routine (see above).  DOS is NOT safe inside
  104.   KeyProc either.  KeyProc should be compiled with stack and error checking
  105.   disabled ($S-,R-).  SetKeyRoutine is safe to call from an interrupt
  106.   handler. }
  107.  
  108. Function TsrActive : Boolean;
  109.   { Returns TRUE if BeginTSR has been called successfully.  (You may not know
  110.   inside an ExitProc for instance.)  TsrActive is safe to call from an
  111.   interrupt handler. }
  112.  
  113. Function IoResult : Integer;
  114.   { Shell for System IoResult function which gets critical error info from TSR
  115.   intercept. }
  116.  
  117. Function CheckLoaded(Var Check : String) : Pointer;
  118.   { Scans DOS Memory Control Blocks from low memory to high and returns the
  119.    address of the first string that matches Check at the same offset from the
  120.    beginning of a memory block as Check is from PrefixSeg.  For a simple "I'm
  121.    already loaded" check: Declare a typed constant check string unique to your
  122.    TSR, then, If CheckLoaded(ChkStr) <> @ChkStr Then <I'm already loaded>.
  123.    If you wish to communicate with the previously loaded TSR, you may follow
  124.    the check string with data or procedure pointers and address them with the
  125.    pointer returned by CheckLoaded. }
  126.  
  127. { Use the following procedures to optimize the use of memory }
  128.  
  129. Function ProgramSize : LongInt;
  130.   { Returns the current size of the program block in bytes.  This function
  131.   is safe to call from an interrupt handler (why would you want to?) }
  132.  
  133. Function DosFreeSpace : LongInt;
  134.   { Returns the amount of free DOS memory immediately following the program
  135.   block.  Call this function only from background, not from an interrupt
  136.   handler. }
  137.  
  138. Procedure SetFreeHeap(BytesFree : LongInt);
  139.   { Changes the size of the free space at the end of the heap using DOS
  140.   function $4A to modify the memory block allocated to the program.  The
  141.   heap may be expanded by no more than DosFreeSpace bytes.  Setting heap
  142.   freespace to zero may make it impossible to Dispose/FreeMem because the
  143.   freespace table has nowhere to expand.  Suggestion: Do as much heap
  144.   allocation as possible before going resident, then, just before calling
  145.   BeginTSR, call SetFreeHeap(<some small number>).  This will minimize
  146.   the space the program occupies in memory.  SetFreeHeap may be called
  147.   after the program is resident, but there is no way to predict how much
  148.   (if any) DosFreeSpace will be available to make the heap larger.  Call
  149.   this procedure only from background, not from an interrupt handler. }
  150.  
  151. { The following macros may be useful for interrupt handlers. }
  152.  
  153. Procedure DisableInterrupts;
  154.   { Disable 80x86/8 interrupts }
  155. Inline($FA);
  156.  
  157. Procedure EnableInterrupts;
  158. { Enable 80x86/8 interrupts }
  159. Inline($FB);
  160.  
  161. Procedure ChainToInterrupt(IntAddr : Pointer);
  162. Inline(
  163. { Chain to interrupt from Pascal interrupt handler }
  164.   $5B/     { pop bx; get interrupt address in ax:bx }
  165.   $58/     { pop ax }
  166.   $87/$5E/$0E/ { xchg [bp+$0E],bx; exchange interrupt address with old ax:bx }
  167.   $87/$46/$10/ { xchg [bp+$10],ax }
  168.   $89/$EC/ { mov sp,bp }
  169.   $FF/$76/$16/ { push [bp+$16]; restore flags }
  170.   $9D/     { popf }
  171.   $5D/     { pop bp; do most of the normal interrupt exit }
  172.   $07/     { pop es }
  173.   $1F/     { pop ds }
  174.   $5F/     { pop di }
  175.   $5E/     { pop si }
  176.   $5A/     { pop dx }
  177.   $59/     { pop cx }
  178.   $FA/     { cli; no interrupts }
  179.   $CB);    { retf; bx/ax already restored, return thru old isr address }
  180.  
  181. Procedure CallInterrupt(IntAddr : Pointer);
  182. Inline(
  183. { Call interrupt from Pascal interrupt handler. Uses original registers from }
  184. { stack and returns updated registers to stack }
  185.   $5B/                   {    pop bx    ; save parameter}
  186.   $59/                   {    pop cx}
  187.   $E8/$00/$00/           {    call x1   ; get IP}
  188.   $58/                   {x1: pop ax}
  189.   $05/$2C/$00/           {    add ax,(x2-x1)  ; add offset to return}
  190.   $1E/                   {    push ds   ; save ds}
  191.   $55/                   {    push bp   ; and bp}
  192.   $FF/$76/$16/           {    push [bp+$16]   ; get original flags}
  193.   $9D/                   {    popf}
  194.   $9C/                   {    pushf     ; push flags...}
  195.   $0E/                   {    push cs   ; and our return address...}
  196.   $50/                   {    push ax   ; so we look like an INT}
  197.   $51/                   {    push cx   ; restore parameter (int ep)}
  198.   $53/                   {    push bx}
  199.   $8B/$46/$10/           {    mov ax,[bp+$10] ; restore original regs}
  200.   $8B/$5E/$0E/           {    mov bx,[bp+$0E]}
  201.   $8B/$4E/$0C/           {    mov cx,[bp+$0C]}
  202.   $8B/$56/$0A/           {    mov dx,[bp+$0A]}
  203.   $8B/$76/$08/           {    mov si,[bp+$08]}
  204.   $8B/$7E/$06/           {    mov di,[bp+$06]}
  205.   $8E/$5E/$04/           {    mov ds,[bp+$04]}
  206.   $8E/$46/$02/           {    mov es,[bp+$02]}
  207.   $8B/$6E/$00/           {    mov bp,[bp+$00]}
  208.   $FA/                   {    cli             ; enter interrupt disabled}
  209.   $CB/                   {    retf            ; call interrupt via stack}
  210.   $9C/                   {x2: pushf           ; save int flags}
  211.   $55/                   {    push bp         ; save int bp}
  212.   $89/$E5/               {    mov bp,sp       ; restore our bp}
  213.   $87/$6E/$04/           {    xchg bp,[bp+$04]}
  214.   $89/$46/$10/           {    mov [bp+$10],ax ; save int regs}
  215.   $89/$5E/$0E/           {    mov [bp+$0E],bx}
  216.   $89/$4E/$0C/           {    mov [bp+$0C],cx}
  217.   $89/$56/$0A/           {    mov [bp+$0A],dx}
  218.   $89/$76/$08/           {    mov [bp+$08],si}
  219.   $89/$7E/$06/           {    mov [bp+$06],di}
  220.   $8C/$5E/$04/           {    mov [bp+$04],ds}
  221.   $8C/$46/$02/           {    mov [bp+$02],es}
  222.   $58/                   {    pop ax    ; save int. bp}
  223.   $89/$46/$00/           {    mov [bp+$00],ax}
  224.   $58/                   {    pop ax    ; save int. flags}
  225.   $89/$46/$16/           {    mov [bp+$16],ax ; save}
  226.   $58/                   {    pop ax    ; was our bp, discard}
  227.   $1F);                  {    pop ds    ; restore our ds}
  228.  
  229. Implementation
  230.