Retro video games delivered to your door every month!
Click above to get retro games delivered to your door ever month!
X-Hacker.org- Zortech C++ 3.0r4 - <b>the tsr package</b> http://www.X-Hacker.org [<<Previous Entry] [^^Up^^] [Next Entry>>] [Menu] [About The Guide]
The TSR Package

   Small model programs can be simply and easily turned into Pop-Up or TSR
   programs by means of the routines in this library. Many of the standard

   library functions can be used within a TSR. These functions are only
   supported under real mode MS-DOS.

   The routines supplied with this package allow you to write programs in
   Zortech C and C++ that can optionally become memory resident. Such
   programs are often called TSRs or Pop Ups. In addition your programs can
   optionally be given a slice of the processor's time, allowing a carefully
   written program to run as a background process.

   The TSR package is only intended for use with real-mode MS_DOS. It is not
   supported with OS/2 or when using the 16 or 32 bit DOS extender. The
   terms, TSR and Pop Up mean the same thing. When your program is run it
   will become an extension to DOS. It will constantly monitor the keyboard
   looking for a key press that matches the key combination that you have
   declared in your program. This hotkey combination will be the signal for

   your program to spring into life, or pop up.

   The term TSR comes from the fact that when invoked from the DOS prompt
   your program can Terminate just like normal programs but it can also Stay
   Resident in memory. You have probably seen and used many TSR programs,
   now you will be able to write your own.

   The difference between a Pop Up and a background program is quite
   fundamental. The Pop Up is only active when the user invokes it with its
   hot key, while the background program is automatically invoked by the
   processor about 18 times every second. Do not worry too much at this
   stage about the implications of each type of program, this will become
   apparent when we go into more detail later.

History of the TSR

   From day one, DOS was designed as a single tasking, single user operating
   system and, since day two, programmers world wide have striven to change
   this. The way this was finally achieved was to write programs that make
   themselves extensions to DOS. They take over certain operating system

   functions and provide additional facilities without the operating system
   knowing anything about it. This is achieved via the terminate but stay
   resident procedure mentioned earlier.

   The first successful commercial TSR was a program called PROKEY from
   Rosesoft released in 1982. Borland soon followed this with a program
   called SIDEKICK, which sold beyond their wildest dreams.

   With the next major release of DOS (2.0) in March 1983, Microsoft had
   slipped in a couple of major TSRs of their own. These were ASSIGN,
   GRAPHICS and most importantly PRINT (the print spooler).

   However to help with the introduction of these programs they had also
   modified the operating system to be slightly more welcoming to potential
   TSR programs. They added the DOS function 31h, that allows .exe programs
   to become memory resident and they added the background scheduler, int
   28h, so that PRINT could spool out documents while DOS, or the user, was
   doing something else.

   This new facility of the background scheduler was not made common

   knowledge by Microsoft, but it was not long before astute programmers
   realized that PRINT was in effect "multi-tasking". They began to work on
   finding out how this was achieved.

   As the new releases of DOS have come and gone, there have been no further
   enhancements that have had any significant impact on the TSR programmer.
   The only item of interest was the release of a little known (and little
   used) special OEM version of DOS called MS-DOS 4.0 and later updated to
   MS-DOS 4.1. This is not to be confused with the later release of a
   commercial version 4.0 of MS-DOS and PC-DOS which is an altogether
   different product.

   The development of this OEM DOS version 4.0 was started in January 1983
   but it did not become available until 1987. This version of DOS was an
   attempt at providing a multi-tasking operating system. In the original
   version (4.0) you could run all your normal programs exactly as you could
   on DOS 3, but in addition you could multi-task certain specially written
   programs in the background. The main problem with this was that it was
   still a real mode operating system. This meant that it would run on
   8088/86 chips and was limited to the 640k of memory. The next release

   4.1, followed quickly. This still ran in real mode, but allowed the use
   of expanded (EMS) memory to multi-task the special application software.
   This OEM version of DOS is very rare and of no great value except to
   certain hardware manufacturers.

