home *** CD-ROM | disk | FTP | other *** search
/ ProfitPress Mega CDROM2 …eeware (MSDOS)(1992)(Eng) / ProfitPress-MegaCDROM2.B6I / UTILITY / SYSTEM / TSRSRC31.ZIP / DISABLE.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1991-11-04  |  16.7 KB  |  528 lines

  1. {**************************************************************************
  2. *   DISABLE - Activates or deactivates TSRs.                              *
  3. *   Copyright (c) 1987,1991 Kim Kokkonen, TurboPower Software.            *
  4. *   May be freely distributed and used but not sold except by permission. *
  5. ***************************************************************************
  6. *   version 2.3 5/4/87                                                    *
  7. *     first release. version number matches other TSR Utilities           *
  8. *   :                                                                     *
  9. *   long intervening history                                              *
  10. *   :                                                                     *
  11. *   version 3.0 9/24/91                                                   *
  12. *     update for DOS 5                                                    *
  13. *     add Quiet option                                                    *
  14. *     add support for high memory                                         *
  15. *   version 3.1 11/4/91                                                   *
  16. *     update for new WATCH detection method                               *
  17. ***************************************************************************
  18. *   telephone: 719-260-6641, CompuServe: 76004,2611.                      *
  19. *   requires Turbo Pascal version 6 to compile.                           *
  20. ***************************************************************************}
  21.  
  22. {$R-,S-,I-,V-,B-,F-,A-,E-,N-,G-,X-}
  23. {$M 2048,0,655360}
  24.  
  25. program DisableTSR;
  26.   {-Deactivate and reactivate memory resident programs}
  27.   {-Leaving them in memory all the while}
  28.  
  29. uses
  30.   Dos,
  31.   MemU;
  32.  
  33. const
  34.   Version = '3.1';
  35.  
  36. var
  37.   Blocks : BlockArray;
  38.   BlockMax : BlockType;
  39.   WatchPsp : Word;
  40.   CommandSeg : Word;
  41.   Changes : ChangeArray;
  42.   ChangeMax, ActualMax, PspHex, StartMCB : Word;
  43.   Action : (aDeactivate, aActivate, aCheckFor);
  44.   Override : Boolean;
  45.   Quiet : Boolean;
  46.   ShowHiMem : Boolean;
  47.   UmbLinkStatus : Boolean;
  48.   TsrName : PathStr;
  49.   SaveExit : Pointer;
  50.   Status : Word;
  51.  
  52.   procedure SafeExit; far;
  53.   var
  54.     Status : Word;
  55.   begin
  56.     ExitProc := SaveExit;
  57.     if HiMemAvailable(DosV) then
  58.       Status := SetUmbLinkStatus(UmbLinkStatus);
  59.   end;
  60.  
  61.   procedure Abort(msg : String; ErrorLevel : Byte);
  62.     {-Halt in case of error}
  63.   begin
  64.     WriteLn(msg);
  65.     Halt(ErrorLevel);
  66.   end;
  67.  
  68.   function ExecutableBlock(PspHex : Word) : Boolean;
  69.     {-Return true if psphex corresponds to an executable code block}
  70.   var
  71.     b : BlockType;
  72.   begin
  73.     for b := BlockMax downto 1 do
  74.       {Search back to find executable rather than environment block}
  75.       if Blocks[b].psp = PspHex then begin
  76.         ExecutableBlock := True;
  77.         Exit;
  78.       end;
  79.     ExecutableBlock := False;
  80.   end;
  81.  
  82.   procedure InitChangeArray(WatchPsp : Word);
  83.     {-Initialize information regarding the WATCH data block}
  84.   var
  85.     watchindex : Word;
  86.     p : ^ChangeBlock;
  87.   begin
  88.     {Maximum offset in WATCH data area}
  89.     ActualMax := MemW[WatchPsp:NextChange];
  90.  
  91.     {Transfer changes from WATCH into a buffer array}
  92.     watchindex := 0;
  93.     ChangeMax := 0;
  94.     while watchindex < ActualMax do begin
  95.       p := Ptr(WatchPsp, ChangeVectors+watchindex);
  96.       Move(p^, Changes[ChangeMax], SizeOf(ChangeBlock));
  97.       Inc(watchindex, SizeOf(ChangeBlock));
  98.       if watchindex < ActualMax then
  99.         inc(ChangeMax);
  100.     end;
  101.   end;
  102.  
  103.   procedure PutWatch(chg : ChangeBlock; var watchindex : Word);
  104.     {-Put a change block back into WATCH}
  105.   var
  106.     p : ^ChangeBlock;
  107.   begin
  108.     p := Ptr(WatchPsp, ChangeVectors+watchindex);
  109.     Move(chg, p^, SizeOf(ChangeBlock));
  110.     Inc(watchindex, SizeOf(ChangeBlock));
  111.   end;
  112.  
  113.   procedure ActivateTSR(PspHex : Word);
  114.     {-Patch out the active interrupt vectors of a specified TSR}
  115.   var
  116.     nextchg, chg, watchindex : Word;
  117.     checking, didsomething : Boolean;
  118.   begin
  119.     didsomething := False;
  120.     watchindex := 0;
  121.     chg := 0;
  122.  
  123.     {Scan looking for the specified PSP}
  124.     while chg <= ChangeMax do begin
  125.       with Changes[chg] do
  126.         case ID of
  127.  
  128.           $FF :               {This record starts a new PSP}
  129.             begin
  130.               checking := (PspAdd = PspHex);
  131.               nextchg := Succ(chg);
  132.               if checking then
  133.                 {Turn off interrupts}
  134.                 inline($FA)
  135.               else
  136.                 {Turn on interrupts}
  137.                 inline($FB);
  138.             end;
  139.  
  140.           $01 :               {This record has an inactive vector redefinition}
  141.             if checking then begin
  142.               {We're in the proper PSP}
  143.               didsomething := True;
  144.               {Change the ID to indicate that vector is active}
  145.               ID := 0;
  146.               {Put the original vector code back in place}
  147.               nextchg := Succ(chg);
  148.               if (Changes[nextchg].ID <> 2) or (Changes[nextchg].VecNum <> VecNum) then
  149.                 Abort('Program error in Activate, patch record not found', 255);
  150.               {Restore the patched over code}
  151.               Move(Changes[nextchg].SaveCode, Mem[VecSeg:VecOfs], 6);
  152.               {Don't output the following patch record}
  153.               inc(nextchg);
  154.             end else
  155.               nextchg := Succ(chg);
  156.  
  157.         else
  158.           nextchg := Succ(chg);
  159.         end;
  160.  
  161.       {Put the change block back into WATCH}
  162.       PutWatch(Changes[chg], watchindex);
  163.       {Advance to the next change record}
  164.       chg := nextchg;
  165.     end;
  166.  
  167.     {Store the count back into WATCH}
  168.     MemW[WatchPsp:NextChange] := watchindex;
  169.  
  170.     if not(didsomething) then
  171.       Abort('No changes were needed to activate '+HexW(PspHex), 1);
  172.  
  173.   end;
  174.  
  175.   procedure DeactivateTSR(PspHex : Word);
  176.     {-Patch out the active interrupt vectors of a specified TSR}
  177.   var
  178.     newchange : ChangeBlock;
  179.     chg, watchindex, curpsp : Word;
  180.     putrec, checking, didsomething : Boolean;
  181.  
  182.     procedure PutPatch(vecn : Byte; vecs, veco, curpsp : Word);
  183.       {-Patch vector entry point with JMP to previous controlling vector}
  184.     label
  185.       ExitPoint;
  186.     var
  187.       vec : ^Word;
  188.       chg : Word;
  189.     begin
  190.       {Get the original vector from WATCH}
  191.       Move(Mem[WatchPsp:(OrigVectors+(vecn shl 2))], vec, 4);
  192.  
  193.       {Scan the Changes array to look for redefinition of this vector}
  194.       for chg := 0 to ChangeMax do begin
  195.         with Changes[chg] do
  196.           case ID of
  197.             0, 1 :            {This is or was a redefined vector}
  198.               if vecn = VecNum then
  199.                 {It's the vector we're interested in}
  200.                 {Store the latest value of the vector}
  201.                 Move(VecOfs, vec, 4);
  202.             $FF :             {This record starts a new PSP}
  203.               if PspAdd = curpsp then
  204.                 {Stop when we get to the PSP that is being disabled}
  205.                 goto ExitPoint;
  206.           end;
  207.       end;
  208. ExitPoint:
  209.       {Patch the vector entry point into a JMP FAR vec}
  210.       Mem[vecs:veco] := $EA;
  211.       Move(vec, Mem[vecs:Succ(veco)], 4);
  212.     end;
  213.  
  214.     function CountVecs(chg : Word) : Word;
  215.       {-Return count of vectors taken over by the PSP starting at changeblock chg}
  216.     var
  217.       count : Word;
  218.       ID : Byte;
  219.     begin
  220.       count := 0;
  221.       repeat
  222.         {Skip over the first one, which defines the current PSP}
  223.         inc(chg);
  224.         ID := Changes[chg].ID;
  225.         if (ID = 0) and (chg <= ChangeMax) then
  226.           inc(count);
  227.       until (ID = $FF) or (chg >= ChangeMax);
  228.       CountVecs := count;
  229.     end;
  230.  
  231.     function ValidToPatch(chg : Word) : Boolean;
  232.       {-Assure that there is space to place 6-byte patches}
  233.     var
  234.       First : Word;
  235.       Next : Word;
  236.       I : Word;
  237.       J : Word;
  238.       IAddr : LongInt;
  239.       JAddr : LongInt;
  240.     begin
  241.       ValidToPatch := True;
  242.       if Override then
  243.         Exit;
  244.  
  245.       {First vector to patch}
  246.       First := chg+1;
  247.  
  248.       {Last vector to patch}
  249.       Next := First;
  250.       while (Next <= ChangeMax) and (Changes[Next].ID <> $FF) do
  251.         inc(Next);
  252.  
  253.       {Any to patch?}
  254.       if Next = First then
  255.         Exit;
  256.  
  257.       {Compare each pair to assure enough space for patch}
  258.       for I := First to Next-1 do begin
  259.         with Changes[I] do
  260.           IAddr := (LongInt(VecSeg) shl 4)+VecOfs;
  261.         for J := First to Next-1 do
  262.           if I <> J then begin
  263.             with Changes[J] do
  264.               JAddr := (LongInt(VecSeg) shl 4)+VecOfs;
  265.             if Abs(IAddr-JAddr) < 6 then begin
  266.               ValidToPatch := False;
  267.               Exit;
  268.             end;
  269.           end;
  270.       end;
  271.     end;
  272.  
  273.   begin
  274.  
  275.     {Scan looking for the specified PSP}
  276.     didsomething := False;
  277.     watchindex := 0;
  278.  
  279.     for chg := 0 to ChangeMax do begin
  280.       putrec := True;
  281.       with Changes[chg] do
  282.         case ID of
  283.  
  284.           $FF :               {This record starts a new PSP}
  285.             begin
  286.               checking := (PspAdd = PspHex);
  287.               if checking then begin
  288.                 {Store the current PSP}
  289.                 curpsp := PspAdd;
  290.                 {Make sure WATCH has room for the extra changes}
  291.                 if watchindex+(CountVecs(chg)*SizeOf(ChangeBlock)) >
  292.                 MaxChanges*SizeOf(ChangeBlock) then
  293.                   Abort('Insufficient space in WATCH data area', 255);
  294.                 {Make sure the patches will be valid}
  295.                 if not ValidToPatch(chg) then
  296.                   Abort('Insufficient space between vectors to patch TSR', 255);
  297.                 {Turn off interrupts}
  298.                 inline($FA);
  299.               end else
  300.                 {Turn on interrupts}
  301.                 inline($FB);
  302.             end;
  303.  
  304.           $00 :               {This record has an active vector redefinition}
  305.             if checking then begin
  306.               {We're in the proper PSP}
  307.               didsomething := True;
  308.  
  309.               {Change the ID to indicate that vector is inactive}
  310.               ID := 1;
  311.               {Output the record now so that the new record can immediately follow}
  312.               PutWatch(Changes[chg], watchindex);
  313.               putrec := False;
  314.  
  315.               {Output a new change record so we can reactivate later}
  316.               {Indicate this is a patch record}
  317.               newchange.ID := 2;
  318.               {Save which vector it goes with}
  319.               newchange.VecNum := VecNum;
  320.               {Save the code we'll patch over}
  321.               Move(Mem[VecSeg:VecOfs], newchange.SaveCode, 6);
  322.               {Output the record to the WATCH area}
  323.               PutWatch(newchange, watchindex);
  324.               {Patch in a JMP to the previous vector}
  325.               PutPatch(VecNum, VecSeg, VecOfs, curpsp);
  326.             end;
  327.  
  328.         end;
  329.       if putrec then
  330.         {Put the change block back into WATCH}
  331.         PutWatch(Changes[chg], watchindex);
  332.     end;
  333.  
  334.     {Store the count back into WATCH}
  335.     MemW[WatchPsp:NextChange] := watchindex;
  336.  
  337.     if not(didsomething) then
  338.       Abort('No changes were needed to deactivate '+tsrname, 1);
  339.  
  340.   end;
  341.  
  342.   procedure CheckUpperOption;
  343.     {-Set ShowHiMem option}
  344.   var
  345.     arg : String[127];
  346.     i : Word;
  347.   begin
  348.     ShowHiMem := False;
  349.     for I := 1 to ParamCount do begin
  350.       arg := StUpcase(ParamStr(i));
  351.       if (arg = '-U') or (arg = '/U') then begin
  352.         ShowHiMem := True;
  353.         Exit;
  354.       end;
  355.     end;
  356.   end;
  357.  
  358.   procedure GetOptions;
  359.     {-Analyze command line for options}
  360.   var
  361.     arg : String[127];
  362.     arglen : Byte absolute arg;
  363.     i, code : Word;
  364.  
  365.     procedure WriteCopyright;
  366.     begin
  367.       WriteLn('DISABLE ', Version, ', Copyright 1991 TurboPower Software');
  368.     end;
  369.  
  370.     procedure WriteHelp;
  371.       {-Show the options}
  372.     begin
  373.       WriteCopyright;
  374.       WriteLn;
  375.       WriteLn('DISABLE allows you to selectively disable and reenable a TSR while leaving it');
  376.       WriteLn('in memory. To run DISABLE, you must have previously installed the TSR utility');
  377.       WriteLn('WATCH.');
  378.       WriteLn;
  379.       WriteLn('DISABLE is command-line driven. You specify a single TSR by its name (if you');
  380.       WriteLn('are running DOS 3.0 or later) or by its address as determined from a MAPMEM');
  381.       WriteLn('report. Addresses must be preceded by a dollar sign "$" and specified in hex.');
  382.       WriteLn;
  383.       WriteLn('DISABLE accepts the following command line syntax:');
  384.       WriteLn;
  385.       WriteLn('  DISABLE TSRname|$PSPaddress [Options]');
  386.       WriteLn;
  387.       WriteLn('Options may be preceded by either / or -. Valid options are as follows:');
  388.       WriteLn;
  389.       WriteLn('     /A     reactivate the specified TSR.');
  390.       WriteLn('     /C     check whether TSR is installed.');
  391.       WriteLn('     /O     disable the TSR even if dangerous (Override).');
  392.       WriteLn('     /Q     write no screen output.');
  393.       WriteLn('     /U     work with upper memory blocks (DOS 5).');
  394.       WriteLn('     /?     write this help screen.');
  395.       Halt(1);
  396.     end;
  397.  
  398.     function FindOwner(name : String) : Word;
  399.       {-Return segment of executable block with specified name}
  400.     var
  401.       b : BlockType;
  402.     begin
  403.       name := StUpcase(name);
  404.       {Scan the blocks in reverse order}
  405.       for b := BlockMax downto 1 do
  406.         with Blocks[b] do
  407.           if Succ(mcb) = psp then
  408.             {This block is an executable block}
  409.             if NameFromEnv(Ptr(mcb, 0)) = name then begin
  410.               {Found it}
  411.               FindOwner := psp;
  412.               Exit;
  413.             end else if DosV >= 5 then
  414.               if NameFromMcb(Ptr(Mcb, 0)) = name then begin
  415.                 {Found it}
  416.                 FindOwner := psp;
  417.                 Exit;
  418.               end;
  419.       FindOwner := $FFFF;
  420.     end;
  421.  
  422.   begin
  423.     {Initialize defaults}
  424.     PspHex := 0;
  425.     Action := aDeactivate;
  426.     Override := False;
  427.     Quiet := False;
  428.  
  429.     i := 1;
  430.     while i <= ParamCount do begin
  431.       arg := ParamStr(i);
  432.       if (arg[1] = '?') then
  433.         WriteHelp
  434.       else if (arg[1] = '-') or (arg[1] = '/') then
  435.         case arglen of
  436.           1 : Abort('Missing command option following '+arg, 254);
  437.           2 : case UpCase(arg[2]) of
  438.                 '?' : WriteHelp;
  439.                 'A' : Action := aActivate;
  440.                 'C' : Action := aCheckFor;
  441.                 'E' : Action := aActivate;
  442.                 'O' : Override := True;
  443.                 'Q' : Quiet := True;
  444.                 'U' : ; {ignore, but allow, here}
  445.               else
  446.                 Abort('Unknown command option: '+arg, 254);
  447.               end;
  448.         else
  449.           Abort('Unknown command option: '+arg, 254);
  450.         end
  451.       else begin
  452.         {TSR to change}
  453.         if arg[1] = '$' then begin
  454.           {Treat as hex address}
  455.           Val(arg, PspHex, code);
  456.           if code <> 0 then
  457.             Abort('Invalid hex address specification: '+arg, 254);
  458.         end else if DosV >= 3 then
  459.           {Treat as PSP owner name - scan to find proper PSP}
  460.           PspHex := FindOwner(arg)
  461.         else
  462.           Abort('Must have DOS 3.0+ to find TSRs by name', 254);
  463.         TsrName := StUpcase(arg);
  464.       end;
  465.       inc(i);
  466.     end;
  467.  
  468.     if not Quiet then
  469.       WriteCopyright;
  470.     if PspHex = 0 then
  471.       Abort('No TSR name or address specified', 254)
  472.     else if PspHex = $FFFF then
  473.       Abort('No such TSR found', 2);
  474.   end;
  475.  
  476. begin
  477.   {Determine whether upper memory control is desired}
  478.   CheckUpperOption;
  479.  
  480.   {Set up for high memory access}
  481.   if HiMemAvailable(DosV) then begin
  482.     UmbLinkStatus := GetUmbLinkStatus;
  483.     Status := SetUmbLinkStatus(ShowHiMem);
  484.     if ShowHiMem and (Status = 1) then
  485.       Abort('To access high memory you must have DOS=[HIGH,]UMB in CONFIG.SYS', 255);
  486.   end;
  487.   SaveExit := ExitProc;
  488.   ExitProc := @SafeExit;
  489.  
  490.   {Get all allocated memory blocks in normal memory}
  491.   {Must do first to support TSRs by name in GetOptions}
  492.   FindTheBlocks(Blocks, BlockMax, StartMcb, CommandSeg);
  493.  
  494.   {Analyze command line for options}
  495.   GetOptions;
  496.  
  497.   {Find the watch block}
  498.   WatchPsp := WatchPspSeg;
  499.   if WatchPsp = 0 then
  500.     Abort('WATCH must be installed in order to use DISABLE', 255);
  501.  
  502.   {Assure PspHex corresponds to an executable block}
  503.   if not ExecutableBlock(PspHex) then
  504.     Abort('No such TSR found', 2);
  505.  
  506.   {Initialize information regarding the WATCH data block}
  507.   InitChangeArray(WatchPsp);
  508.  
  509.   {Activate or deactivate the TSR}
  510.   case Action of
  511.     aDeactivate:DeactivateTSR(PspHex);
  512.     aActivate:ActivateTSR(PspHex);
  513.   end;
  514.  
  515.   {Write success message}
  516.   if not Quiet then begin
  517.     case Action of
  518.       aDeactivate:Write('Deactivated');
  519.       aActivate:Write('Activated');
  520.       aCheckFor:Write('Found');
  521.     end;
  522.     Write(' ');
  523.     if TsrName[1] = '$' then
  524.       Write('TSR at ');
  525.     WriteLn(TsrName);
  526.   end;
  527. end.
  528.