home *** CD-ROM | disk | FTP | other *** search
- ; This code illustrates how to install and deinstall a TSR and under what
- ; circumstances the body of a TSR should be given control.
- ;
- ; The hot keys in this example are the Alt + Left Shift keys. This hot key
- ; combination is defined in the variable hot_keys and can be changed to suit
- ; the user by changing the bit pattern.
- ;
- ; This example is intended to illustrate the recommendations made in the
- ; following articles:
- ;
- ; "DOS: Terminate and Stay Resident", M. Steven Baker
- ; Programmer's Journal, Nov/Dec 1986, pages 26 - 30
- ;
- ; "Coding Guidelines for Resident Programs", Graham Pearson
- ; Programmer's Journal, Mar/Apr 1987, pages 34 - 38
- ;
- ;
- ; The author can be reached at the following address:
- ; Kudos Software, 9111 Cadawac Road, Houston, Texas 77074
- ; Tel: (713) 774-6108
-
- ;******************************************************************************
-
- DELAY_COUNT EQU 36 ;Timer counts between hot key triggers
- ;36 ticks = approx. 2 seconds
-
- ; Locations of BIOS Data needed by the resident program
-
- bios_data segment at 40H
- org 17H ;Keyboard status flags
- kbd_status dw ?
- org 6CH ;Timer count - low word. This rolls
- low_timer dw ? ;around 0FFFFH once per hour
- bios_data ends
-
- ;------------------------------------------------------------------------------
-
- code segment
- assume cs:code, ds:nothing, es:nothing, ss:nothing
- org 100H ;Define starting point for .COM file
-
- entry_point:
- jmp install ;Skip over the code to be made resident
-
- ;------------------------------------------------------------------------------
-
- hot_keys dw 01010B ;Hot key bits -> Alt + Left Shift
-
- this_time dw ? ;Most-recent time hot keys detected
- trig_time dw ? ;Last time resident code was triggered
-
- dos_busy label dword ;Pointer to "DOS is busy" flag
- dos_busy_off dw ? ;These values are initialized during
- dos_busy_seg dw ? ;the "install" process
-
- criterr_flag dw ? ;Used by diverted INT 24H
-
- ;------------------------------------------------------------------------------
-
- ; Replacement for INT 24H - critical DOS error
-
- diverted_int24:
-
- mov cs:criterr_flag,0FFFFH ;Switch error flag ON
- xor al,al ;Tell DOS to ignore the error
- iret ;Return to DOS
-
- int_24_vect label dword
- int_24_off dw ? ;These values are initialized each time
- int_24_seg dw ? ;the TSR body takes control
-
- ;------------------------------------------------------------------------------
-
- ; Replacement for INT 9 - keyboard hardware interrupt
-
- diverted_int9:
-
- pushf ;Simulate an INT 9 to pass through the
- call_int9 db 09AH ;original BIOS interrupt handler
- int_9_vect label dword
- int_9_off dw ? ;These values are initialized during
- int_9_seg dw ? ;the "install" process
-
- push ds ;Save all registers used by this
- push bx ;section of code
- lds bx,dos_busy ;See if DOS is busy
- cmp byte ptr [bx],0
- pop bx ;Restore all registers
- pop ds
- jz get_bios_data ;Zero means DOS is not busy
-
- dos_is_busy:
- iret ;Return control to interrupted process
-
- ;------------------------------------------------------------------------------
-
- ; Replacement for INT 28 - generated by DOS, esp. during keyboard I/O functions
-
- diverted_int28:
-
- pushf ;Simulate an INT 28H to pass through
- call_int28 db 09AH ;the original DOS interrupt handler
- int_28_vect label dword
- int_28_off dw ? ;These values are initialized during
- int_28_seg dw ? ;the "install" process
-
- ;------------------------------------------------------------------------------
-
- get_bios_data:
-
- sti ;Restore interrupts
- push ds ;Save all registers used by this
- push bx ;section of code
-
- mov bx,bios_data ;Retrieve BIOS Data values
- mov ds,bx
- assume ds:bios_data
-
- mov bx,low_timer ;Retrieve and save timer count
- mov cs:this_time,bx
- mov bx,kbd_status ;Retrieve keyboard status bits
-
- push cs ;Point DS to our code segment
- pop ds
- assume ds:code
-
- chk_keys:
- and bx,hot_keys ;See if hot keys are pressed
- cmp bx,hot_keys
- jne back_to_applic
-
- chk_timer:
- mov bx,this_time
- cmp bx,trig_time ;Enter resident routine if timer
- jb time_is_right ;count has rolled around the hour
-
- sub bx,trig_time
- sub bx,DELAY_COUNT ;Transfer to resident code only if
- jnc time_is_right ;elapsed time between hot keys is
- ;greater than delay count
- back_to_applic:
- pop bx ;Restore all registers
- pop ds
- iret ;Return control to interrupted process
-
- ;------------------------------------------------------------------------------
-
- time_is_right:
- mov bx,this_time ;Update latest trigger time
- mov trig_time,bx
- pop bx ;Restore all registers
- pop ds
-
- ;******************************************************************************
-
- ; This is the start of the application-dependent resident code
-
- start_program:
-
- push ax ;Save all registers used by the
- push bx ;resident application
- push cx
- push dx
- push si
- push di
- push bp
- push ds
- push es
-
- push cs ;Point DS to our CS
- pop ds
-
- mov ax,3524H ;Get current INT 24H vector
- int 21H
- mov int_24_off,bx
- mov int_24_seg,es
- mov ax,2524H ;Redirect INT 24H
- mov dx,offset diverted_int24
- int 21H
-
-
- ;******************************************************************************
-
- ; Include application specific code here
-
- ;******************************************************************************
-
-
- restore_int24:
- lds dx,int_24_vect ;Restore INT 24H
- mov ax,2524H ;Error in PJ listing (was 2509H)
- int 21H
-
- pop es ;Restore all registers
- pop ds
- pop bp
- pop di
- pop si
- pop dx
- pop cx
- pop bx
- pop ax
- iret ;Return control to interrupted process
-
- ; This is the end of the application-dependent resident code
-
- end_of_res label word
-
- ;******************************************************************************
-
- ; This procedure installs the resident section of code in memory.
- ; It performs the following tasks:
- ;
- ; 1 Make sure the operating system is at least DOS 2.00
- ;
- ; 2 Make sure the resident code is not already installed in memory
- ; If it IS already installed, remove it from memory
- ;
- ; 3 Retrieve an available vector for installing the signature
- ;
- ; 4 Retrieve vector to "DOS is busy" and save it for use by resident code
- ;
- ; 5 Update the interrupt vectors required by resident code.
- ;
- ; 6 Install the signature in the available vector found in step 3
- ;
- ; 7 Terminate and stay resident - transfer control back to DOS
-
- ;------------------------------------------------------------------------------
-
- install:
-
- ; Make sure that the operating system is at least DOS 2.00
-
- mov ah,30H
- int 21H
- or al,al
- jnz chk_vectors
-
- mov dx,offset baddos_msg ;DS:DX -> Display "bad DOS" message
- mov ah,9
- int 21H
-
- int 20H ;Return to DOS the old-fashioned way
-
- ;------------------------------------------------------------------------------
-
- ; See if the resident code is already installed in memory.
- ; If so, remove the resident code from memory.
- ; If not, retain an available interrupt vector for later use as a signature.
-
- chk_vectors:
- push ds ;Save DS -> CS
-
- xor ax,ax ;Search 32 interrupt vectors starting
- mov ds,ax ;at INT 60H - user interrupt area
- mov si,60H * 4
- mov cx,20H
-
- next_vector:
- mov ax,[si + 2]
- or ax,ax ;If segment value is zero, get offset
- jz get_vect_off ;value
-
- cmp ax,0D0C7H ;Check interrupt segment value against
- jne vector_loop ;resident code signature
-
- deinstall:
- mov bx,[si] ;Retrieve original resident code
- ;segment value
- xor ax,ax
- mov [si],ax ;Remove signature from the
- mov [si + 2],ax ;interrupt vector
-
- restore_int9:
- mov ds,bx ;DS -> original resident code segment
- lds dx,int_9_vect ;Restore INT 9 - keyboard I/O
- mov ax,2509H
- int 21H
-
- restore_int28:
- mov ds,bx ;DS -> original resident code segment
- lds dx,int_28_vect ;Restore INT 28 - DOS interrupt
- mov ax,2528H
- int 21H
-
- mov es,bx ;ES -> code segment to be deinstalled
- mov ah,49H
- int 21H ;Free allocated memory
-
- mov es,es:[2CH] ;ES -> environment to be deinstalled
- mov ah,49H
- int 21H ;Free allocated memory
-
- pop ds ;Restore DS -> CS
- mov dx,offset remove_msg ;DS:DX -> Display "remove" message
- mov ah,9
- int 21H
-
- mov ax,4C01H ;Return error code of 1
- int 21H ;Return to DOS with error code
-
- get_vect_off:
- cmp word ptr [si],0 ;If offset value is zero, this vector
- je found_vector ;is available for our use
-
- vector_loop:
- add si,4 ;Interrogate next vector
- loop next_vector
-
- found_vector:
-
- ;Make sure we successfully complete the install process before
- ;installing the signature in this available interrupt vector
-
- pop ds ;Restore Data Segment
- mov free_vector,si ;Save free vector for later
-
- ;------------------------------------------------------------------------------
-
- ; Retrieve original interrupt vectors and install these in the resident code.
- ; Redirect the interrupt vectors to point to resident code.
- ; Install signature in available interrupt vector.
-
- push es ;Save ES -> CS
-
- mov ah,34H ;Retrieve segment + offset
- int 21H ;pointer to "DOS is busy" flag
- mov dos_busy_off,bx
- mov dos_busy_seg,es
-
- mov ax,3509H ;Get current INT 9H vector
- int 21H
- mov int_9_off,bx
- mov int_9_seg,es
- mov ax,2509H ;Redirect INT 9H
- mov dx,offset diverted_int9
- int 21H
-
- mov ax,3528H ;Get current INT 28H vector
- int 21H
- mov int_28_off,bx
- mov int_28_seg,es
- mov ax,2528H ;Redirect INT 28H
- mov dx,offset diverted_int28
- int 21H
-
- pop es ;Restore ES -> CS
- mov di,free_vector ;Retrieve value found earlier
-
- push ds ;Save DS -> CS
- xor ax,ax ;DS -> interrupt vectors
- mov ds,ax
- mov [di],cs ;Install signature in the available
- mov word ptr [di+2],0D0C7H ;interrupt vector
- pop ds ;Restore DS -> CS
-
- ;------------------------------------------------------------------------------
-
- ; Display installed message
-
- mov dx,offset success_msg ;DS:DX -> Display "success" message
- mov ah,9
- int 21H
-
- ;------------------------------------------------------------------------------
-
- ; Prepare for program "terminate and stay resident"
-
- mov dx,offset end_of_res ;Calculate the amount of memory used
- dec dx ;by the resident code
- or dx,0FH
- inc dx ;Round up to the nearest paragraph
-
- mov cl,4 ;Convert code size to paragraphs
- shr dx,cl
- mov ax,03100H ;Return error code of 0
- int 21H ;Terminate but stay resident
-
- ;------------------------------------------------------------------------------
-
- free_vector dw ? ;Pointer to available interrupt vector
-
- copyright db ' Copyright (c) 1986 Kudos Software '
-
- baddos_msg db 'TSR will not run with DOS 1.XX'
- db 0DH, 0AH, '$'
-
- remove_msg db 'TSR is no longer resident in memory'
- db 0DH, 0AH,'$'
-
- success_msg db 'TSR successfully installed in memory'
- db 0DH, 0AH, '$'
-
- ;------------------------------------------------------------------------------
-
- code ends
- end entry_point ;Define entry point for .COM file