{***********************************************************************}
{									}
{ __RemPgm    Remove a resident program from memory			}
{									}
{ procedure __RemPgm(	ProgSeg : word, 				}
{		     CheckHooks : boolean;				}
{		    var ParsRem,					}
{		      ErrorCode : word);				}
{									}
{	      ProgSeg	The program segment of the program to be	}
{			removed from memory.				}
{	      CheckHooks						}
{			If set to TRUE, __RemPgm will not removed the	}
{			program from memory if there are interrupt	}
{			vectors hooked by the program.	If it finds	}
{			a hooked vector, the vector number is returned	}
{			in the low byte of the error code.  If set to	}
{			FALSE, no checking for hooked vectors is done.	}
{	      ParsRem	If the program is removed from memory, the	}
{			number of paragraphs of memory released back to }
{			DOS is returned in this parameter.  If the	}
{			program cannot be removed, the value returned	}
{			is zero.					}
{	      ErrorCode Returned error code.  The possible values are:	}
{			0 - Program successfully removed from memory.	}
{			1 - ProgSeg does not represent a program seg-	}
{			    ment.  No action is taken, 0 is returned	}
{			    in ParsRem. 				}
{			7 - DOS memory control blocks destroyed when	}
{			    trying to free memory.  This error is	}
{			    returned by __FreeMem, but should not occur.}
{			9 - Invalid memory block address when trying to }
{			    free memory.  This error is returned by	}
{			    __FreeMem, but should not occur.		}
{			$10xx - The program cannot be removed because	}
{			    ChecksHooks is TRUE and a hooked vector	}
{			    was found.	The vector number is returned	}
{			    in the low order byte of ErrorCode. 	}
{									}
{ Description This procedure removes a resident program by releasing	}
{	      all memory blocks allocated by the program back to DOS.	}
{	      __RemPgm first checks that ProgSeg is the program segment }
{	      of some program (the program must be the owner of the	}
{	      associated memory control block).  If CheckHooks is TRUE, }
{	      __RemPgm next checks that no interrupt vector between 0	}
{	      and $7F is hooked by the program (see __HookMem).  If	}
{	      both conditions are satisfied, all DOS memory control	}
{	      blocks are inspected, and the memory blocks owned by the	}
{	      program are freed.  The total number of freed paragraphs	}
{	      is returned in ParsRem.					}
{									}
{ Version     4.00 (C)Copyright Blaise Computing Inc.  1987		}
{_______________________________________________________________________}

procedure __RemPgm(   ProgSeg : word;
		   CheckHooks : boolean;
		  var ParsRem,
		    ErrorCode : word);

  var
    NextPtr   : pointer;
    MemPtr    : pointer;
    ProgBlock : _MemCtrl;
    HookVecNo : integer;

  begin {__RemPgm}

    ParsRem   := 0;		       { Initialize the return values.	}
    ErrorCode := 0;

    { First make sure that ProgSeg is the segment address of a memory	}
    { block, and that the memory block is a program segment.  __CtrlMem }
    { returns a control block of zeros if ProgSeg is not the segment	}
    { of a block.  Moreover, if it does represent a memory block, it is }
    { not a program segment unless the owner is ProgSeg.		}

    NextPtr := __CtrlMem(Ptr(ProgSeg,0),ProgBlock);
    with ProgBlock do
      if ((_Header = #0) or (_OwnerPSP <> ProgSeg)) then
	 begin			       { ProgSeg is not the segment of	}
	   ErrorCode := 1;	       { a program segment.		}
	   Exit
	 end;

    { Now if CheckHooks is TRUE, make sure that no vector is hooked by	}
    { the program.  __HookMem starts the search for a hooked vector	}
    { at vector number 0 and continues to vector $FF.  If a vector is	}
    { not found, __HookMem returns -1 in the parameter HookVecNo.	}

    if (CheckHooks) then
       begin
	 HookVecNo := 0;
	 __HookMem(ProgSeg,HookVecNo);
	 if ((HookVecNo >= 0) and (HookVecNo <= $7F)) then
	    begin
	      ErrorCode := __2WordSup($10,Lo(HookVecNo));
	      Exit
	    end
       end;

    { Finally search through all DOS memory blocks, releasing the ones	}
    { belonging to ProgSeg.						}

    MemPtr := __FirstMem;
    while (MemPtr <> NIL) do
      begin
	NextPtr := __CtrlMem(MemPtr,ProgBlock);
	with ProgBlock do
	  if (_OwnerPSP = ProgSeg) then
	     begin
	       __FreeMem(MemPtr,ErrorCode);
	       if (ErrorCode <> 0) then
		  Exit
	       else
		  Inc(ParsRem,_Size)
	     end;
	MemPtr := NextPtr
      end

  end;	{__RemPgm}
