home *** CD-ROM | disk | FTP | other *** search
- /*
- TSREXAMP.C
- by Raymond J. Michels
- with revisions by Tim Paterson
- and Andrew Schulman
- */
-
- #include <stddef.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <conio.h>
- #include <dos.h>
- #include <bios.h>
- #include "tsr.h"
-
- #define STACK_SIZE 8192 /* must be 16 byte boundaray */
- #define SET_DTA 0x1a /* SET Disk Transfer Address */
- #define GET_DTA 0x2f /* GET Disk Transfer Address */
-
- #define DOS_EXIT 0x4C /* DOS terminate (exit) */
-
- #define KEYBOARD_PORT 0x60 /* KEYBOARD Data Port */
-
- #define PSP_TERMINATE 0x0A /* Termination addr. in our PSP */
- #define PSP_PARENT_PSP 0x16 /* Parent's PSP from our PSP */
- #define PSP_ENV_ADDR 0x2c /* environment address from PSP */
-
- #define HOT_KEY 32 /* Hot Key along with ALT (D)*/
-
- #define RIGHT_SHIFT 1
- #define LEFT_SHIFT 2
- #define CTRL_KEY 4
- #define ALT_KEY 8
-
- #define MULTIPLEX_ID 0xC0
- #define INSTALL_CHECK 0x00
- #define INSTALLED 0xFF
- #define DEINSTALL 0x01
-
- #define PARAGRAPHS(x) ((FP_OFF(x) + 15) >> 4)
-
- unsigned char multiplex_id = MULTIPLEX_ID;
- char far *stack_ptr; /* pointer to TSR stack */
- unsigned ss_save; /* slot for stack segment register */
- unsigned sp_save; /* slot for stack pointer register */
- int tsr_already_active = 0; /* true if TSR active */
- int popup_while_dos_busy = 0; /* true if hot key hit while dos busy */
- int int_28_in_progress = 0; /* true if INT 28 in progress */
- int unsafe_flag = 0; /* true if INT 13 in progress */
- unsigned keycode;
- unsigned foreground_psp; /* PSP of process we've interrupted */
- unsigned foreground_dta_seg; /* DTA of process we've interrupted */
- unsigned foreground_dta_off;
- char buf[20]; /* work buffer */
- unsigned long TerminateAddr; /* used during de-install */
- union REGS regs; /* register work structures */
- struct SREGS sregs;
- struct ExtErr ErrInfo; /* save area for extended error info */
- int hot_key; /* keycode for activation */
- int shift_key; /* shift status bits (alt, ctrl..) */
- int user_key_set = 0;
-
- /* Save areas for old interrupt pointers */
- INTVECT old_int8, old_int9, old_int10, old_int13, old_int1b, old_int23;
- INTVECT old_int24, old_int28, old_int2f;
-
- #ifdef DOS_SWAP
- extern int dos_critical; /* used by DOSSWAP.C */
- INTVECT old_int2a;
- void interrupt far new_int2a(INTERRUPT_REGS);
- #endif
-
- /* PROTOTYPES FOR THIS MODULE */
- void interrupt far new_int8(INTERRUPT_REGS);
- void interrupt far new_int9(INTERRUPT_REGS);
- extern void interrupt far new_int13(void); /* in TSRUTIL.ASM */
- void interrupt far new_int1b(INTERRUPT_REGS);
- void interrupt far new_int23(INTERRUPT_REGS);
- void interrupt far new_int24(INTERRUPT_REGS);
- void interrupt far new_int28(INTERRUPT_REGS);
- void interrupt far new_int2f(INTERRUPT_REGS);
- void tsr_function(void);
- void tsr_exit(void);
- void usage(char *);
- int UnlinkVect(int Vect, INTVECT NewInt, INTVECT OldInt);
- void parse_cmd_line(int argc, char *argv[]);
- void main(int argc,char *argv[]);
-
- /*********
- * TIMER INTERRUPT HANDLER
- *********/
- void interrupt far new_int8(INTERRUPT_REGS r)
- {
- #ifdef DOS_SWAP
- if (!tsr_already_active && popup_while_dos_busy &&
- !dos_critical && !unsafe_flag)
- #else
- if (!tsr_already_active && popup_while_dos_busy &&
- !DosBusy() && !unsafe_flag)
- #endif
- {
- popup_while_dos_busy = 0;
- tsr_already_active = 1;
- (*old_int8)(); /* process timer tick */
- _enable(); /* turn interrupts back on */
- tsr_function();
- tsr_already_active = 0;
- }
- else
- (*old_int8)(); /* process timer tick */
- }
-
- /**********
- * KEYBOARD INTERRUPT HANDLER
- **********/
- void interrupt far new_int9(INTERRUPT_REGS r)
- {
- if (! tsr_already_active)
- {
- if ((keycode = inp(KEYBOARD_PORT)) != hot_key)
- _chain_intr(old_int9);
-
- if ((_bios_keybrd(_KEYBRD_SHIFTSTATUS) &
- shift_key) == shift_key)
- {
- #ifdef USES_DISK
- if (!unsafe_flag)
- {
- #endif
- popup_while_dos_busy = 0;
- tsr_already_active = 1;
- (*old_int9)(); /* send key to old int routine */
- tsr_function();
- tsr_already_active = 0;
-
- #ifdef USES_DISK
- }
- else
- {
- popup_while_dos_busy = 1;
- _chain_intr(old_int9);
- }
- #endif
- }
- else
- _chain_intr(old_int9);
- }
- else
- _chain_intr(old_int9);
- }
-
- /*********
- * CTRL-BREAK INTERRUPT HANDLER
- *********/
- void interrupt far new_int1b(INTERRUPT_REGS r)
- {
- /* do nothing */
- }
-
- /**********
- * CTRL-C INTERRUPT HANDLER
- **********/
- void interrupt far new_int23(INTERRUPT_REGS r)
- {
- /* do nothing */
- }
-
- /**********
- * CRTITICAL ERROR INTERRUPT HANDLER
- **********/
- void interrupt far new_int24(INTERRUPT_REGS r)
- {
- if (_osmajor >= 3)
- r.ax = 3; /* fail dos function */
- else
- r.ax = 0;
- }
-
- /**********
- * DOS IDLE INTERRUPT HANDLER
- **********/
- void interrupt far new_int28(INTERRUPT_REGS r)
- {
- int_28_in_progress++;
-
- #ifdef DOS_SWAP
- if (popup_while_dos_busy && !dos_critical
- && !tsr_already_active && !unsafe_flag)
- #else
- if (popup_while_dos_busy && (!Int28DosBusy())
- && !tsr_already_active && !unsafe_flag)
- #endif
- {
- tsr_already_active = 1;
- tsr_function();
- tsr_already_active = 0;
- }
-
- int_28_in_progress--;
- _chain_intr(old_int28);
- }
-
- #ifdef DOS_SWAP
- /*********
- * DOS INTERNAL INTERRUPT HANDLER
- *********/
- void interrupt far new_int2a(INTERRUPT_REGS r)
- {
- switch (r.ax & 0xff00)
- {
- case 0x8000: /* start critical section */
- dos_critical++;
- break;
- case 0x8100: /* end critical section */
- case 0x8200: /* end critical section */
- if (dos_critical) /* don't go negative */
- dos_critical--;
- break;
- default:
- break;
- }
- _chain_intr(old_int2a);
- }
- #endif
-
- /*********
- * DOS MULTIPLEX INTERRUPT HANDLER
- *********/
- void interrupt far new_int2f(INTERRUPT_REGS r)
- {
- unsigned ah = r.ax >> 8;
- unsigned al = r.ax & 0xFF;
-
- if (ah == multiplex_id)
- {
- if (al == INSTALL_CHECK)
- r.ax |= INSTALLED;
- else if (al == DEINSTALL)
- {
- // because of stack swap, pass arg in static variable.
- TerminateAddr = ((long)r.bx << 16) + r.dx;
- if (! tsr_already_active) /* don't exit if we're active */
- {
- _enable(); /* STI */
- tsr_exit();
- // If we got here, we weren't able to unlink
- r.ax = 0xFFFF; //let caller know we're still there
- // MSC 6.0 /Ox optimizes the above instruction away
- // get it back by using the value in ax
- tsr_already_active = -r.ax;
- // set to 1 to prevent any more action
- }
- }
- }
- else
- _chain_intr(old_int2f);
- }
-
- /**********
- * TSR ACTIVE SECTION
- **********/
- void tsr_function()
- {
- set_stack();
-
- #ifdef DOS_SWAP
- if (SaveDosSwap() && !int_28_in_progress)
- #else
- if (DosBusy() && !int_28_in_progress)
- #endif
- popup_while_dos_busy = 1; /* set flag: next INT 8,28 activates us */
- else
- {
- popup_while_dos_busy = 0;
-
- /* save old interrupt-CTRL-BREAK, CTRL-C and CRIT ERROR */
- old_int1b = _dos_getvect(0x1b);
- old_int23 = _dos_getvect(0x23);
- old_int24 = _dos_getvect(0x24);
-
- /* set our interrupts functions */
- _dos_setvect(0x1b, new_int1b);
- _dos_setvect(0x23, new_int23);
- _dos_setvect(0x24, new_int24);
-
- /* save current PSP and set to ours */
- /* not needed for DOSSWAP, but can be used by application */
- foreground_psp = GetPSP();
-
- SetPSP(_psp); // _psp in STDLIB.H
-
- #ifndef DOS_SWAP
- /* get foreground DTA */
- regs.h.ah = GET_DTA;
- intdosx(®s, ®s, &sregs);
- foreground_dta_seg = sregs.es;
- foreground_dta_off = regs.x.bx;
- #endif
-
- /* set up our DTA */
- regs.h.ah = SET_DTA;
- regs.x.dx = 0x80; /* use default in PSP area */
- sregs.ds = _psp;
- intdosx(®s, ®s, &sregs);
-
- #ifndef DOS_SWAP
- /* Get Extended Error Information */
- GetExtErr(&ErrInfo);
- #endif
-
- /* suck up key(s) in buffer */
- while (_bios_keybrd(_KEYBRD_READY))
- _bios_keybrd(_KEYBRD_READ);
-
- /* your code goes here */
- application();
-
- #ifdef DOS_SWAP
- RestoreDosSwap();
- #else
- /* put back extended error information */
- SetExtErr(&ErrInfo);
-
- /* put back original DTA */
- regs.h.ah = SET_DTA;
- regs.x.dx = foreground_dta_off;
- sregs.ds = foreground_dta_seg;
- intdosx(®s, ®s, &sregs);
-
- /* put back original PSP */
- SetPSP(foreground_psp);
- #endif
-
- /* put back original INTS */
- _dos_setvect(0x1b, old_int1b);
- _dos_setvect(0x23, old_int23);
- _dos_setvect(0x24, old_int24);
- }
-
- restore_stack();
- }
-
- // only restores OldInt if someone hasn't grabbed away Vect
- int UnlinkVect(int Vect, INTVECT NewInt, INTVECT OldInt)
- {
- if (NewInt == _dos_getvect(Vect))
- {
- _dos_setvect(Vect, OldInt);
- return 0;
- }
- return 1;
- }
-
- void tsr_exit(void)
- {
- set_stack();
- /* put interrupts back the way they were, if possible */
-
- if (!(UnlinkVect(8, new_int8, old_int8) |
- UnlinkVect(9, new_int9, old_int9) | // Do not use ||, we
- UnlinkVect(0x28, new_int28, old_int28) | // don't want early out
- UnlinkVect(0x13, new_int13, old_int13) |
- #ifdef DOS_SWAP
- UnlinkVect(0x2a, new_int2a, old_int2a) |
- #endif
- UnlinkVect(0x2f, new_int2f, old_int2f) ))
- {
- // Set parent PSP, stored in our own PSP, to the current PSP
- *(int far *)(((long)_psp << 16) + PSP_PARENT_PSP) = GetPSP();
-
- // Set terminate address in our PSP
- *(long far *)(((long)_psp << 16) + PSP_TERMINATE) = TerminateAddr;
-
- /* set psp to be ours */
- SetPSP(_psp);
-
- /* exit program */
- bdos(DOS_EXIT, 0, 0);
- }
- restore_stack();
- }
-
- void usage(char *progname)
- {
- fputs("Usage: ", stdout);
- puts(progname);
- puts(" [-d to deinstall] [-k keycode shift-status] [-f multiplex id]");
- puts(" Valid multiplex id");
- puts(" 00 through 15 specifies a unique INT 2F ID");
- puts(" Valid shift-status is any combination of:");
- puts(" 1 = Right Shift");
- puts(" 2 = Left Shift");
- puts(" 4 = CTRL");
- puts(" 8 = ALT");
- exit(1);
- }
-
- void do_deinstall(char *progname)
- {
- fputs(progname, stdout);
- switch (deinstall())
- {
- case 1:
- puts(" was not installed");
- break;
- case 2:
- puts(" deinstalled");
- break;
- default:
- puts(" deactivated but not removed");
- break;
- }
- exit(0);
- }
-
- int set_shift_key(unsigned sh)
- {
- /* figure out, report on shift statuses */
- /* make sure shift key < 0x10 and non-zero */
- if (((shift_key = sh) < 0x10) && shift_key)
- {
- printf("Activation: %s%s%s%sSCAN=%d\n",
- shift_key & RIGHT_SHIFT ? "RIGHT " : "",
- shift_key & LEFT_SHIFT ? "LEFT " : "",
- shift_key & CTRL_KEY ? "CTRL " : "",
- shift_key & ALT_KEY ? "ALT " : "",
- hot_key);
- return 1;
- }
- else /* error, bad param */
- {
- puts("Invalid Shift-Status");
- return 0;
- }
- }
-
- void parse_cmd_line(int argc, char *argv[])
- {
- int i;
- int tmp;
-
- for (i = 1; i < argc; i++) /* for each cmdline arg */
- if ((argv[i][0] == '-') || (argv[i][0] == '/'))
- switch(toupper(argv[i][1]))
- {
- case 'D':
- do_deinstall(argv[0]);
- break;
- case 'K': /* set pop-up key sequence */
- user_key_set = 1;
- i++; /* bump to next argument */
- if ((hot_key = atoi(argv[i])) != 0)
- {
- i++; /* bump to next argument */
- if (! set_shift_key(atoi(argv[i])))
- usage(argv[0]);
- }
- else
- usage(argv[0]);
- break;
- case 'F': /* set multiplex ID */
- i++; /* bump to next argument */
- if ((tmp = atoi(argv[i])) < 0x10)
- multiplex_id += tmp; /* range of C0-CF */
- else
- usage(argv[0]);
- break;
- default: /* invalid argument */
- usage(argv[0]);
- } /* end switch */
- else
- usage(argv[0]);
- }
-
- void main(int argc,char *argv[])
- {
- union REGS regs;
- struct SREGS sregs;
- unsigned far *fp;
- unsigned memtop;
- unsigned dummy;
-
- InitInDos();
-
- parse_cmd_line(argc,argv);
-
- /* check if TSR already installed! */
- regs.h.ah = multiplex_id;
- regs.h.al = INSTALL_CHECK;
- int86(0x2f, ®s, ®s);
- if (regs.h.al == INSTALLED)
- {
- puts("TSR already installed");
- fputs(argv[0], stdout); puts(" -D de-installs");
- exit(1);
- }
-
- if (! user_key_set)
- {
- puts("Press ALT-D to activate TSR ");
- printf("Multiplex ID = %0x \n",multiplex_id);
- hot_key = HOT_KEY;
- shift_key = ALT_KEY;
- }
-
- #ifdef DOS_SWAP
- if (InitDosSwap() != 0)
- {
- puts("Error initializing DOS Swappable Data Area");
- exit(1);
- }
- #endif
-
- /* MALLOC a stack for our TSR section */
- stack_ptr = malloc(STACK_SIZE);
- stack_ptr += STACK_SIZE;
-
- /* get interrupt vector */
- old_int8 = _dos_getvect(8); /* timer interrupt */
- old_int9 = _dos_getvect(9); /* keyboard interrupt */
- old_int13 = _dos_getvect(0x13); /* disk intr, in TSRUTIL.ASM */
- old_int28 = _dos_getvect(0x28); /* dos idle */
- old_int2f = _dos_getvect(0x2f); /* multiplex int */
-
- #ifdef DOS_SWAP
- old_int2a = _dos_getvect(0x2a); /* dos internal int */
- #endif
-
- init_intr(); /* initilize int routines in TSRUTIL.ASM */
-
- /* set interrupts to our routines */
- _dos_setvect(8, new_int8);
- _dos_setvect(9, new_int9);
- _dos_setvect(0x13, new_int13); /* in TSRUTIL.ASM */
- _dos_setvect(0x28, new_int28);
- _dos_setvect(0x2f, new_int2f);
-
- #ifdef DOS_SWAP
- _dos_setvect(0x2a, new_int2a);
- #endif
-
- /* release environment back to MS-DOS */
- FP_SEG(fp) = _psp;
- FP_OFF(fp) = PSP_ENV_ADDR;
- _dos_freemem(*fp);
-
- /* release unused heap to MS-DOS */
- /* All MALLOCS for TSR section must be done in TSR_INIT() */
- /* calculate top of memory, shrink block, and go TSR */
- segread(&sregs);
- memtop = sregs.ds + PARAGRAPHS(stack_ptr) - _psp;
-
- _dos_setblock(memtop, _psp, &dummy);
- _dos_keep(0, memtop);
- }
-