Dec 292017
C++ source for a TSR class (hotkey or timer popup).
File TSR100JE.ZIP from The Programmer’s Corner in
Category C++ Source Code
C++ source for a TSR class (hotkey or timer popup).
File Name File Size Zip Size Zip Type
$FILES.LST 967 345 deflated
CLOCK.CPP 3781 1397 deflated
CLOCK.EXE 17536 10197 deflated
MAKEFILE.MAK 1498 605 deflated
PROTECT.CPP 5396 1692 deflated
PROTECT.EXE 18428 10529 deflated
SCRCOPY.CPP 4793 1598 deflated
SCRCOPY.EXE 19684 11264 deflated
TICK.CPP 3037 1128 deflated
TICK.EXE 17600 10304 deflated
TSR.CPP 33985 8753 deflated
TSR.DOC 14616 4633 deflated
TSR.H 11982 3211 deflated
TSR.OBJ 6902 3975 deflated

Download File TSR100JE.ZIP Here

Contents of the TSR.DOC file

Page 1

Class TSR: an abstract base class for DOS resident programs.

Author: John English ([email protected])
Department of Computing
University of Brighton
Brighton BN2 4GJ, England.

Copyright (c) J.English 1993.

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.

1. Introduction.
This class provides a framework for writing memory-resident DOS
programs (TSRs). TSRs produced using this class can be woken up
by a specific key (the "hotkey") or after a specified number of
timer ticks (the "timeslice") or a combination of both. Writing
TSRs unaided is a non-trivial task, but this class provides the
essential TSR functionality which allows you to concentrate on
your application-specific requirements. TSRs written using this
class will require a PC/AT compatible machine running DOS version
3 or higher. Compile them with Borland C++ version 3.0 or higher.

To create a TSR using this class, you must derive a class for your
application from it. You must supply a function "main" in your
application class, which will be called whenever the TSR is woken
up. To create a TSR, declare an instance of your derived class.

A program built using an instance of your class can make itself
resident using the member function "run", it can test if a copy
is already loaded using the member function "loaded", and it can
unload a previously loaded copy using the member function "unload".
A foreground copy can also communicate with a resident copy using
the functions "request" and "respond". Each TSR must be given a
unique name up to 32 characters long which can be used to identify
it once it is made resident.

The constructor and "run" will set an internal status code if any
errors are detected. If "run" returns, this will show the cause
of the error. The status can be tested during program execution
using the member function "status". This can be used to display
meaningful error messages or to return as the program exit status.
The member function "name" returns the name of the TSR, which can
also be used in error messages.

If you find this class useful or have any suggestions as to how it
can be enhanced, please contact the author at one of the addresses
given above. E-mail and postcards will both be welcome!

2. Deriving a new TSR class "MyTSR" from class TSR.
The constructor for your derived class "MyTSR" must invoke the
constructor for class TSR. The constructor for class TSR takes

Page 2

two parameters:

* a unique string which will be used to identify your TSR, and

* the size in bytes of the stack to be used when the resident
part of your TSR is active. If no stack size is specified,
the default stack size is taken to be 1024 bytes.

Class MyTSR must also provide a definition of a member function
called "main" which will contain the application-specific code
for your TSR. This will be executed whenever your TSR is woken
up. It must be declared as follows:

void main (int hotkey);

Class MyTSR may also provide a destructor (~MyTSR), but this will
only be called when the TSR is not made resident.

Having created a derived class, you should then declare a single
instance of this class in your program, as for example:

MyTSR my_tsr;

You must not declare more than one instance of a class derived
from TSR in your program.

Your program can obtain status information by calling the following
member functions: ();
This returns the name of the TSR instance (as specified
in the constructor call to class TSR).

my_tsr.loaded ();
This returns an integer result which will be non-zero
if a copy of the TSR is already loaded.

my_tsr.status ();
This returns an integer result which will be non-zero
if any errors have been detected by the constructor or
by "run". The error codes are as follows:

1: incompatible DOS version (version 3 or higher required)
2: attempt to declare more than one instance of a TSR
3: unable to create stack of specified size
4: cannot allocate self-identify multiplex function
5: TSR already loaded
6: failed to make TSR resident (unlikely to occur)
7: user "startup" function reported failure

my_tsr.unload ();
This attempts to unload a previously-loaded copy of the
TSR. It returns an integer result which will be non-zero
if it failed, as follows:

1: TSR not loaded, so it cannot be unloaded.
2: Something else has hooked the same interrupts, so it
cannot be unloaded.

Page 3

3: Unable to free memory, so it cannot be unloaded (but it
will now be disabled and will no longer respond to the
hotkey or to timer ticks). This is unlikely to occur.
4: unable to free TSR environment space (although the TSR
itself will have been successfully unloaded). This is
unlikely to occur.

3. Making your TSR resident.
To make your TSR resident in memory, call the member function
"run". "Run" requires two parameters:

* A value representing the hotkey to be used to activate the
TSR. This is described further below.

* An optional timeslice size. This is an integer giving the
number of timer ticks between TSR activations (a timer tick
is approximately 55 milliseconds). If this parameter is
omitted or zero, the TSR will only be activated when the
hotkey is pressed.

The hotkey should be a combination of values from the following

Keycodes: TSR::KEY_A to TSR::KEY_Z, TSR::KEY_0 to TSR::KEY_9,

