-Marcus Gustafsson
You have to unhook all used interrupts, then use the memory deallocation
function on the PSP of the (TSR'd) version of the program. Also deallocate
the memory used by your tsr'd program's environment if you don't wish to
lose it. What I generally do is have the TSR hook an interrupt (say int 80h)
and then when you run it the second time it detects whether it is
previously loaded by examining the int 80h vector and maybe running it
to see if it can get a specific code back from the TSR'd version. Then
you unhook the ints, free the memory, and return to DOS. If you want you
can put the rundown code in the TSR'd version... then instead of
returning to DOS it should return to your second invocation of the
tsr which can then return to DOS.
David
:
: -Marcus Gustafsson
and don't forget to switch the the TSR's PSP if calling 4Ch int 21
otherwise you just kill the program which was active, as your TSR
came to execution again. Besides calling 4C in a TSR is not too wise.
Some systems can react very strangely.
The most safe way is to free all the handles, reset the interrupts used
and go through the MCB's to change all of the PSP entries equal to
yours to 0000. You should have saved the PSP at installation time.
--
Have a nice, foolish day,
THE FOOL
I THINK I'M GOING SLIGHTLY MAD ...
------------------------------------------------------------------------
|\ | o _ |/ Life's like a jigsaw
| \| | |_ |\ You get the straight bits
But there's something missing in the middle
Nick Brown, Strasbourg, France (Nick....@dct.coe.fr)
------------------------------------------------------------------------
>Hello everybody
>How do you unload a TSR?
>I've made a small TSR wich is supposed to remove itself the second time
>its called, but I haven't got a clue how to do it, when I use dos
>function 4c, everything just locks up.
First, the transient code has to search for a resident copy, and
if found, store the segment address of the resident copy. I've seen this
done in three ways: (1) Search for a unique signature string in the
resident code. This can be an actual copyright notice, etc., or (to save
resident memory), a paragraph or two of the program's executable code
(provided that you make sure that no variables are in the signature).
(2) Hook a special interrupt (INT 2Fh and INT 2Dh are the most popular)
and have the resident copy's interrupt handler return a unique value if
it's called by the transient copy. (3) Search the memory control block
chain for a valid MCB containing the TSR's name in the owner field, and a
matching size in the size field. Option 1 is probably the easiest one to
do, and most economical of memory. Option 2 is probably the most
foolproof. Option 3 might be useful in special cases.
If a resident copy is found, when you attempt to uninstall, you
must do three things: (1) Call INT 21h, function 35h to get your
interrupt's address for every interrupt you've hooked. Compare the output
in BX with the offset of your interrupt handler; if not the same, a later
program has hooked that interrupt, and you must abort the uninstallation.
(2) If that test is passed, use INT 21h, function 25h to readdress each
interrupt to the original address which you should have stored in a
variable before going resident (this reverses what you did when you hooked
the interrupt). (3) Use INT 21h, function 49h, with the segment of the
resident copy in ES, to free the TSR's memory. (This should also be done
for its environment block, if you didn't release that before installing.)
If all this proceeds without errors, you can *then* terminate with
function 4Ch.
I can provide .ASM code samples of these techniques on request.
--Donald Davis
>There's a convention that TSRs should hook interrupt 2Fh and respond to
>this interrupt being called with a certain "magic" value in AX. You can
>code your initials in ASCII or whatever. Extra elegance comes by having
>this "multiplex code" be a command line option, so you can coexist
>with another TSR which uses the same method and by coincidence the same
>AX value.
That will work, but you don't really need to do this manually.
The TSR Pc-Dial (from the book "PC Magazine DOS 6 Techniques &
Utilities," by Jeff Prosise) incorporates a routine to find the first
unused multiplex ID number on the system running the TSR.
--Donald Davis
>and don't forget to switch the the TSR's PSP if calling 4Ch int 21
>otherwise you just kill the program which was active, as your TSR
>came to execution again. Besides calling 4C in a TSR is not too wise.
>Some systems can react very strangely.
I believe that the original questioner was calling INT 21, 4Ch
from the transient code when attempting to get the transient copy to
uninstall the resident copy. The above problem arises only if it is
called from the resident copy.
--Donald Davis
PC Intern from Abacus has a example of a TSR load/unload program.
1) Revector all hooked interrupts to their previous vectors but,
only if they still point to your code. If not, someone else
has hooked them after your TSR was loaded and it now cannot
be unloaded.
2) Restore anything else your TSR might have done, ie allocating
memory, changing Video Modes, reprogramming the timer, etc.
3) Free the memory allocated to your TSR (and the environment if
you kept it when the TSR was loaded). If the TSR is a .COM
then its PSP is the .Code segment. If its an .EXE, then you
have to save the PSP segment in a local variable when it loads.
Hope this helps.