; NOTE : This template is for .COM files only do not use for .EXE files!! ; ; ; ; Copyright 1986 by Dana Nowell - All rights reserved ; ; HISTORY: ; Version Date Name Description ; 1.0 11/10/86 dn first cut ; 1.01 11/21/86 dn Fixed memory allocation bug ; Added installation message ; title TSR Template NULL equ 00h BELL equ 07h ; bell character BACKSPACE equ 08h ; backspace character TAB equ 09h ; tab character LF equ 0ah ; line feed F_FEED equ 0ch ; form feed CR equ 0dh ; carriage return EOF equ 1ah ; ctrl z ( end of file ) SPACE equ ' ' ; ascii space character QUOTE equ '"' SIGNATURE1 equ 6144h ; used for already SIGNATURE2 equ 616eh ; resident check DOS_INT equ 21h ; DOS function interrupt DISP_CHAR equ 02h GET_KEY equ 08h DOS_SCR_MSG equ 09h DOS_SET_INT equ 25h DOS_RESIDENT equ 31h DOS_GET_INT equ 35h DOS_TERMINATE equ 4ch DOS_STRING_TERM equ '$' ; Interrupt vectors used HOOK_INT equ 1ch ; interrupt to be hooked ( timer tick now ) ;------------------------------------------------------------------------------ ; ; MACRO SECTION ; ;------------------------------------------------------------------------------ Version_msg macro jmp short copyright_end copyright_msg db CR, LF db 'TSR Shell - Version 1.01', CR, LF db 'Copyright 1986, Dana Nowell ', CR, LF, CR, LF db 'May be distributed without license', CR, LF, '$' copyright_end: Msg copyright_msg endm Msg macro ptr push dx push ax lea dx, ptr mov ah, 09h int 21h pop ax pop dx endm com segment para public 'code' assume cs:com, ds:com, es:com ;------------------------------------------------------------------------------ ; ; note: The PSP occurs at the beginning of the code segment ; for all programs. In COM files the code seg = data seg ; ;------------------------------------------------------------------------------ org 0 psp_start dw ? ; int 20h - possibly a block for unresolved ; externals during link ? mem_size dw ? ; size of available memory in paragraphs filler db ? ; reserved usually zero dos_call db ? ; call dd ? ; address of dos function handler term_vector dd ? ; address of dos terminate routine break_vector dd ? ; address of dos break routine error_vector dd ? ; address of dos error routine dos_reserved db 2 dup(?); reserved by dos dos_handles db 20 dup(?) ; file handle array environ_ptr dw ? ; seg of dos environment ( offset = 0 ) dos_work db 34 dup(?) ; dos work area int_21h db ? ; int db ? ; 21h db ? ; retf ( return far ) reserved dw ? ; reserved by dos fcb1_ext db 7 dup(?) ; fcb # 1 extension fcb1 db 9 dup(?) ; fcb #1 fcb2_ext db 7 dup(?) ; fcb # 2 extension fcb2 db 20 dup(?) ; fcb #2 ; ; disk transfer area ( dta ) and parameter block occupy the same space ; ; ;dta db 128 dup(?) ; disk transfer area param_len db ? ; length of parameter string ( excludes CR ) parameters db 127 dup(?) ; parameters ;------------------------------------------------------------------------------ ; ; Note on standard fcb structure : ; ; The standard FCB is larger than the size reserved in the PSP if you ; intend to use to FCB data from the PSP move it to a different location. ; ; ; STANDARD STRUCTURE OF A FILE CONTROL BLOCK ; ; ; extension : ; offset length description ; -7 1 extension active flag ( 0ffh = active ) ; -6 5 normally unused should be zeros ; -1 1 file attribute when extension is active ; 1 . . . . . . . 1 read-only ; 2 . . . . . . 1 . hidden ; 4 . . . . . 1 . . system ; 8 . . . . 1 . . . volume label ; 16 . . . 1 . . . . subdirectory ; 32 . . 1 . . . . . archive ; 64 . 1 . . . . . . unused ; 128 1 . . . . . . . unused ; ; fcb : ; offset length description ; 0 1 special drive number ( 1 byte ) ; 0 = default ; 1 = a: ; 2 = b: etc ; 1 8 filename or device name ; 9 3 filename extension ; 12 2 current block number ; 14 2 record size ; 16 4 file size in bytes ( dos dir entry at open ) ; 20 2 file date ( bit coded as in dir ) ; 22 10 dos work area ; 32 1 current record number ( 0 - 127 ) ; 33 4 random record number ; ;------------------------------------------------------------------------------ org 100h ; required for COM file ( skips PSP ) start: jmp install ; install the demon ;------------------------------------------------------------------- ; ; resident data structures go here ; ;------------------------------------------------------------------- old_int dd 0 ; original value of hooked interrupt resident1 dw SIGNATURE1 resident2 dw SIGNATURE2 ;------------------------------------------------------------------- ; ; new interrupt starts here ; ;------------------------------------------------------------------- new_int: pushf sti ; must turn INT on if we're going to use them ;------------------------------------------------------------------- ; ; be well behaved and pass control to original int ; ;------------------------------------------------------------------- popf pushf call dword ptr cs:old_int ; do old interrupt iret ; bye bye ;------------------------------------------------------------------------------ ; ; INSTALLATION DATA STRUCTURES AND CODE GO HERE ; ; WARNING WARNING WARNING - this area does not exist after installation ; ;------------------------------------------------------------------------------ last_resident_byte db 0 ; last resident byte resident_flag dw 0 ; am I already resident ? ( 0 = NO ) install_msg db CR, LF, 'Installation Complete', CR, LF, '$' already_installed_msg db CR, LF db 'Already Installed - Installation Aborted' db CR, LF, '$' install proc near Version_msg mov al, HOOK_INT ; int to hook mov ah, DOS_GET_INT ; get int(AL) vector ==> ES+BX int DOS_INT ; do the int lea si, old_int ; where to put old timer interrupt vector mov [si], bx ; save the offset and segment mov 2[si], es ; ( es also used in check resident ) call check_resident ; am I already resident ? cmp resident_flag, 0 je not_resident Msg already_installed_msg mov ah, DOS_TERMINATE ; terminate & stay resident mov al, 1 ; return value is 1 (already installed) int DOS_INT ; bye-bye not_resident: mov dx, offset new_int ; offset of new timer interrupt mov al, HOOK_INT ; timer tick mov ah, DOS_SET_INT ; set int(AL) vector from DS+DX int DOS_INT ; do the int ; program terminate and stay resident Msg install_msg ; Display the installation message mov dx, offset last_resident_byte mov cl, 4 ; convert to paragraphs required to shr dx, cl ; remain resident ( divide by 16 ) inc dx ; allow for any remainder of division mov ah, DOS_RESIDENT ; terminate & stay resident mov al, 0 ; return value is 0 (good return) int DOS_INT ; bye-bye install endp ; ; Check resident procedure ; requires es register to contain the segment address of ; the current location for the interrupt being hooked. ; use the DOS function 35h to obtain this information. ; check_resident proc near cmp es:resident1, SIGNATURE1 jne not_res cmp es:resident2, SIGNATURE2 jne not_res mov resident_flag, 1 not_res: ret check_resident endp com ends end start