Terminate-and-Stay-Resident (TSR) Program Example

Last reviewed: July 17, 1997
Article ID: Q28568
5.10 6.00 6.00a 6.00ax 7.00 | 1.00 1.50
MS-DOS                      | WINDOWS
kbprg

The information in this article applies to:

  • Microsoft C for MS-DOS, versions 5.1, 6.0, 6.0a, and 6.0ax
  • Microsoft C/C++ for MS-DOS, version 7.0
  • Microsoft Visual C++ for Windows, versions 1.0 and 1.5

SUMMARY

The following code example demonstrates using Microsoft C to write a terminate-and-stay-resident (TSR) program. The example also demonstrates using the following functions in the C run-time library:

   _dos_setvect
   _dos_getvect
   _dos_keep
   _chain_intr
   spawnXXX

MORE INFORMATION

DIRZAP.MAK

DIRZAP.OBJ:     DIRZAP.C
          CL -AM -c DIRZAP.C
          LINK DIRZAP.OBJ;

DIRZAP.H

/********************************************************************/
/*                                                                  */
/*                            DirZap.h                              */
/*                                                                  */
/*        This header file defines a global variable, macros,       */
/*        function pointers, and function prototypes needed         */
/*        in the DirZap.c program.                                  */
/*                                                                  */
/*                                                                  */
/********************************************************************/

/* Global Variable For Macro SHIFTL(x, n) */
long _ADDRESS;

/* Macro Definitions */
#define INT5  0x5
#define INT21 0x21
#define SHIFTL(x, n) (_ADDRESS = 0L, _ADDRESS = (long)(x), _ADDRESS << (n))
#define HIBYTE(x) (((unsigned)(x) >> 8) & 0xff)
#define REGPAK unsigned es, unsigned ds, unsigned di, unsigned si,\
               unsigned bp, unsigned sp, unsigned bx, unsigned dx,\
               unsigned cx, unsigned ax, unsigned ip, unsigned  cs,\
               unsigned flags

/* Function Pointers */
void (interrupt far *save_dir_adr)();
/* Saves address of the original interrupt service routine */

void (interrupt far *set_dir_adr)();
/* This function pointer gets set to the address of the new
   interrupt service routine 'set_dir' */

void (interrupt far *reset_dir_adr)();
/* This function pointer gets set to the address of the new
   interrupt service routine 'reset_dir' */

/* Function Declarations */
void cdecl interrupt far set_dir(REGPAK);
/* This is the new service routine which zaps the directory
   interrupt routines. */

void interrupt far reset_dir(void);
/* This routine toggles between setting and disabling the
   directory interrupt routines */

unsigned _get_memsize(void);
/* This function gets the number of bytes to keep resident */

short _set_shell(void);
/* Sets a DOS shell. */

DIRZAP.C

/*******************************************************************/
/*                                                                 */
/*                        DirZap.c                                 */
/*                                                                 */
/*  This is an illustration of a Terminate-and-Stay-Resident       */
/*  program. It traps and disables the directory interrupts for    */
/*  MkDir, RmDir, and ChDir.  When DirZap is in memory you can     */
/*  toggle it on and off with the PrintScreen key.  When it is     */
/*  on you will not be able to change directories or make or       */
/*  remove any directories.                                        */
/*  The PrintScreen key and directories have nothing to do with    */
/*  TSR programming.  They were just randomly picked to create     */
/*  an application.  This program is not intended to be a complete */
/*  application.  It's intent is to demonstrate how to write a     */
/*  TSR.  You can take the concept used here and incorporate it    */
/*  in to your own program.                                        */
/*  Below is a summary of what this program does :                 */
/*   - Save the address of INT 21                                  */
/*   - Revector INT 21 to a routine that disables the directory    */
/*     operations.                                                 */
/*   - Revector the PrintScreen interrupt to a routine that will   */
/*     toggle DirZap on and off.                                   */
/*   - Execute a _dos_keep to make the program resident            */
/*                                                                 */
/*                                                                 */
/*   Copyright (c) Microsoft Corp 1988. All rights reserved.       */
/*                                                                 */
/*  To run:                                                        */
/*          1) Type DirZap at dos prompt                           */
/*          2) The PRINT SCREEN key now toggles                    */
/*             DirZap on and off but no memory                     */
/*             is freed.                                           */
/*                                                                 */
/*******************************************************************/
/* NOTE:                                                           */
/*                                                                 */
/* THIS PROGRAM, ITS USE, OPERATION AND SUPPORT IS PROVIDED "AS IS"*/
/* WITHOUT WARRANTY OF ANY  KIND, EITHER EXPRESSED OR IMPLIED,     */
/* INCLUDING, BUT  NOT LIMITED TO, THE IMPLIED WARRANTIES OF        */
/* MERCHANTABILITY AND FITNESS FOR  A PARTICULAR PURPOSE.          */
/* THE ENTIRE RISK  AS TO THE QUALITY AND  PERFORMANCE OF THIS     */
/* PROGRAM IS WITH THE USER. IN NO EVENT SHALL MICROSOFT BE LIABLE */
/* FOR ANY DAMAGES  INCLUDING, WITHOUT LIMITATION,  ANY LOST       */
/* PROFITS,  LOST SAVINGS OR OTHER INCIDENTAL OR CONSEQUENTIAL     */
/* DAMAGES ARISING THE USE OR INABILITY TO USE SUCH PROGRAM, EVEN  */
/* IF MICROSOFT HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES*/
/* OR FOR ANY CLAIM BY ANY OTHER PARTY.                            */
/*******************************************************************/