How a TSR works

   When you enter the name of a TSR program at the DOS prompt, it is treated
   just like any other program. Indeed, at this stage it is exactly that.
   DOS will allocate memory for it and load the .exe or .com file. It will
   then pass control to the first instruction in the program.

   Since DOS is a single tasking operating system, it hands the entire
   resources of the computer over to the program, to do as it pleases. When
   a program decides to become a TSR, it is giving up the safe world
   controlled by DOS, for a hostile world in which it is every program for
   itself. Therefore it must do certain things to protect itself.

   Firstly it must intercept certain interrupts. For instance if it wants to
   monitor the keyboard, to check for a special key combination, it would

   normally capture interrupt 9 (although there other ways of doing this).
   Interrupt 9 is an event that happens every time you press or release any
   key on the keyboard. If it wants to take advantage of the background
   scheduler, it must also capture int 28h.

What is an Interrupt?

   On the PC there are 256 interrupts (0 through 255). Each interrupt has an
   associated vector in memory. A vector consist of four bytes that contains
   the far address of a routine to be performed when the associated
   interrupt occurs. So when you press a key, an interrupt 9 is generated.
   This results in the CPU freezing whatever it is doing, picking up the
   address held in the associated vector and passing control to this
   routine. When this called routine returns the processor will continue
   from where it left off.

   Capturing an interrupt consists of placing the address of your own
   program in the interrupt vector. Thus we can see that if you capture int
   9 for example, and point this to a section of your program, this will
   automatically be called every time someone presses a key. If the program

   intends to let itself be unloaded, it obviously has to first save the
   contents of the vector, so that it can return it to its original state.

   The next thing a TSR must do is decide on the minimum amount of memory it
   requires. Once it has established this, it can ask DOS to terminate but
   to leave its image in memory. When this is done DOS will terminate the
   program and return to the DOS prompt. The memory that is requested by the
   TSR will be reserved and any subsequent programs will be loaded into
   memory after it.

   At this stage the program is in a state of suspended animation. Its image
   is in memory but it is not doing anything. Then when an interrupt that
   has been captured occurs, the program will activate.

   Let us add to the above scenario, by considering the timer interrupt, 8h.
   This is automatically invoked by hardware 18 times a second. So if a TSR
   also captures this interrupt, its chosen routines will also be serviced
   18 times a second. Therefore if the TSR is written with this in mind it
   can become a pseudo multi- tasking program, like PRINT.


What a TSR Can and Cannot Do

   When a TSR is given control via one of the captured interrupts it cannot
   do anything until it has checked to see if MS-DOS and the BIOS are
   stable. Remember that MS-DOS is a single user operating system so it is
   not surprising that when certain parts of it were written they were not
   made to be re-entrant. In other words if MS-DOS is doing something and a
   TSR "pops up" and asks it to do something else, the most likely result
   will be a frozen computer.

   This is overcome by the TSR program monitoring certain events. For
   instance, it monitors any non-re-entrant code and refuses to pop up when
   this is active. The TSR must monitor such things as disk access, and MS-
   DOS operations to detect if they are in use.

   The algorithm looks something like this:

   1.  Is the TSR already active?...if yes end
           else
   2.  Is Disk service busy?...if yes end

           else
   3.  Is a graphics application running?...if yes end
           else
   4.  Is DOS busy?...yes then are we inside scheduler...if no end

   The last condition needs a little explanation. Most TSRs chain into the
   scheduler, int 28h. As explained earlier this is an interrupt that is
   used by such programs as PRINT. It can be considered as an "all clear"
   indicator. Whenever DOS finds itself free it will fire off an int 28h.
   When this happens any program that is chained into int 28h will have a
   chance to do some processing.

   By chaining into this as well as another interrupt like 9 (keyboard) or 8
   (timer), TSRs give themselves two bites at the cherry in their attempts
   to pop up. What this actually means is that if your int 28h handler is
   given control it can ignore the test to see if DOS is busy, because it
   knows that int 28h is only fired when DOS is free. However if it is
   another handler that gets control it must not continue if DOS is busy.
   This can be demonstrated by attempting to pop up a TSR program, while at
   the DOS prompt.


C>

   When you see this on the screen, DOS is waiting for a command. This means
   that it is busy. So any pop up that relies on only an interrupt 8 or 9,
   will never pop up. However when DOS is waiting for input, there are a few
   seconds here and there when it is safe to pop up and in these few
   seconds, DOS will repeatedly issue interrupt 28hs.

   Once your TSR gets past the above maze, it can then virtually continue as
   normal. With one small proviso, it must not use a DOS service below 0Dh.
   (A DOS service is called by placing the service number in AH and issuing
   an interrupt 21h.)

   You will be pleased to know that you do not need to concern yourself with
   this housekeeping. The TSR routines will only let you proceed if it is
   considered safe to do so. In addition if you attempt to perform any
   illegal DOS services you will be given a warning on the screen. (See
   Debugging later).


Pop Ups Within Pop Ups

   We have seen that DOS has become more sociable towards memory resident
   programs, (even though it actually thinks it is being sociable to
   print.com), but what about TSRs being sociable with each other. The
   original release of SIDEKICK demonstrated how not to write a sociable
   program. It contained features such as forcing the contents of interrupt
   vectors to a value it thought was correct even when another program was
   using the same vector. This meant that dozens of other TSRs had trouble
   running alongside SIDEKICK, and instructions like "Load this program
   before SIDEKICK" became common place.

   There are some guidelines that make for a more compatible TSR. These are:

   1.  Chain into as few interrupts as possible

   2.  In your interrupt handlers, always service the old interrupt
   routine first. Unless of course you are adding features to an existing
   service.


   3.  Do not restore interrupt vectors unless you know that you are the
   owner of the vector. In which case restore them as you found them.

   All the above are implemented by the TSR routines. There is only one rule
   that you must adhere to (if you want to write friendly TSRs): When inside
   your pop up, at times when you are looping (for a key press etc.) give
   other pop ups a chance by executing an int 28h (see function
   tsr_service).

Supplied Files

tsr.h

   This is the header file for the TSR package. It must be included in your
   TSR program. It contains #defines for the scan codes and shift values
   that you can use when declaring your hotkey combination in your programs.
   It also contains the prototypes for the functions in the toolkit. Most
   importantly it ensures that the correct memory allocation method is used
   by the compiler. Failure to use this header file could result in your
   programs taking far more memory than it actually needs.


resdemo.c

   This file contains a sample program that you may wish to use for
   reference when writing your own programs. It shows exactly how to declare
   the necessary hot key and finger print declarations. It makes use of many
   standard library functions, including the Display package.

tsrclock.c

   This sample file is a program that uses the background option of the TSR
   package. Use this as an example when attempting to write this type of
   program. Background mode is explained in detail later.

Writing Your TSR Pop Up

   Writing your TSR could not be simpler. Write and debug your program as
   you would any normal program. Do not attempt to make it memory resident
   until you are confident that it is bug free.


   While writing your program keep the following points in mind:

   Do NOT use any functions that allocate memory (malloc etc.). You can use
   the Page package to manage your own memory if you wish.

   Do NOT use buffered file (*FILE) routines (fgets etc.), use the
   untranslated functions instead (open/read/close).

   Do NOT exit from any function, simply return.

Making Your Program Resident

   If you examine the resdemo.c source code you will see that this program
   starts in exactly the same way as any other program. The main function is
   entered and the program examines the command line arguments. If none are
   supplied it presumes you are attempting to load the software in memory
   resident mode. So the software attempts to make itself resident by
   calling:

tsr_install(int argument)


   If this is successful, the function will NOT return. If it does return it
   will pass back an error code which is covered later. Remember that you do
   not have to make your programs immediately become memory resident. For
   instance you could have a menu option that makes your program memory
   resident.

   You can see from the above that the function tsr_install takes one
   argument, this can currently be one of two alternatives, depending on the
   type of program your are writing. These alternatives are POPONLY and
   TIMESLICE.

tsr_install(POPONLY);

   This will make your program into a normal TSR pop up and the special
   function popmain will only be called when the user presses the chosen
   hotkey combination. The other alternative is:

