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

ID: Q28568


The information in this article applies to:
  • Microsoft C for MS-DOS, versions 5.1, 6.0, 6.0a, 6.0ax
  • Microsoft C/C++ for MS-DOS, version 7.0
  • Microsoft Visual C++ for Windows, versions 1.0, 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 query words: kbinf 1.00 1.50 5.10 6.00 6.00a 6.00ax 7.00

Keywords : kb16bitonly
Version : :1.0,1.5,5.1,6.0,6.0a,6.0ax; MS-DOS:7.0
Platform : MS-DOS
Issue type :


Last Reviewed: January 3, 2000
© 2000 Microsoft Corporation. All rights reserved. Terms of Use.