The hotkey value must not use more than one of the values from
the "keycodes" list above. If you do not wish a hotkey to be
used, specify a value of TSR::NONE for the hotkey parameter.
Some examples of valid hotkey specifications are shown below: (TSR::ALT + TSR::F1);
// "my_tsr" should be woken up whenever Alt-F1 is pressed. (TSR::LSHIFT + TSR::RSHIFT);
// "my_tsr" should be woken up whenever the left and right
// shift keys are pressed at the same time.

If you specify a hotkey of TSR::NONE and no timeslice is specified
either, "main" will never be woken up. You can use this to load
interrupt handlers (using "startup" and "shutdown" as described
below) which need to remain resident but do not need to interact
with the user in any way. "Main" should be an empty function if
this is the case, since it will never be called.

If the TSR is installed successfully, "run" will not return.
If "run" returns, it indicates that an error has occurred. The
member function "status" (see above) can be used to determine
the cause of the error.

4. Writing the member function "main".
"MyTSR::main" (the main function of your derived class) will be
called whenever the TSR is woken up, either as the result of the
hotkey being pressed or the specified timeslice expiring. The

Page 4

parameter "hotkey" will be non-zero if the TSR was woken up by
the hotkey being pressed and zero if it was woken up because the
timeslice expired. "Main" cannot perform operations which call
DOS functions 00 - 0C (character I/O), 48 (allocate memory), 4C
(terminate process) or 3E (close file, standard files only), but
otherwise it is a normal C++ function.

The following member functions can be used within "main":

void pause ();
This should be called whenever your "main" function is
performing any lengthy processing. It allows other TSRs
to execute while your TSR is active.

void sync ();
Timed activations normally occur every N timer ticks after
"run" is called. This function resets the timer so that
the next timed activation will happen N timer ticks from
now, rather than when the current timer count expires.
This can be useful to resynchronise timed activations if
a hotkey is used to enable/disable TSR activity.

int userbreak ();
This returns a non-zero result if "control-break" has been
pressed since it was last called. This can be polled from
"main" if control-break detection is required.

Your class may also overload the following functions to perform
error recovery for the resident part of your program:

critical_code critical_error (int n);
Called when a critical error (Abort, Retry, Fail?) occurs
during execution of "main". You must not call any DOS
services other than functions 00 - 0C within this function.
The result must be one of the values TSR::IGNORE, TSR::RETRY
or TSR::FAIL. The default action for this function is to
return TSR::FAIL.

void dos_error (int fn, int ce, int cs, int ip);
Called when an illegal DOS function is called from within
"main" or "critical_error" (see above). The parameter "fn"
is the function code from register AH; "ce" is non-zero if
the error occurred while a critical error was being handled;
"cs" and "ip" are the segment and offset of the return address
from the offending interrupt. If this function is called it
indicates a bug in your "main" or "critical_error" functions.
You must not use any DOS services in this function (although
BIOS services can still be used). The default action is to
reset the screen to text mode if it is in graphics mode and
then display an error message.

These functions should not be called directly; they will be called
automatically if an error occurs during execution of "main".

5. Initialisation and finalisation.
Since a TSR which is made resident does not exit in the normal way,
the destructor for your TSR will only be called if it is not made

Page 5

resident. However, you may need to perform some initialisation when
the TSR is made resident (e.g. hooking interrupts) and finalisation
when it is unloaded (e.g. restore the original interrupt vectors).
There are two virtual functions which can be overloaded to perform
this sort of initialisation and finalisation:

void startup ();
Called by "run" when the TSR is being installed in memory. This
can be used to provide application-specific initialisation (e.g.
hooking interrupts). The default is to do nothing.

void shutdown ();
Called by "unload" when the TSR is being unloaded from memory.
This can be used to provide application-specific finalisation
(e.g. restoring hooked interrupt vectors). The default is to
do nothing.

These functions should not be called directly; they will be called
automatically during TSR loading and unloading.

6. Communicating with a resident TSR.
Sometimes it may be necessary to communicate with a resident copy of
a TSR from a foreground program to adjust its parameters in some way.
The functions "request" and "respond" provide a method to perform
such communication. The program should provide an appropriate
implementation for the virtual function "respond", which has the
following specification:

int respond (int fn, int far& p1, int far& p2);

The parameter "fn" will be a function code in the range 0 to 127, and
the parameters "p1" and "p2" can be used for an application-specific
parameter list (which could be the segment and offset of a far pointer
of a lengthier parameter list).

A copy of the program loaded in the foreground can communicate with
a previously-loaded resident copy by calling the function "request".
"Request" requires three reference-to-integer parameters which will
be used to call "respond" in the resident copy; the first one should
contain the function code to be passed to "respond" and the remaining
two will be passed to "respond" as the parameters "p1" and "p2". The
result from "respond" will be stored in the first parameter, and the
final values of "p1" and "p2" produced by "respond" will be stored in
the last two. "Request" returns zero if the call is successful, and
a non-zero result (TSR::NOT_LOADED) if there is no resident copy to
communicate with.

7. A plea for feedback.
If you use this class, please contact the author via the addresses
at the beginning; if you don't have e-mail access please send me a
postcard (I like postcards!) just to let me know you've looked at
it. Feel free to suggest enhancements, find bugs or (better still)
fix them and send me patches. Happy hacking!

 December 29, 2017  Add comments

 Leave a Reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>