tsr_install(TIMESLICE);

   If you use this method, your program will be converted into a background
   task and popmain will be entered repeatedly up to a maximum of 18 times
   per second. With this latter method, popmain will also be entered when
   the user presses the correct hotkey. Usually you will wish to determine
   whether popmain was entered through the hotkey or because of the
   timeslice algorithm.

   You can ascertain the answer to this by examining a global variable
   called _tsr_timeslice. Quite simply if popmain() was entered by the
   timeslice algorithm this variable will be set to 1, otherwise it will be
   set to 0. Examine the tsrclock.c source code to see this in action.

   This example uses the hotkey to toggle the time display on or off. If you
   decide to write a background task, you should design your program to be
   as efficient as possible. Try and keep the processing done in each time
   slice to a minimum. In other words keep your background tasks efficient
   and brief. As mentioned in the earlier introduction to memory resident
   programming you can make your program more compatible with other TSRs by
   giving them a chance to pop up when you are at a convenient point within
   your own TSR. You can do this with the tsr_service function.


void tsr_service(void)

   For instance instead of waiting for a key press like this:

       bioskey(0);

   Try this instead:

       while(bioskey(1)==0)        /* while no key press */
           tsr_service();          /* give others a chance */
       bioskey(0);                 /* then get key as normal */

   The function tsr_service, simply fires off a scheduler interrupt (int
   28h). No value is passed to or returned from tsr_service.

Debugging

   When you enter the world of TSR programming, you have to accept that
   there are certain things you can never do and other things that you can

   only do at certain times. Failure to adhere to these rules will probably
   result in a frozen computer. However these problems are compounded in a
   TSR written in C or C++, because you may know the rules, but you could
   call a function that does not. This could result in difficult to trace
   problems.

   To help you with this, we have included a facility that will trap and
   alert you to any possible bad practice within your TSR program. When you
   use this facility and any illegal actions are detected, a window will
   open with a (hopefully) meaningful message within it. This will help you
   to track down the particular function call that is causing the problems.

   To switch this debugging aid on, simply add the command,

       |TSR_DEBUG

   to your existing tsr_install command. For instance, if you normally use
   the form:

       tsr_install(POPONLY);


   Simply extend this to,

       tsr_install(POPONLY|TSR_DEBUG);

   likewise you could use,

       tsr_install(TIMESLICE|TSR_DEBUG);

   This facility does NOT attempt to cure any illegal actions it only alerts
   the user (programmer), waits for a key press and then allows the request
   to continue as normal. It will not stop a faulty program from freezing
   the computer, but it will explain why the computer is about to freeze!

   When invoked the debugging routines can trap several of the most common
   pitfalls that you may encounter. For each different problem you will see
   a meaningful message displayed. These are as follows:

Dos function 0dh
Press a key


   This means that some function in your program has made a call to INT 21h
   (dos function dispatcher) with the ah register set to a value below
   hexadecimal 0dh. This is illegal in a TSR program.

   To cure this, you could place displays in your code to track down the
   exact function call causing the problem. Likely culprits are the getch
   family.

Attempt to close std handle
Press a key

   Every time you open a file, DOS allocates an handle to that file. Then
   when you want to read or write to it, you use the handle that DOS gave
   you on opening. The handles that DOS allocates start from 5 and increment
   with each open request. The handles from 0000 to 0004 are reserved by DOS
   for its standard devices. These are such things as
   keyboard/screen/printer and com port.

   It is quite possible for your program to close these reserved devices,

   either intentionally or by accident. If you do ask DOS to close one of
   its standard handles, the debugging code will presume you have done so in
   error and it will inform you accordingly.

Memory Allocation
Not inside TSR!

   Memory resident programs are given a chunk of DOS' 640k when they make
   the transition from normal programs to TSRs. If they later make further
   requests for additional memory, DOS will try to oblige and get itself
   well and truly tangled. With this in mind the debugging software will
   watch for any attempts to get additional memory and the above window will
   appear to alert you of the request.

   If you want to dynamically manage memory within your TSR you should
   create a static buffer and turn this into a heap using page_initialize.
   You can then use page_malloc etc. to manage your memory. See the library
   entry for the Page package for more details.

   There is one further error mesage that may be observed:


