?? tsr.cpp
字號:
//--------------------------------------------------------------------------
//
// Int 28 (DOS scheduler) handler.
//
// This handler is called by DOS whenever it is idle. It first
// checks to see if the TSR is not already running and that there
// is a pending activation request. If not, it calls the old
// handler and exits. Otherwise it checks if DOS is in a safe
// state and if it is activates the TSR. Note that the INDOS
// flag is safe if it is 1, as this means it is being called
// from inside DOS but that no nested calls are in progress.
//
static void interrupt TSRint28 ()
{
// chain to old handler if TSR is already running or activation not
// requested
if (TSRactive || (!hotkeyflag && !TSRrequest))
_chain_intr (oldint28);
// activate TSR if DOS is safe
if (*indos <= 1 && *critical == 0 && diskflag == 0)
activate ();
}
//--------------------------------------------------------------------------
//
// Int 2F (multiplex) handler.
//
// This function provides a means of communicating with the TSR
// for installation testing and unloading. AH must be the TSR
// function code (as located by the constructor), AL must be the
// subfunction code (00, 01, or 80 to FF), BX:DI must point to a
// copy of the class copyright notice and ES:SI must point to a
// copy of the TSR's name (or be a null pointer if AL = 00). If
// these conditions are not met, the call is passed to the original
// handler. Otherwise ES:SI is set to point to the copyright notice
// (which is guaranteed not to be the same as any identifying string
// due to its length) and a result code from the selected subfunction
// is stored in AX. The calls are handled as follows:
//
// Subfunction 00 (installation check): set AX to 0xFF if ES:SI point
// to a copy of this TSR's name (TSR is installed) or if ES:SI
// are both zero (check if function is available for use by a
// TSR built using this class).
// Subfunction 01 (unload TSR): the handler attempts to unhook the
// TSR ready to be unloaded from memory. If this is successful,
// AX is set to the TSR's PSP address; otherwise AX will be set
// to zero.
// Subfunctions 80 - FF (application-specific): CX and DX are the
// call parameters (which might be a far pointer to a longer
// parameter block). They are passed as references to the
// virtual function "respond". The function result is returned
// in AX; the values of CX and DX as set by "respond" will also
// be returned to the calling program.
//
static void interrupt TSRint2F (unsigned, unsigned di, unsigned si,
unsigned, unsigned es, int dx,
int cx, unsigned bx, unsigned ax)
{
if ((ax >> 8) != TSRfunction
|| compare ((char far*) MK_FP(bx,di), COPYRIGHT) != 0)
_chain_intr (oldint2F); // this call doesn't return
unsigned al = ax & 0xFF; // subfunction code
// installation check
if (al == 0 && ((es == 0 && si == 0)
|| compare ((char far*) MK_FP(es,si), TSRname) == 0))
ax = 0xFF;
// unload resident copy request
else if (al == 1 && compare ((char far*) MK_FP(es,si), TSRname) == 0)
ax = unhook ();
// application-specific request to resident copy
else if (al >= 0x80 && compare ((char far*) MK_FP(es,si), TSRname) == 0)
ax = instance->respond (al & 0x7F, cx, dx);
// interrupt not directed here, so chain to old handler
else
_chain_intr (oldint2F); // this call doesn't return
// set ES:SI to address of resident copy's copyright notice
es = FP_SEG (COPYRIGHT);
si = FP_OFF (COPYRIGHT);
}
//--------------------------------------------------------------------------
//
// Activate body of TSR.
//
// This function performs some essential housekeeping operations
// before and after calling the main TSR function. This involves
// hooking interrupts 21, 23 and 24, saving the current DTA and
// PSP addresses, switching to the user stack, setting the TSRactive
// flag to avoid re-entrant activations, and clearing TSRrequest.
// After TSR::main has returned, the hotkey flag is cleared and
// the original context (stack, DTA, PSP and interrupt vectors)
// is restored. Since this function is declared as a friend in
// the class declaration, it has to be public; to make sure it is
// not called directly, it checks that "TSRrequest" is non-zero
// before doing anything.
//
void activate ()
{
// declare non-stack variables
static unsigned oldpsp; // saved PSP segment
static unsigned olddtaseg; // saved DTA segment
static unsigned olddtaoff; // saved DTA offset
static int oldsp; // saved stack pointer
static int oldss; // saved stack segment
static union REGS r; // registers for DOS calls
static struct SREGS s; // segment registers for DOS calls
// test TSR activation has been requested
if (TSRrequest == 0)
return;
// save DTA and PSP addresses
r.h.ah = 0x2F; // get DTA
intdosx (&r, &r, &s);
olddtaseg = s.es, olddtaoff = r.x.bx;
r.h.ah = 0x51; // get PSP
intdos (&r, &r);
oldpsp = r.x.bx;
// set DTA and PSP to saved addresses
r.h.ah = 0x1A; // set DTA
s.ds = dtaseg, r.x.dx = dtaoff;
intdosx (&r, &r, &s);
r.h.ah = 0x50; // set PSP
r.x.bx = pspseg;
intdos (&r, &r);
// set interrupt vectors for TSR execution
oldint21 = getvect (0x21);
oldint23 = getvect (0x23);
oldint24 = getvect (0x24);
setvect (0x21, Handler (TSRint21));
setvect (0x23, Handler (TSRint23));
setvect (0x24, Handler (TSRint24));
// switch to TSR stack
asm { cli; }
oldsp = _SP;
oldss = _SS;
_SP = FP_OFF (stack);
_SS = FP_SEG (stack);
asm { sti; }
// execute body of TSR
TSRactive = 1;
instance->main (hotkeyflag);
TSRactive = 0;
// restore original stack
asm { cli; }
_SP = oldsp;
_SS = oldss;
asm { sti; }
// restore original interrupt vectors
setvect (0x21, oldint21);
setvect (0x23, oldint23);
setvect (0x24, oldint24);
// save DTA and PSP addresses
r.h.ah = 0x2F; // get DTA
intdosx (&r, &r, &s);
dtaseg = s.es, dtaoff = r.x.bx;
r.h.ah = 0x51; // get PSP
intdos (&r, &r);
pspseg = r.x.bx;
// reset original DTA and PSP
r.h.ah = 0x1A; // set DTA
s.ds = olddtaseg, r.x.dx = olddtaoff;
intdosx (&r, &r, &s);
r.h.ah = 0x50; // set PSP
r.x.bx = oldpsp;
intdos (&r, &r);
// clear hotkey and request flags
TSRrequest = 0;
}
//--------------------------------------------------------------------------
//
// TSR::TSR
//
// This is the class constructor. It checks for a number of
// possible errors, and stores the name and stack size of the
// TSR in global variables. A pointer to the current instance
// is stored in the global variable "instance" so that interrupt
// routines can invoke member functions. The multiplex (int 2F)
// functions from 0xC0 to 0xFF are scanned for an unused function
// or an existing TSR based on this class; this is stored in
// "TSRfunction" and will be the function code recognised by
// the int 2F handler.
//
TSR::TSR (const char* name, unsigned stacksize)
{
stat = SUCCESS;
// copy name
strncpy (TSRname, name, sizeof(TSRname));
TSRname [sizeof(TSRname) - 1] = '\0';
// check DOS version
if (_osmajor < 3)
{ stat = DOS_VERSION; // error: DOS version < 3
return;
}
// save instance pointer
if (instance != 0)
{ stat = MULTI_COPIES; // error: multiple instances
return;
}
instance = this;
// set stack length
stacklen = (stacksize < MIN_STACK ? MIN_STACK : stacksize);
// find spare multiplex function
union REGS r;
struct SREGS s;
for (int i = 0xC0; i <= 0xFF; i++)
{ r.h.ah = i, r.h.al = 0;
r.x.bx = FP_SEG (COPYRIGHT);
r.x.di = FP_OFF (COPYRIGHT);
s.es = 0, r.x.si = 0;
int86x (0x2F, &r, &r, &s);
if (r.h.al == 0)
break; // function not in use
if (r.h.al == 0xFF
&& compare ((char far*) MK_FP(s.es, r.x.si), COPYRIGHT) == 0)
break; // function in use by derivation of TSR
}
if (i > 0xFF)
{ stat = NO_MUX_FUNC; // error: can't find multiplex function
return;
}
TSRfunction = i;
}
//--------------------------------------------------------------------------
//
// Do TSR setup.
//
// This function creates the stack, saves the DTA and PSP addresses,
// locates the INDOS and critical error flags, and hooks the wake-up
// interrupts. Note that the stack is never deleted; it will remain
// in existence while the TSR is loaded, and will be deallocated along
// with everything else when it is unloaded. It returns zero if the
// stack could not be allocated.
//
static int setup ()
{
// create stack (note: this is never deleted!)
char* stk = new char [stacklen];
if (stk == 0)
return 0;
stack = (stk + stacklen);
// save DTA and PSP addresses
union REGS r;
struct SREGS s;
r.h.ah = 0x2F; // get DTA
intdosx (&r, &r, &s);
dtaseg = s.es, dtaoff = r.x.bx;
r.h.ah = 0x51; // get PSP
intdos (&r, &r);
pspseg = r.x.bx;
// locate INDOS flag
r.h.ah = 0x34;
intdosx (&r, &r, &s);
indos = (char far*) MK_FP(s.es, r.x.bx);
// locate critical error flag
r.x.ax = 0x5D06;
intdosx (&r, &r, &s);
critical = (char far*) MK_FP(s.ds, r.x.si);
// hook interrupts
oldint8 = getvect (0x08);
oldint9 = getvect (0x09);
oldint13 = getvect (0x13);
oldint28 = getvect (0x28);
setvect (0x08, Handler (TSRint8));
setvect (0x09, Handler (TSRint9));
setvect (0x13, Handler (TSRint13));
setvect (0x28, Handler (TSRint28));
return 1;
}
//--------------------------------------------------------------------------
//
// TSR::run
//
// This function makes the TSR resident, and will only return if
// a copy of the TSR is already loaded. The virtual function
// "startup" is called to perform any class-specific intialisation.
//
void TSR::run (int hotkey, unsigned timeslice)
{
if (stat != SUCCESS)
return;
// avoid reloading TSR if already loaded or failed
if (loaded ())
{ stat = RELOAD_FAIL;
return;
}
// set hotkey shift state and scancode
hotshift = (hotkey >> 8) & 0xFF;
hotscan = hotkey & 0xFF;
// check for F1 .. F10, which have different scan codes if ALT, CTRL
// or SHIFT is pressed (ALT takes precedence over CTRL which takes
// precedence over SHIFT)
if (hotscan >= F1 && hotscan <= F10)
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -