Function 31h Terminate Process and Stay Resident, KEEP, or TSR entry AH 31h AL exit code DX program memory requirement in 16 byte paragraphs return AX return code (retrieveable by function 4Dh Int\21f\4D) note 1) Files opened by the application are not closed when this call is made 2) Memory can be used more efficiently if the block containing the copy of the DOS environment is deallocated before terminating. This can be done by loading ES with the segment contained in 2Ch of the PSP and issuing function call Int\21f\49 (Free Allocated Memory). 3) Unlike Int/27, more than 64k may be made resident with this call o Ref: Dr. Dobb's Journal, April 1991 Pg 117 The TSR is a kludge. It exists because the designers of DOS failed to foresee the need for simple task-switching between concurrently resident programs. The TSR was made possible because those same designers needed to tack a print spooler to the single-user, single-tasking DOS. Their technique is both fragile and ugly. DOS is not re-entrant. If you interrupt a program while it is in the middle of a DOS call and run another program that makes DOS calls, DOS will crash and burn. A TSR must set an indicator that says it wants to pop up and then wait until DOS says it is OK. DOS indicates to the system when it can be interuppted by maintaining a flag called INDOS which is made available through Int\21f\34. If InDos is set, DOS is already busy with another call. In order to gain CPU service during a time that InDos is not set, the TSR must hook into the timer interrupt Int\1C which then allows it to become active 18.2 each second. When the TSRs keyboard interrupt service routine sees that you have pressed the hot key, it sets a flag. When the TSR timer interrupt service routine executes it looks at the hot key flag. If the hot key flag is set and the InDOS flag is not, the TSR is activated. Many TSRs also use the timer interrupt to guard against other, ill-behaved, TSRs that may hook the keyboard interrupt without chaining to the previous owner to pass along unused keystrokes. This is accomplished by looking at the address stored at the Int 09h space (0000:0024) and compairing it to the entry address of the keyboard interrupt service routine. If it has been changed, the program may decide to change it back or error out. Now, think about this, how does COMMAND.COM get input from the user at the command line? It makes a DOS call. While DOS is waiting for keystrokes InDos is set. DOS does not want to be interrupted..... TSRs can't run? This fine example of poor design is countered by (was there any doubt?) yet another kludge. While DOS is looping, waiting for a keystroke, it periodically cleans itself up well enough to handle calls above Int\21f\0C, and then calls Int\28. This provides a "back door" for TSRs to gain CPU cycles while DOS waits for user input. When the TSRs interrupt 28 service routine is activated, it looks at the hot key flag and, if it is set, activates the TSR. In Summary: A TSR attaches the keyboard interrupt to watch for the hot key, Int\28 to watch for spare CPU time, and usually the timer interrupt to watch everything. The Pop UP Before popping up, the TSR must switch context from the interrupted program to itself. This includes: o Changing from the interrupted program's stack to that of the TSR, o Tricking DOS into thinking the TSR is its single task by switching its pointer to the running program's Program Segment Prefix (PSP). Note that the calls for getting and setting the PSP in DOS versions prior to 3.0 do not work properly. Int\21f\50 -wrong stack Later DOS versions work just fine Int\21f\62 o Changing the Disk Transfer Address (DTA) from that of the interrupted program to that of the TSR's. Int\21f\2f Int\21f\1A o Temporarily disabling DOS's critical error handler. Int\24 o Capture Ctrl-Break and Ctrl-C keypresses. Int\23 Int\09 -Ctrl-Break Int\21f\08 -ctrl-C o If the program is going to use the mouse, save the current mouse context. Int\33 -Save Driver State o Depending on what the program is going to do, the video mode will have to be determined, saved, reset, and restored on exit. Be aware that if the interrupted program has set the video mode by directly writing to the CRT controllers registers, there may be no way to determine what the mode is. (this makes it rather difficult to save the mode, or to restore it later!) Int\10f\00 o REF PC Magazine Vol 10.7 Pg 342 When the TSR loader program is executed, it must make sure that the resident portion of its code is not already loaded. Otherwise, multiple copies of the same program will be competing for the hot key, memory, and cycles. To determine if a TSR program has already made its self self resident, include a check message consisting of any unique ASCII text in the resident portion of the code. Then sequentially check each segment of memory to see if this check message is located where it should be. However, before starting to search through the segments, change the check message slightly so that a match will not be found in a disk cache. Start the search at segment A000h and wrap around to low memory. In this way the TSR code will be caught in the event that it has been loaded into high memory. o 28APR91@20:24 Why not just compare the copy of the resident code that was loaded with the loader to each segment in memory? o 28APR91@20:38 For that matter, why not just call int 28 with a special code which will be ignored by the background tasks but recongized and responded to with the resident segment address by the resident code?