Exit detected
Use return instead

   In a normal program you have probably used the exit function to abort
   your program. However you must remember that DOS does not really know
   about or understand TSR programs. It thinks that there is only ever one
   program running. It presumes that the underlying application (Wordstar
   etc.) and your TSR are one and the same. So if you end your program with
   a call to exit, DOS will presume the underlying program has asked to exit
   and it will duly abort it. To avoid any such conflict you should use
   return only, never use exit.

Removing your Program

   You will notice in the resdemo.c source code, that if a /R is placed on
   the command line, the program will attempt to unload a PREVIOUSLY LOADED
   copy of itself. It does this with a call to:

int tsr_uninstall(void);

   This function will always return a value. The various return codes are
   shown later. This function can be called, either from within the TSR when
   it is active, or from a routine that is executed when your program is
   called from the DOS prompt. If it is called from within the pop up when
   it is active it will remove the current copy of the TSR program from
   memory. So once the program has "popped down" it will not be able to pop
   up again. If it is called when the program is executed from DOS it will
   remove any previously loaded copy of itself.

   If you intend to remove your program from memory, when it is popped up,
   it is worth understanding a little of how DOS allocates and de-allocates
   memory.

   When a program is loaded by DOS, it is allocated one or more segments of
   memory. A segment is up to 64k bytes. A clever program can trace through
   the DOS allocated memory records and ascertain the owner of any segment
   (or part segment) of memory. When you use the TSR toolkit, your programs
   automatically have this ability and this is used when you try to remove
   your program from memory.


   When you call tsr_uninstall, it will look through the memory and return
   to DOS any segments that have been allocated to your program. It will
   also unhook any interrupts that are used by the TSR routines. However it
   is important to realize that just because the segments are returned to
   DOS it does not mean that your program is no longer in memory, it is and
   it will continue to run after tsr_uninstall returns. Although DOS now
   considers the memory previously allocated to your program to be free, in
   reality it still contains an image of your program, this is why it will
   continue to run. The freed blocks of memory will only be reused when DOS
   needs to allocate memory for another program.

   Consider the following situation:

   1.  You load your TSR program, DOS allocates memory to it and returns
   to the DOS prompt.

   2.  You load an ordinary program, Wordstar for instance.

   3.  You pop up your program from within Wordstar and it contains an

   option to remove itself from memory. (just like the RESDEMO example)

   4.  You select the option to uninstall the pop up.

   In the above scenario you have in effect created an hole in DOS' memory,
   this is because the memory was allocated as follows:

       DOS DRIVERS
       ...
       Your POP UP
       Wordstar

   Now that DOS has regained the memory allocation blocks that were
   allocated to your pop up a hole as appeared. However, DOS is perfectly
   capable of managing such situations. It will only use the memory in the
   "hole" if it is sufficient for its needs, it will not overwrite Wordstar
   (or what ever).

   Finally when Wordstar is exited, DOS will regain all the memory
   associated with it and the hole will disappear. The return values from

   tsr_install and tsr_uninstall are as follows:

   Return      Description
   ------------------------------------------------------------------------

   0           Function successful

   1           Can not load, program already loaded

   2           Can not remove, the program is NOT loaded

   3           Can not remove, another TSR program has been loaded on top of
               your program

Globals

   In your source file you must specify certain variables that will be
   referenced by the TSR routines. The value that you place in these
   variables will determine how the TSR routines work.


