?? tsr.cpp
字號(hào):
//--------------------------------------------------------------------------
//
// TSR.CPP: body of DOS TSR class.
// Copyright (c) J.English 1993.
// Author's address: je@unix.brighton.ac.uk
//
// Permission is granted to use copy and distribute the
// information contained in this file provided that this
// copyright notice is retained intact and that any software
// or other document incorporating this file or parts thereof
// makes the source code for the TSR class of which this file
// is a part freely available.
//
//--------------------------------------------------------------------------
//
// Note: this class is highly DOS specific and hence non-portable.
// It also involves the use of assembly language and interrupt
// functions, so it is also very compiler-specific. Will require
// modifications for use with compilers other than Borland C++ 3.0
// or later. If Borland compilers prior to version to version 3.0
// are used, note that they do not support nesting of types within
// classes (so TSR::F1 etc. will need changing to a global name F1)
// and that the "_chain_intr" function used here was introduced with
// version 3.0.
//
// Revision history:
// 1.0 March 1993 Initial coding
//
//--------------------------------------------------------------------------
#include "tsr.h"
#include <stdio.h>
#include <string.h>
#include <dos.h>
#include <bios.h>
//--------------------------------------------------------------------------
//
// Constants.
//
const int MIN_STACK = 512; // minimum stack size in bytes
const int ALT_FKEY = 0x68 - TSR::F1; // hotkey change for Alt-Fn
const int CTRL_FKEY = 0x5E - TSR::F1; // hotkey change for Ctrl-Fn
const int SHIFT_FKEY = 0x54 - TSR::F1; // hotkey change for Shift-Fn
const long DAY_LENGTH = 1573040L; // length of day in timer ticks
const char far* COPYRIGHT = "C++ TSR class, Copyright (c) J.English 1993";
// copyright notice for self-identify
//--------------------------------------------------------------------------
//
// Global (static) variables.
//
static TSR* instance = 0; // pointer to the TSR instance
static char TSRname [32]; // TSR identifying string
static unsigned char hotshift; // shift state for hotkey
static unsigned char hotscan; // scancode for hotkey
static int interval; // length of timeslice in timer ticks
static int TSRfunction; // Int 2F function used to find TSR
static char far* stack; // stack for TSR execution
static unsigned stacklen; // size of TSR stack in bytes
static unsigned pspseg; // saved PSP segment
static unsigned dtaseg; // saved DTA segment
static unsigned dtaoff; // saved DTA offset
static volatile char far* indos; // saved INDOS flag address
static volatile char far* critical; // saved critical error flag address
static volatile int diskflag = 0; // set if disk interrupt in progress
static volatile int breakflag = 0; // set if ctrl-break has been pressed
static volatile int hotkeyflag = 0; // set if hotkey pressed
static volatile int TSRrequest = 0; // set if TSR should wake up
static volatile int TSRactive = 0; // set if TSR already active
static volatile long nexttick = 0; // next timer tick to wake up at
static volatile long far* timer = (volatile long far*) MK_FP(0x40,0x6C);
static volatile char far* midnight = (volatile char far*) MK_FP(0x40,0x70);
// timer values in BIOS data area
//--------------------------------------------------------------------------
//
// Functions and function pointers.
//
typedef void interrupt (*Handler)(...); // interrupt handler address type
static Handler oldint8; // old int 8 vector (timer)
static Handler oldint9; // old int 9 vector (keyboard)
static Handler oldint13; // old int 13 vector (disk)
static Handler oldint21; // old int 21 vector (DOS services)
static Handler oldint23; // old int 23 vector (control-break)
static Handler oldint24; // old int 24 vector (critical error)
static Handler oldint28; // old int 28 vector (DOS scheduler)
static Handler oldint2F; // old int 2F vector (multiplex)
static int unhook (); // unload function used by int 2F
//--------------------------------------------------------------------------
//
// Compare two far strings.
//
// This is the same as "strcmp" except that we need a function to
// compare far pointers in all memory models, and "strcmp" only
// handles near pointers in the small and medium models.
//
int compare (const char far* a, const char far* b)
{
while (*a == *b)
{ if (*a == '\0')
return 0;
a++, b++;
}
return *a - *b;
}
//--------------------------------------------------------------------------
//
// Check if a key has been pressed.
//
// This nasty little routine is necessary because bioskey(1) does
// not recognise extended keyboards and will swallow keystrokes
// such as "ctrl-del" not supported on 84-key keyboards. This
// makes it necessary to use bioskey(0x11) instead, but there
// is a problem in that this function does not leave AX clear
// if no key has been pressed (it just sets the zero flag) so
// some assembler is needed to deal with this. It also means
// this library will not work with old (pre-AT) BIOSes that
// don't support int 16h, function 11h.
//
int check_key ()
{
asm {
mov ah,0x11; // do function 11h,
int 0x16; // ... int 16h
jnz key_found; // skip if a key has been pressed
mov ax,0; // else set AX = 0
};
key_found:
return _AX;
}
//--------------------------------------------------------------------------
//
// Int 08 (timer) handler.
//
// This handler first calls the original timer handler and then
// checks if either timeslicing has been selected or the hotkey
// has been pressed (as shown by "hotkeyflag"). If so, the TSR
// request flag is set. If DOS is in a safe state, the TSR is
// then activated.
//
static void interrupt TSRint8 ()
{
// chain to old int 8
oldint8 ();
// exit if TSR is already running
if (TSRactive)
return;
// amend "nexttick" if midnight has passed
if (*midnight != 0 && nexttick >= DAY_LENGTH)
nexttick -= DAY_LENGTH;
// check if TSR should be activated
if (hotkeyflag == 0 && (interval == 0 || (*timer - nexttick) < 0))
return;
// set request flag if so
TSRrequest = 1;
// reset timer if past last activation period
if (interval != 0 && (*timer - nexttick) >= 0)
nexttick += interval;
// activate TSR if DOS is safe
if (*indos == 0 && *critical == 0 && diskflag == 0)
activate ();
}
//--------------------------------------------------------------------------
//
// Int 09 (keyboard) handler.
//
// This handler first calls the original keyboard handler (with
// interrupts enabled) and then looks to see if the keys pressed
// match the hotkey. If so, "hotkeyflag" is set. If a keycode
// is included in the hotkey code (i.e. it is not just a set of
// shift keys only) the key is removed from the keyboard buffer.
//
static void interrupt TSRint9 ()
{
// chain to old int 9
asm { sti; }
oldint9 ();
// check if TSR uses hotkey
if (hotshift == 0 && hotscan == 0)
return;
// check if hotkey modifier keys are pressed
if ((bioskey(2) & 0x0F) != hotshift)
return;
// check if hotkey (if any) has been pressed
if (hotscan == 0 || (check_key() >> 8) == hotscan)
{ hotkeyflag = 1;
if (hotscan != 0)
bioskey (0x10);
}
}
//--------------------------------------------------------------------------
//
// Int 13 (disk) handler.
//
// This handler sets a flag to show that a (time-critical) disk
// transfer is in progress and then calls the original disk handler.
// It is declared as a far non-interrupt function, although it will
// be called as an interrupt handler; the code here does not affect
// any registers, and we want the flag settings from the original
// disk handler to be returned to the caller.
//
// On entry, BP has been pushed on the stack. DS must be set up
// so that "diskflag" and "oldint13" can be accessed, so DS is
// pushed on the stack and the BP is used to reset it. On exit,
// DS and BP are popped from the stack and we return via a RETF 2
// which will throw away the flag register on the stack below the
// return address.
//
// The code here is highly dependent on the compiler-generated entry
// sequence, so CHECK WITH CARE if any compiler other than Borland
// is being used!
//
static void far TSRint13 ()
{
// set correct data segment
asm { push ds; mov bp,seg diskflag; mov ds,bp; }
// set flag while disk operation in progress
diskflag = 1;
// chain to old int 13
oldint13 ();
// clear disk flag
diskflag = 0;
// return using "retf 2" to leave flags intact
asm { pop ds; pop bp; retf 2; }
}
//--------------------------------------------------------------------------
//
// Int 21 (DOS service) handler.
//
// This handler is installed immediately prior to activating the
// TSR, and checks that the TSR does not call any unsafe services.
// The unsafe services are 00-0C (character I/O services), 3E (close
// file) for standard handles (0-4), 48 (allocate memory) and 4C
// (terminate process), or functions above 0C if a critical error
// is being handled. If any of these are called from the TSR, the
// virtual function "dos_error" will be called with the service
// number as a parameter. All other calls are passed to DOS in
// the normal way.
//
static void interrupt TSRint21 (unsigned, unsigned, unsigned,
unsigned, unsigned, unsigned,
unsigned, unsigned bx, unsigned ax,
unsigned ip, unsigned cs)
{
// static flag keeps track of whether called from "dos_error"
static int dosflag = 0;
// ignore DOS calls from within "dos_error"
if (dosflag != 0)
return;
// trap and ignore unsafe calls
const unsigned ah = ax >> 8;
if ((!*critical && (ah <= 0x0C || ah == 0x48 || ah == 0x4C
|| (ah == 0x3E && bx <= 4)))
|| (*critical && ah > 0x0C))
{ dosflag = 1;
instance->dos_error (ah, *critical, cs, ip);
dosflag = 0;
return;
}
// chain to old handler for safe calls
_chain_intr (oldint21);
}
//--------------------------------------------------------------------------
//
// Int 23 (control-break) handler.
//
// This handler is installed immediately prior to activating the
// TSR. It just sets a flag to record that control-break has been
// pressed. The main TSR function can poll this flag using the
// member function "userbreak", which returns the flag value and
// also resets the flag.
//
static void interrupt TSRint23 ()
{
breakflag = 1;
}
//--------------------------------------------------------------------------
//
// Int 24 (critical error) handler.
//
// This handler is installed immediately prior to activating the
// TSR. It just calls the virtual function "critical_error" to
// deal with the error.
//
static void interrupt TSRint24 (unsigned, unsigned di, unsigned,
unsigned, unsigned, unsigned,
unsigned, unsigned, unsigned ax)
{
ax = instance->critical_error (di & 0x00FF);
if (ax == 2 || ax > 3)
ax = 3;
}
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -