
102/107 17 Dec 91 14:32:55
From:   Gadi Oxman
To:     Jay Cadieux
Subj:   Unloading Stubborn Tsr
Attr:   
------------------------------------------------
Hi,

> Is there any way to force a TSR out of memory (unload it) in
> either ASM, C or PASCAL?  I think you have to do something to the
> PSP, but I'm not sure...

The TSR which will be unloaded should be the last TSR loaded into memory
for a safe unloading.
The main reason for this limitation, besides the problems of the operating 
system to work with memory slices, is that a TSR ("next") which is loaded
after the above TSR ("previous") can capture the same interrupts as the
previous did, and though reference adresses inside the previous as the
original interrupt vectors, adresses which will point to an invalid code
once the previous will be removed from memory.

In order to check if the TSR is the last resident program in memory, the
unloading program must check if the TSR is placed right below her.

When loading a program, DOS gives it a copy of the environment. Each
piece of memory is preceeded by a "memory control block" - "MCB" which
has a pointer to the next MCB.

Though the memory has to look like this:

[TSR's environment MCB]
[TSR's environment]
[TSR's MCB]  
[TSR]  
****** Unloading program must check that there is nothing here ******        
[Unloading program environment MCB]
[Unloading program environment]
[Unloading program MCB]
[Unloading program]

The unloading program should have a way to communicate with the resident
program in order to get the adress of it's PSP (which will give the adress
of it's MCB). This can be achieved by another captured interrupt which
will return this information. Usually interrupt 2fh (multiplexer) is
used.

For example:

mov       ax,1111h       ;Our tsr's code.
mov       bl,1           ;Service 1 - Request psp adress in ax.
int       2fh            ;The tsr should, of course, contain a handler 
                         ;to handle this function.

push      ax             ;Save tsr's PSP

dec       ax             ;ax points to tsr's MCB.
mov       es,ax
mov       bx,3           ;Offset 3 in MCB - 
add       ax,es:[bx]     ;Pharographs in memory block.
inc       ax             ;Next MCB.

mov       cx,psp_segment ;Our PSP
mov       es,cx
mov       bx,2ch         
mov       cx,es:[bx]     ;Our environment segment
dec       cx             ;Our environment MCB

cmp       ax,cx          ;Is the MCB after the tsr our environment MCB ?
pop       ax             ;Clear stack
jne       Can't uninstall;No - It's unsafe to uninstall

When it's guaranteed that the previous TSR is the last TSR loaded,
it's captured vectors and all other changes to the system should be restored,
and it's code and environment should be removed from memory.


;Return all captured vectors and other system changes to their original
;state.


;Free tsr

pop       ax             ;Tsr's PSP in ax

mov       es,ax          ;ES - Tsr's PSP segment.
mov       bx,2ch
mov       bx,es:[bx]     ;BX - Tsr's environment segment.

mov       ah,49h         ;Free memory block pointed by ES.
int       21h            ;Unload tsr.
jc        Error

mov       es,bx          ;Environment's segment in ES.
mov       ah,49h
int       21h            ;Unload tsr's environment.

I would recommend you to buy the book: 
"The Waite Group's MS-DOS Developer's Guide" from HOWARD W.SAMS & COMPANY.
The MS-DOS memory management and tsrs are explained there in detail, among
other things.

Gadi Oxman
---
 * Origin: => Gadi's point <= Gem bbs, ISRAEL. (RA 2:403/150.6)