HOTSHIFT and HOTSCAN

   We have already stated that your (or any other) pop up TSR program must
   have a special key sequence that it recognizes as being the signal for it
   to pop up. This is usually called the hotkey combination. It is called a
   combination because it is the combination of one or more shift keys and
   an ordinary key (usually in the range A-Z). When this key combination is
   pressed the pop up will take control of the machine resources and can run
   as if it was the only program in the machine. The way that you specify
   your hotkey combination in your programs is to declare and initialize two
   variables called HOTSHIFT and HOTSCAN.

   HOTSHIFT is an integer that must contain a value that represents the
   shift keys you have chosen. The way to determine the value you should
   place in this integer is as follows:

   Choose your shift keys from one or more of the following available keys:

       LSHIFT  Left Shift key


       RSHIFT  Right Shift key

       CTRL    Control key

       ALT     Alt key

   Then simply declare an int called HOTSHIFT and initialize it with your
   chosen hot shift, like this:

       int HOTSHIFT=ALT+RSHIFT;

   This would declare your hot shift as being the alt key + the right shift
   key. You must also choose and declare the key that is to be used with the
   shift. Choose a key in the range A-Z and declare an int called HOTSCAN.
   Initialize it like this:

       int HOTSCAN=SCAN_Q;

   This will declare your key to be Q, so when someone presses:


       ALT+RIGHT SHIFT+Q

   Your program will pop up. Note that you must initialize HOTSCAN with a
   scan value not the character itself:

       int HOTSCAN='Q'     /* WRONG! */
       int HOTSCAN=SCAN_Q  /* RIGHT! */

   All the scan values for the keys A-Z and F1 to F10 are defined in the
   tsr.h file. If you really need to use a key outside the A-Z range, simply
   consult your favourite manual to find the scan value for the key you want
   to use and initialize HOTSCAN with this value.

   If you prefer not to use a scan value and you only want your hot key to
   consist of shift keys all you have to do is declare HOTSCAN as follows:

       HOTSCAN=NO_SCAN;

   This will instruct the TSR routines to ignore the scan value and only
   test the shift key values.


tsr_fprint

   This is a character string, 20 bytes long and it is your programs unique
   finger print. This is used by the install and uninstall functions to
   determine if your program is loaded in memory.

   For example:

       char tsr_fprint[20]= "Prog ID";

   Every time you write a new TSR program give it a unique finger print.

_okbigbuf

   The TSR routines have to determine how much memory your program requires,
   so that it can free the remaining memory and thus make it available to
   any applications that may be run. In order for the routines to arrive at
   an optimum figure your program should contain the following line above
   your main function.


       extern int _okbigbuf = 0;

   Failure to do this will simply result in a TSR which takes up too much
   system memory.

_tsr_timeslice

   As mentioned earlier, if you need to ascertain whether your popmain() was
   called because the hotkey was pressed or because of the timeslice
   algorithm, you can use the global _tsr_timeslice.

   If the hot key was responsible this will be set to zero, if the algorithm
   was responsible it will be set to 1. Using this you can provide a
   background task that can still be popped up and configured in some way by
   the user. For example, examining the tsrclock.c source code will show
   that this is how it displays a clock on the screen and allows you to
   press the hotkey to toggle the display on or off.

The Special Function popmain


   When your hotkey combination is pressed the TSR routines will pass
   control to a function in your program called popmain. When writing this
   function, remember that at that point you are handed control of the
   computer, it is up to you to save any areas of screen that you may
   destroy, also remember to save the cursor position and shape. The
   functions to do all this are supplied in the standard Zortech library,
   see the library entry for the Display package.

   When you have completed processing restore any areas of the screen that
   you may have overwritten and return control from popmain back to the
   calling TSR functions, they will return control to the underlying
   application.

Limitations

   The limitations of programs that use these routines are the same as for
   any TSR program. Namely you can only pop up when DOS is stable and no
   disk access is taking place. This is taken care of by the TSR routines.
   However no TSR program can allocate memory or make calls to DOS functions

   below 0Dh. There is the added problem that you may use a library function
   that performs some invalid task and not know it. Library functions to
   avoid are:

           malloc (or any other memory related command)

           Any buffered file usage (fread, fgets etc.).

