Program EuroTSR; {$S-} {$M 1024, 0, 0} uses Dos; const SwConst:word=$1234; {This variable MUST always have same value in EURO and in EUROTSR} var CPURegisters: Registers; { General register structure for Intr calls. } MadeActive: Boolean; { TRUE if this TSR has been asked to pop up. } PInt09: Pointer; { Saved address of keyboard handler. } PInt12: Pointer; { Saved address of GetMemorySize interrupt. } PInt28: Pointer; { Saved address of background task scheduler. } PInDosFlag: ^Word; { Points to DOS's InDos flag. } TempPtr: Pointer; { Used internally to DoUnInstall. } TSRInUse: Boolean; { Set TRUE during processing to avoid double activation. } PSPPtr : ^Word; {Allocates a pointer to PSP} procedure BackgroundInt; interrupt; begin { Call saved INT 28H handler. } asm PUSHF CALL PInt28 end; if MadeActive then begin TSRInUse := True; MadeActive := False; asm MOV AH,5h MOV CH,12h MOV CL,159 INT 16h end; TSRInUse := False; end; end; {BackgroundInt} procedure KeyboardInt; interrupt; begin if not TSRInUse then if (MEM[$40:$17] and 8) = 8 then {These two: AltGr (RightALT)} if (MEM[$40:$18] and 2) = 0 then if Port[$60]=$12 then {This one: Key E make code} begin TSRInUse := True; if (PInDosFlag^ = 0) then begin {act now} MadeActive := False; asm MOV AH,5h MOV CH,12h MOV CL,159 INT 16h end; TSRInUse := False; end else {act later} MadeActive := True; end; { Call existing keyboard interrupt handler. } asm PUSHF CALL PINT09 end; end; {KeyboardInt} procedure DoUnInstall ( var Removed: Boolean ); forward; var MessageNum : Integer; DeInstallOk: Boolean; procedure OurInt12 (_AX, BX, CX, DX, SI, DI, DS, ES, BP:Word); interrupt; begin {1.- if DX=SWCOnst then message for us. Otherwise, normal DOS call} If DX = SwConst Then MessageNum := CX else begin MessageNum := 0; asm pushf call PInt12 mov _AX, ax {return memory size in _AX} end; end; {2.- Message for us? Then interpretate} if MessageNum > 0 then case lo(MessageNum) of 1: DX := Swap (DX); {I'm here!!!} 2: begin { Performs request to uninstall the TSR. } DoUnInstall (DeInstallOk); DX := ord(not DeInstallOk); End; End; end; procedure DoUnInstall ( var Removed: Boolean ); begin Removed := True; {1.- Check if no other TSR has installed afterwards} GetIntVec( $28, TempPtr ); if TempPtr <> @BackgroundInt then Removed := False; GetIntVec( $12, TempPtr ); If TempPtr <> @OurInt12 then Removed := False; GetIntVec( $09, TempPtr ); if TempPtr <> @KeyBoardInt then Removed := False; {2.- YES: then restore everything} if Removed then begin { Restore interrupts } SetIntVec( $28, PInt28 ); SetIntVec( $12, PInt12 ); SetIntVec( $09, PInt09 ); { Free up memory allocated to this program using INT 21 Func=49H "Release memory". } CPURegisters.AH := $49; CPURegisters.ES := PrefixSeg;{ Current program's PSP } Intr( $21, CPURegisters ); end; end; BEGIN {1.- Set controlling variables} MadeActive := False; TSRInUse := False; {2.- Deallocate DOS Environment block to save memory} PSPPtr := Ptr( PrefixSeg, $2C ); CPURegisters.AX := $4900; CPURegisters.ES := PSPPtr^; Intr( $21, CPURegisters); {3.- Initialize pointer to DOS's InDos flag. } CPURegisters.AH := $34; Intr( $21, CPURegisters ); PInDosFlag := Ptr( CPURegisters.ES, CPURegisters.BX ); {4.- Save old interrupt controllers} asm cli end; {INT 12h: Return free memory} GetIntVec( $12, PInt12 ); SetIntVec( $12, @OurInt12 ); {INT 28h: iddle proccesses} GetIntVec( $28, PInt28 ); SetIntVec( $28, @BackgroundInt ); {INT 09h: Keyboard} GetIntVec( $09, PInt09 ); SetIntVec( $09, @KeyboardInt ); asm sti end; {5.- Leave it resident} Keep(0); END.