home *** CD-ROM | disk | FTP | other *** search
- Code from "Converting a Turbo C Program to a TSR' by Michael J.
- Young, PJ, Volume 6.2. Copyright 1987 Michael J. Young.
-
- Listing 1
-
- #pragma inline
-
- #include <dos.h>
- #include "tsr.h"
-
- static unsigned int TCSS; /* Turbo C stack segment. */
- static unsigned int TCSP; /* Turbo C stack pointer. */
- static void (*UserRtn) (void); /* Pointer to user's start routine. */
- static int HotKeyMask; /* Hot key shift mask. */
- static unsigned int TCDtaSeg; /* Turbo C Disk Transfer Area segment. */
- static unsigned int TCDtaOff; /* Turbo C Disk Transfer Area offset. */
- static char far *InDosPtr; /* Pointer to DOS 'indos' flag. */
- static void interrupt (*OldInt28) (void); /* Old int 28h vector. */
- static void interrupt (*OldInt13) (void); /* Old int 13h vector. */
- static void interrupt (*OldInt9) (void); /* Old int 09h vector. */
- static void interrupt NewInt28 (void); /* New int 28h handler. */
- /* New int 13h handler: */
- static void interrupt NewInt13 (unsigned BP, unsigned DI, unsigned SI,
- unsigned DS, unsigned ES, unsigned DX,
- unsigned CX, unsigned BX, unsigned AX,
- unsigned IP, unsigned CS, unsigned FLAGS);
- static void interrupt NewInt9 (void); /* New int 09h handler. */
- static int GetShift (void); /* Returns BIOS shift status flag. */
- static int Busy = 0; /* Flag indicates TSR is active. */
- static void Activate (void); /* Routine to activate user's TSR. */
- static int InBios = 0; /* Flag indicating BIOS disk activity. */
- extern void far *_heapbase; /* Defined by Turbo C; holds break addr.*/
-
- int TsrInstall (void (*FPtr) (void),int HotKey,VIFP Code)
- /*
- This routine terminates the C program, but leaves the code resident in
- memory. It installs interrupt handlers so that when the shift key
- combination specified by 'HotKey' is pressed, the function pointed to
- by 'FPtr' receives control, provided that conditions are safe.
- */
- {
- unsigned int i;
- int Found = 0;
-
- for (i=0x60;i<=0x67;++i) /* Search 'user' interrupt vectors */
- if (getvect (i) == Code) /* to see if Code is present */
- { /* indicating that the TSR is */
- Found = 1; /* already installed. */
- break;
- }
- if (Found) /* Already installed, therefore */
- return (INSTALLED); /* return error message. */
- for (i=0x60;i<=0x67;++i) /* Not already installed, therefore */
- if (getvect (i) == (VIFP)0) /* search for a free (==0) user */
- { /* interrupt vector. */
- setvect (i,Code); /* Found a free vector; therefore */
- Found = 1; /* place special code in vector. */
- break;
- }
- if (!Found) /* No free vectors; therefore */
- return (NOINT); /* return error code. */
-
- if (_osmajor < 2) /* Test that OS version is >= 2.0. */
- return (WRONGDOS); /* Wrong DOS version. */
-
- TCSS = _SS; /* Save Turbo C stack segment. */
- TCSP = _BP; /* Save Turbo C stack pointer. */
- HotKeyMask = HotKey; /* Save hotkey shift mask. */
- UserRtn = FPtr; /* Save address of the routine that is activated */
- /* when the hotkey is pressed. */
- _AH = 0x2f; /* Save old Disk Transfer Address. */
- geninterrupt (0x21); /* Invoke MS-DOS function to get */
- TCDtaSeg = _ES; /* current Disk Transfer Address. */
- TCDtaOff = _BX;
-
- _AH = 0x34; /* Get pointer to 'indos' flag using*/
- geninterrupt (0x21); /* the undocumented function 34h. */
- InDosPtr = MK_FP (_ES,_BX);
-
- OldInt28 = getvect (0x28); /* Save old interrupt vectors. */
- OldInt13 = getvect (0x13);
- OldInt9 = getvect (0x9);
-
- setvect (0x28,NewInt28); /* Initialize new interrupt vectors.*/
- setvect (0x13,NewInt13);
- setvect (0x9,NewInt9);
-
- keep (0, FP_SEG (_heapbase)-_psp); /* Terminate and stay resident. */
-
- return (ERROR); /* 'keep' should not return, */
- /* therefore something has gone */
- /* wrong. Return general error code*/
- } /* end TsrInstall */
-
-
- static void interrupt NewInt28 (void)
- /*
- This is the new interrupt 28, the 'DOS idle interrupt', handler.
- */
- {
- (*OldInt28) (); /* Chain to previous interrupt 28 handler. */
- disable (); /* Disable interrupts to test and set */
- if (Busy) /* 'Busy' semaphore. */
- return;
- Busy = 1;
- enable (); /* Re-enable interrupts. */
- if ((GetShift () & HotKeyMask) != HotKeyMask) /* Test if hot key */
- { /* is pressed. */
- Busy = 0;
- return;
- }
- if (InBios) /* Test if BIOS disk services is active. */
- {
- Busy = 0;
- return;
- }
- Activate (); /* Conditions are safe, therefore activate TSR*/
- Busy = 0; /* Reset the active semaphore. */
- return;
-
- } /* end NewInt28 */
-
-
- static void interrupt NewInt13 ( unsigned BP, unsigned DI, unsigned SI,
- unsigned DS, unsigned ES, unsigned DX,
- unsigned CX, unsigned BX, unsigned AX,
- unsigned IP, unsigned CS, unsigned FLAGS)
- /*
- This is the new interrupt 13, BIOS disk services, handler. This
- function serves only to set a flag while BIOS interrupt 13h is active.
- */
- {
- ++InBios; /* Set flag. */
- (*OldInt13) (); /* Chain to old interrupt 13h handler. */
- --InBios; /* Reset flag. */
- AX = _AX; /* Must pass on the information returned by */
- asm pushf /* the BIOS in AX and flag registers. */
- asm pop FLAGS
-
- } /* end NewInt13 */
-
-
- static void interrupt NewInt9 (void)
- /*
- This is the new handler for interrupt 09, the hardware interrupt
- activated by the keyboard.
- */
- {
- (*OldInt9) (); /* Chain to prior interrupt 09 handler. */
- disable (); /* Disable interrupts to test and set 'Busy' */
- if (Busy) /* semaphore. */
- return;
- Busy = 1;
- enable (); /* Enable interrupts. */
- if ((GetShift () & HotKeyMask) != HotKeyMask) /* Test if hot key */
- { /* is pressed. */
- Busy = 0;
- return;
- }
- if (InBios || *InDosPtr) /* Test if EITHER DOS or the BIOS disk */
- { /* services are active. */
- Busy = 0;
- return;
- }
- Activate (); /* Conditions are safe, therefore activate TSR*/
- Busy = 0; /* Reset the active semaphore. */
- return;
-
- } /* end NewInt9 */
-
-
- static unsigned int OldSS;
- static unsigned int OldSP;
- static unsigned int OldPsp;
- static unsigned int OldDtaSeg;
- static unsigned int OldDtaOff;
-
- static void Activate (void)
- /*
- This function is called either by 'NewInt9' or by 'NewInt29', when
- conditions are safe, to activate the user's TSR entry routine.
- */
- {
- register int DSSave; /* Temporary storage for C data segment. */
-
- OldSS = _SS; /* Switch to Turbo C's own stack. */
- OldSP = _SP;
- _SS = TCSS;
- _SP = TCSP;
-
- _AH = 0x2f; /* Save old Disk Transfer Address. */
- geninterrupt (0x21);
- OldDtaSeg = _ES;
- OldDtaOff = _BX;
-
- _DX = TCDtaOff; /* Set Turbo C Disk Transfer Address*/
- DSSave = _DS;
- _DS = TCDtaSeg;
- _AH = 0x1a; /* DOS set DTA service. */
- geninterrupt (0x21);
- _DS = DSSave;
-
- if (!*InDosPtr) /* Save the old PSP and set the PSP */
- { /* to the Turbo C value, using the */
- _AH = 0x51; /* undocumented functions 51h and */
- geninterrupt (0x21); /* 50h. Note that this procedure */
- OldPsp = _BX; /* is safe only if DOS is not */
- _BX = _psp; /* active. */
- _AH = 0x50;
- geninterrupt (0x21);
- }
-
- (*UserRtn) (); /* Call the user's Turbo C function.*/
-
- if (!*InDosPtr) /* Restore the PSP, if DOS is not */
- { /* active. */
- _BX = OldPsp;
- _AH = 0x50;
- geninterrupt (0x21);
- }
-
- _DX = OldDtaOff; /* Restore Old Disk Transfer Address*/
- DSSave = _DS;
- _DS = OldDtaSeg;
- _AH = 0x1a;
- geninterrupt (0x21);
- _DS = DSSave;
-
- _SS = OldSS; /* Restore the old stack. */
- _SP = OldSP;
- return;
-
- } /* end Activate */
-
-
- int TsrInDos ()
- /*
- This function returns zero if DOS is not currently active, and a
- non-zero value otherwise.
- */
- {
- return (*InDosPtr); /* Uses the 'indos' flag maintained by DOS. */
-
- } /* end TsrInDos */
-
-
- int GetShift ()
- /*
- This function returns the BIOS shift status word.
- */
- {
- return *((int far *)0x00400017);
-
- } /* end GetShift */
-
-