A Complete Example

   This is an example of the TIMESLICE facility of the TSR toolkit. If you
   press the hotkey, you will toggle ON/OFF a clock on the screen. This
   clock will run in the background, while you continue to work as normal in
   the foreground.

   /*
                       TSRCLOCK.C
   Demo program for Zortech's Memory Resident Toolkit
   */


   /* #include other.h here */

   /*  ***********************************************  */
   /*   All programs must have these statements         */

   #include <tsr.h>                     /*must use this */
   unsigned TSR_HOTSHIFT = CTRL+LSHIFT; /* Your hotkey  */
   char     TSR_HOTSCAN  = SCAN_Q;      /* combination  */
   char tsr_fprint[20] = "tsrclock.v1"; /* unique string*/

   /*  In addition background programs must have this   */
   extern unsigned _tsr_timeslice;

   /*  ***********************************************  */
   /*  ------------Then enter your program---------     */

   union REGS regs;
   int cur_pg,cur_s,cur_p;
   int toggle=1;
   int hours,mins,secs;


   int main(int argc,char *argv[])
   {
       int i;

       if((strncmp(argv[1],"/R",2) ==0) ||
   (strncmp(argv[1],"/r",2)==0))
           {
               i=tsr_uninstall();
               if(i==0)
                   printf("Program removed\n");
                   if(i==2)
                       printf("Can not remove,
                               Program not loaded!\n");
                   if(i==3)
                       printf("Can not remove,
                               Another program loaded above\n");
                   exit(EXIT_SUCCESS);
               }


               printf("Press Control+Left Shift+Q to
                       toggle clock ON/OFF\n");

               i=tsr_install(TIMESLICE|TSR_DEBUG);

               /* if it returns, error has occurred  */
               if(i==1)
                   printf("Can not load,
                   program already loaded!\n");
               else
                   printf("Failed to install, error %i\n",i);
       return(EXIT_FAILURE);
   }

   void popmain(popmain)
   {
   /*
       POPMAIN is a special "reserved name" function, which
       the TSR routines will pass control to when the hot
       key is pressed.

   */

       if(_tsr_timeslice==0)   /* if hotkey */
       {
           toggle=toggle*-1;       /* set toggle on/off */
           return;
       }

       if(toggle)                  /* only display when on */
           return;

       regs.h.ah=0x2c;
       intdos(&regs,&regs);

       if(secs==regs.h.dh)     /* and if secs changed */
           return;

       hours=regs.h.ch;
       mins=regs.h.cl;
       secs=regs.h.dh;         /*save_cursor will destroy*/


       save_cursor();
       disp_open();
       disp_move(0,66);
       disp_setattr(14);
       disp_printf("TIME:%2.2i:%2.2i:%2.2i",hours,mins,secs);
       disp_close();
       restore_cursor();
   }

   save_cursor()
   {
        regs.x.ax=15*256;
        int86(0x10,&regs,&regs);
        cur_pg = regs.x.bx;
        regs.x.ax=3*256;
        int86(0x10,&regs,&regs);
        cur_p = regs.x.dx;
        cur_s = regs.x.cx;


        regs.x.dx=(24*256)+80;
        regs.x.ax=2*256;
        regs.x.bx=cur_pg;
        int86(0x10,&regs,&regs);
   }

   restore_cursor()
   {
        regs.x.ax=256;
        regs.x.bx=cur_pg;
        regs.x.cx=cur_s;
        int86(0x10,&regs,&regs);
        regs.x.dx=cur_p;
        regs.x.ax=2*256;
        int86(0x10,&regs,&regs);
   }

   The above example can also be found on your distribution disks.

Problems

   This package allows someone who has never heard of a "DOS BUSY FLAG" or
   even seen an assembler program to write pop ups easily and quickly.
   However, when you enter the world of the TSR you must expect problems. We
   have taken every care to ensure that self induced problems are kept to a
   minimum by trapping almost every action that you could inadvertently
   perform to crash your own TSR.

   If you experience problems with one of your programs, (most common will
   be a complete lock up), please follow these simple steps to track down
   the problem.

   1.  Ensure that the debugging window does NOT open at any stage inside
   your TSR.

   2.  Place displays in your program in order to identify the instruction
   or section of code that is causing problems.

   3.  Check your own code thoroughly!


   The TSR package has had an extensive testing period and so far no
   problems have been found with it. So please ensure that your own code is
   sound before assuming that the TSR package is at fault.





Online resources provided by: http://www.X-Hacker.org --- NG 2 HTML conversion by Dave Pearson