#include <dos.h>
#include <stdio.h>
#include <stdlib.h>
#include <process.h>
#include "dirzap.h"

extern unsigned _psp;           /* _psp = segment address of PSP   */
unsigned far    *psp_pointer;   /* To retrieve the memsize to stay */
                                /* resident                        */
short           hot_key=1;      /* To toggle dirzap on and off     */

void main(void)
{

      /***************************************/
      /*                                     */
      /* Revector the directory interrupts   */
      /*                                     */
      /***************************************/
      save_dir_adr = _dos_getvect(INT21); /* Save original address  */
      set_dir_adr  = set_dir;            /* Get addr of new routine */

      /***************************************/
      /*                                     */
      /* Revector the PRINT SCREEN interrupt */
      /*                                     */
      /***************************************/
      reset_dir_adr = reset_dir;          /* Get addr of new routine*/
      _dos_setvect (INT5, reset_dir_adr); /* Revector to new routine*/


      /***************************************/
      /*                                     */
      /*      Become memory resident.        */
      /*                                     */
      /***************************************/
      _dos_keep(0, _get_memsize());

      printf ("DirZap is now memory resident");  /* Inform the user */

}

void cdecl interrupt far set_dir(REGPAK)
{
/********************************************************************/
/*                                                                  */
/*  DS:DX points to the string entered by the user for MkDir, RmDir */
/*  and ChDir.  This function makes that string null so that        */
/*  the user will no longer be able to make, remove, or change      */
/*  directories.                                                    */
/*  WARNING: When compiled at high warning levels, several warnings */
/*  are generated. This is because several elements of REGPAK are   */
/*  not referenced. These warnings should be ignored.               */
/*                                                                  */
/********************************************************************/

   if (HIBYTE(ax) == 0x39 || HIBYTE(ax) == 0x3A || HIBYTE(ax) == 0x3B)
      dx=0;
   _chain_intr(save_dir_adr);
}

void interrupt far reset_dir()
{
   /****************************************************************/
   /*                                                              */
   /*  This function is used to toggle DirZap on and off.          */
   /*                                                              */
   /****************************************************************/

   if (hot_key)
   {
      hot_key=0;
      _dos_setvect(INT21, save_dir_adr);  /* Reset initial vector  */
   }
   else
   {
      hot_key=1;
      _dos_setvect(INT21, set_dir_adr);   /* Install DirZap again  */
      _chain_intr(set_dir_adr);    /* Chain to the Zapper function */
   }
}

unsigned _get_memsize() {
   psp_pointer = (int far *) SHIFTL(_psp, 16); /* Get segment of the*/
                                               /* PSP               */
   return(psp_pointer[1] - _psp);            /* Amount of memory to */
                                             /* stay resident       */
}


Additional reference words: kbinf 1.00 1.50 5.10 6.00 6.00a 6.00ax 7.00
KBCategory: kbprg
KBSubcategory: PrgTSR
Keywords : kb16bitonly


THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT APPLY.

Last reviewed: July 17, 1997
© 1998 Microsoft Corporation. All rights reserved. Terms of Use.