home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
magazine
/
msysjour
/
vol07
/
01
/
tsr
/
template.asm
Wrap
Assembly Source File
|
1991-12-31
|
70KB
|
1,473 lines
page 66,132
;=============================================================================
; TEMPLATE - A template for a Terminate and stay resident program
;
; Written by Douglas Boling
;
; Revision History
;
; 1.0 Initial Release
;
;=============================================================================
;----------------------------------------------------------------------------
; BIOS Data segment
;----------------------------------------------------------------------------
bios_data segment at 40h
org 17h
shift_state db ? ;State of keyboard shift keys
org 4Eh
video_buffoff dw ? ;Offset of video buffer
org 63h
video_ioregs dw ? ;I/O addr of video controller
org 84h
video_rows db ? ;Number of rows on the screen
bios_data ends
;----------------------------------------------------------------------------
; CODE segment
;----------------------------------------------------------------------------
code segment para public 'code'
assume cs:code
POPTIME EQU 18 ;Ticks allowed until popup
RESSTACKSIZE EQU 512 ;Size of resident stack
org 80h
command_tail db ?
org 100h
begin: jmp initialize
program db "Template 1.0 (c) 1992 Douglas Boling",13,10
db "Written by Douglas Boling$",26
;-----------------------------------------------------------------------------
; Memory locations required for system overhead.
;-----------------------------------------------------------------------------
hotshift db 0ah ;Shift combination for TSR
; <Alt> <Left shift>
; bit key
; 0 R Shift
; 1 L Shift
; 2 Ctrl
; 3 Alt
dos_version dw 0 ;DOS version number
mouse_flag db 0 ;Mouse driver present
resident_sp dw 0 ;Resident stack pointer
ems_flag db 0 ;Use expanded memory
ems_segment dw 0 ;EMS page frame segment
ems_version db 0 ;Version of EMS manager
ems_handle dw 0 ;EMS handle used
xms_flag db 0 ;Extended memory available
xms_service dd -1 ;Entry pt for XMS manager
xms_version db 0 ;Version of XMS manager
indos_ptr dd -1 ;Pointer to INDOS flag
criterr_ptr dd -1 ;Pointer to DOS crit err flag
int08h dd -1 ;Int 2f vector (Timer)
int09h dd -1 ;Int 09 vector (Keyboard HW)
int10h dd -1 ;Int 10 vector (Video BIOS)
int13h dd -1 ;Int 13 vector (Disk BIOS)
int16h dd -1 ;Int 16 vector (BIOS Keyboard)
int28h dd -1 ;Int 28 vector (DOS Idle)
int2Fh dd -1 ;Int 2F vector (DOS Multiplex)
int08_active db 0 ;Interrupt active flag
int09_active db 0 ;Interrupt active flag
int10_active db 0 ;Interrupt active flag
int13_active db 0 ;Interrupt active flag
int16_active db 0 ;Interrupt active flag
int28_active db 0 ;Interrupt active flag
int2F_active db 0 ;Interrupt active flag
SWNotifyJT dw offset SWNInit ;Jump table used by switcher
dw offset SWNQSuspend ; notification routine.
dw offset SWNSuspend
dw offset SWNActivate
dw offset SWNActive
dw offset SWNCSession
dw offset SWNDSession
dw offset SWNExit
;----------------------------------------------------------------------------
;Switcher global data structures
;----------------------------------------------------------------------------
StartupInfo = $
sisVersion dw 3 ;Switcher structure ID
sisNextDev dd 0 ;Ptr to prev startup structure
sisVirtDevFile dd 0 ;Ptr to name of opt dev drvr
sisReferenceData dd 0 ;Data for Win dev drivr
sisInstData dd 0 ;Ptr to instance mem list
InstItem1 dd 0 ;Ptr to instance data
InstSize1 dw 0 ;Size of instance data
InstItem2 dd 0 ;Ptr to instance stack
InstSize2 dw 0 ;Size of instance stack
dd 0 ;Ptr to next block = 0 to
dw 0 ; terminate list
;============================================================================
;Instance data
;============================================================================
TSRInstData = $
;----------------------------------------------------------------------------
;Switcher instance data structures
;----------------------------------------------------------------------------
SWService dd 0 ;Ptr to switcher service rtn
CallbackInfo = $
scbiNext dd 0 ;Ptr to prev callback struc
scbiEntryPoint dd 0 ;Ptr to local callback proc
scbiReserved dd 0 ;Reserved
scbiAPI dd 0 ;Ptr to info structures
SwapInfo = $
dw 0 ;Zero swapinfo structure
dw 0 ; since no API support
dw 0 ; implimented by the TSR
dw 0
dw 0
;----------------------------------------------------------------------------
;DOS State information
;----------------------------------------------------------------------------
saved_dta dd 0 ;saved pointer to curr DTA
saved_psp dw 0 ;saved segment of curr PSP
ss_register dw 0 ;SS register
sp_register dw 0 ;SP register
shift_save db 0 ;Keyboard shift lock state
A20_state dw 0 ;Saved state of A20 line
mem_alloc dw 0 ;DOS memory allocation strat
linkflag db 0 ;DOS UMB link flag
curr_disk db 0 ;Default disk at popup
curr_dir db 64 dup (0) ;Default directory at popup
errinfoarray:
errAX dw 0 ;Saved extended error info
errBX dw 0
errCX dw 0
errDX dw 0
errSI dw 0
errDI dw 0
errDS dw 0
errES dw 0
dw 3 dup (0) ;Reserved error table bytes
vector1bh dd 0 ;int 1Bh vector (Break)
vector23h dd 0 ;int 23h vector (Ctrl-C)
vector24h dd 0 ;int 24h vector (Crit err)
;----------------------------------------------------------------------------
;TSR State information
;----------------------------------------------------------------------------
popflag db 0 ;Request flag/timer
main_active db 0 ;TSR active flag
no_switch dw 0 ;Flag indicating switch OK
ret_addr dw 0 ;Saved return addr for calls
win_enhanced db 0 ;Enhanced mode windows flag
TSRInstDataEnd = $
;============================================================================
; VIDEOINT processes BIOS video services interrupt (Int 10h)
;============================================================================
videoint proc far
assume cs:code,ds:nothing,es:nothing
inc cs:int10_active
pushf
call cs:[int10h] ;Call old int
dec cs:int10_active
iret ;Return
videoint endp
;=============================================================================
; DISKINT receives control when an interrupt 13h is generated.
;=============================================================================
diskint proc far
assume cs:code,ds:nothing,es:nothing
pushf ;save flags register
inc cs:int13_active ;set disk access flag
call cs:[int13h]
pushf ;save flags again
dec cs:int13_active ;reset disk access flag
popf ;restore flags
ret 2 ;exit with flags intact
diskint endp
;============================================================================
; BIOSKEYINT processes the BIOS keyboard services
;============================================================================
bioskeyint proc far
assume cs:code,ds:nothing,es:nothing
pushf ;save flags register
inc cs:int16_active ;set keyboard active flag
call cs:[int16h]
pushf ;save flags again
dec cs:int16_active ;reset keyborard avtive flag
popf ;restore flags
ret 2 ;exit with flags intact
bioskeyint endp
;============================================================================
; TIMERINT processes timer interrupt (Int 08h)
;============================================================================
timerint proc far
assume cs:code,ds:nothing,es:nothing
pushf
call cs:[int08h] ;Call old int 8
cmp cs:int08_active,0 ;See if we are in this
jne timerint_exit ; routine already
cmp cs:popflag,0 ;See if we need to try to
jne timer_check ; pop up
timerint_exit:
iret ;Return
timer_check:
push ax
inc cs:int08_active ;Set int active flag
call check_system ;See if system OK to pop up
or ax,ax
jne timerint_dec
call main ;Call the TSR
mov cs:popflag,1
timerint_dec:
dec cs:popflag
dec cs:int08_active ;Clear int active flag
pop ax
jmp short timerint_exit
timerint endp
;============================================================================
; KEYINT processes keyboard interrupts (Int 09h)
;============================================================================
keyint proc far
assume cs:code,ds:nothing,es:nothing
pushf
call cs:[int09h] ;Call old int 9
push ax
push ds
mov ax,40h
mov ds,ax ;Set ES to bios data segment
assume ds:bios_data
mov al,ds:[shift_state]
and al,0fh ;Mask lock bits
cmp al,cs:[hotshift]
pop ds
pop ax
je keyint_hotkey
keyint_exit:
iret ;Return
keyint_hotkey:
mov cs:popflag,POPTIME ;Set timer to pop up
jmp short keyint_exit
keyint endp
;============================================================================
; IDLEINT processes DOS Idle interrupt (Int 28h)
;============================================================================
idleint proc far
assume cs:code,ds:nothing,es:nothing
pushf
call cs:[int28h] ;Call old int
cmp cs:int28_active,0 ;See if we are in this
jne idleint_exit ; routine already
cmp cs:popflag,0 ;See if we need to try to
jne idle_check ; pop up
idleint_exit:
iret ;Return
idle_check:
push ax
inc cs:int28_active ;Set int active flag
call check_system ;See if OK to pop up. Ignore
or al,al ; INDOS since in idle.
jne idleint_exit1
mov cs:popflag,0 ;Clear popup flag
call main ;Call the TSR
idleint_exit1:
dec cs:int28_active ;Clear int active flag
pop ax
jmp short idleint_exit
idleint endp
;============================================================================
; MUXINT processes the DOS Multiplex interrupt
;============================================================================
muxint proc far
assume cs:code,ds:nothing,es:nothing
cmp ax,1605h ;See if Windows start
je init_win
cmp ax,4b05h ;See if switcher get instance
je init_instance ; data.
cmp ax,4b01h ;See if switcher build chain
je chain_init
muxint_jmp:
jmp cs:[int2fh] ;Call old int
close_win:
test dx,01h ;See if enhanced mode Windows
jne muxint_jmp
dec cs:win_enhanced ;Clear enhanced mode flag
jmp short muxint_jmp
init_win:
test dx,01h ;See if enhanced mode Windows
jne init_instance
inc cs:win_enhanced
init_instance:
pushf
call cs:[int2fh] ;Call old int
mov word ptr cs:[sisNextDev],bx
mov word ptr cs:[sisNextDev+2],es
push cs ;ES:BX point to switcher struc
pop es
mov bx,offset StartupInfo
jmp short muxint_exit
chain_init:
pushf
call cs:[int2fh] ;Call old int
mov word ptr cs:[scbiNext],bx
mov word ptr cs:[scbiNext+2],es
push cs ;ES:BX point to switcher struc
pop es
mov bx,offset CallbackInfo
muxint_exit:
iret
muxint endp
;---------------------------------------------------------------------------
; Check System Determines if the system is in a state compatible with TSRs
; Exit: CF - Clear if OK to pop up
;---------------------------------------------------------------------------
check_system proc near
assume cs:code,ds:nothing,es:nothing
push bx
push ds
xor ax,ax
or al,cs:int10_active ;Check BIOS video int
or al,cs:int13_active ;Check BIOS disk int
or al,cs:int16_active ;Check BIOS keyboard int
lds bx,cs:criterr_ptr ;Check DOS critical error
or al,byte ptr ds:[bx] ; flag
lds bx,cs:indos_ptr ;Check INDOS flag
mov ah,byte ptr ds:[bx]
check_sys_exit:
pop ds
pop bx
ret
check_system endp
;=============================================================================
; CRITICALERR receives control when an interrupt 24h is generated.
;=============================================================================
criticalerr proc far
assume cs:code,ds:nothing,es:nothing
xor al,al ;Default to ignore
cmp cs:dos_version,30ah ;See if before DOS 3.1
jl critical1
add al,3
critical1:
iret
criticalerr endp
;=============================================================================
; MAIN
;=============================================================================
main proc near
assume cs:code,ds:nothing,es:nothing
cli
inc cs:no_switch ;Don't allow switch
inc cs:[main_active] ;set program status flag
mov cs:ss_register,ss ;save SS and SP registers
mov cs:sp_register,sp
mov ax,cs ;switch to internal stack
mov bx,resident_sp
mov ss,ax
mov sp,bx
dec cs:no_switch
sti ;enable interrupts
call save_regs ;save all registers
assume ds:code,es:nothing
;-----------------------------------------------------------------------------
;Point the interrupt 1Bh, 23h, and 24h vectors to internal handlers.
;-----------------------------------------------------------------------------
mov ax,351bh ;get and save 1Bh vector
int 21h
mov word ptr vector1bh,bx
mov word ptr vector1bh[2],es
mov ax,251bh ;point interrupt to IRET
mov dx,offset idleint_exit
int 21h
mov ax,3523h ;get and save 23h vector
int 21h
mov word ptr vector23h,bx
mov word ptr vector23h[2],es
mov ax,2523h ;Set to IRET
mov dx,offset idleint_exit
int 21h
mov ax,3524h ;get and save 24h vector
int 21h
mov word ptr vector24h,bx
mov word ptr vector24h[2],es
mov ax,2524h ;point interrupt to internal
mov dx,offset criticalerr ; critical error handler
int 21h
;-----------------------------------------------------------------------------
;Save and switch to internal PSP
;-----------------------------------------------------------------------------
mov ah,51h ;Get current PSP
call dospspcall ;Beware DOS 2.0 - 3.0
mov saved_psp,bx ;save it
push cs
pop bx
mov ah,50h ;Set internal PSP
call dospspcall
;-----------------------------------------------------------------------------
;Save and switch to internal DTA
;-----------------------------------------------------------------------------
mov ah,2fh
int 21h ;Get current DTA
mov word ptr saved_dta,bx ;save it
mov word ptr saved_dta[2],es
mov dx,offset command_tail ;use PSP for DTA
mov ah,1ah ;Set DTA
int 21h
;-----------------------------------------------------------------------------
;If DOS 3.x, save extended error information.
;-----------------------------------------------------------------------------
cmp word ptr dos_version,030ah
jb skip_err_save
push ds ;save DS
xor ax,ax ;Clear regs
mov bx,ax
mov cx,ax
mov dx,ax
mov di,ax
mov si,ax
mov ah,59h ;Extended error info
int 21h ;Call DOS
mov cs:[errDS],ds ;save returned DS
pop ds ;Restore DS
push bx
mov bx,offset errinfoarray ;Save data in registers
mov [bx],ax ; in this specific order.
pop [bx+2]
mov [bx+4],cx
mov [bx+6],dx
mov [bx+8],si
mov [bx+10],di
mov [bx+14],es
skip_err_save:
;-----------------------------------------------------------------------------
;If using EMS memory, save EMS mapping context and map our page.
;-----------------------------------------------------------------------------
cmp ems_flag,0
je skip_ems_save
mov ah,47h ;Save mapping context
mov dx,ems_handle
int 67h
or ah,ah
jne clean_up
xor ax,ax
mov bx,ax
call map_emsmem ;Map page
jne clean_up
skip_ems_save:
;-----------------------------------------------------------------------------
;Save default directory and drive
;-----------------------------------------------------------------------------
mov ah,19h ;Get current disk
int 21h
mov curr_disk,al
mov ah,47h ;Get current directory
xor dl,dl
mov si,offset curr_dir
int 21h
;-----------------------------------------------------------------------------
;Save state of A20 line.
;-----------------------------------------------------------------------------
cmp xms_flag,0
je skip_xms_save
mov ah,7 ;Get state of A20 line
call [xms_service]
mov A20_state,ax
skip_xms_save:
;-----------------------------------------------------------------------------
;Save UMB link and mem allocaton state. If DOS 5, link UMBs
;-----------------------------------------------------------------------------
mov ax,5800h ;Get DOS mem alloc strategy
int 21h
mov mem_alloc,ax
cmp dos_version,500h ;If DOS 5, save UMB link
jb skip_umblink ; state. Then link UMBs
mov ax,5802h
int 21h
mov linkflag,al ;Save UMB link state
mov ax,5803h
mov bx,1 ;Link UMBs
int 21h
skip_umblink:
;-----------------------------------------------------------------------------
;Save Mouse state
;-----------------------------------------------------------------------------
cmp mouse_flag,0
je skip_mouse_save
mov ax,17h
mov dx,offset ResCodeEnd ;Save mouse state
push cs
pop es
int 33h
skip_mouse_save:
;-----------------------------------------------------------------------------
;Save Keyboard shift state
;-----------------------------------------------------------------------------
mov ah,2 ;Get keyboard shift state
int 16h
mov shift_save,al
;=============================================================================
;Do work here
;=============================================================================
mov ax,0e07h ;Beep the speaker
int 10h
work_1:
mov ah,01 ;See if key available
int 16h
jne work_2
call TSR_idle ;Indicate TSR idle
jmp short work_1
work_2:
xor ah,ah
int 16h
cmp al,27 ;See if <Esc> key
jne work_1 ;No, continue to wait
mov ax,0e07h ;Beep the speaker again
int 10h
;-----------------------------------------------------------------------------
;Clean up DOS for return to forground task.
;-----------------------------------------------------------------------------
clean_up:
push cs
pop ds
assume ds:code,es:nothing
;-----------------------------------------------------------------------------
;Restore Keyboard shift state
;-----------------------------------------------------------------------------
mov ax,bios_data ;Point ES to BIOS data seg
mov es,ax
assume es:bios_data
mov al,shift_save
and al,0f0h ;Look only at lock bits
mov es:[shift_state],al
push cs
pop es
assume es:code
;-----------------------------------------------------------------------------
;Restore Mouse state
;-----------------------------------------------------------------------------
cmp mouse_flag,0
je skip_mouse_restore
mov ax,17h
mov dx,offset ResCodeEnd ;Restore mouse state
int 33h
skip_mouse_restore:
;-----------------------------------------------------------------------------
;Restore UMB link state, link and allocation strat
;-----------------------------------------------------------------------------
mov ax,5801h ;Set DOS mem alloc strategy
mov bx,mem_alloc
int 21h
cmp dos_version,500h ;If DOS 5, restore UMB link
jb skip_umblink_restore ; state.
mov ax,5803h ;Set UMB link state
xor bh,bh
mov bl,linkflag
int 21h
skip_umblink_restore:
;-----------------------------------------------------------------------------
;Restore A20 line
;-----------------------------------------------------------------------------
cmp xms_flag,0
je skip_xms_restore
mov ah,5 ;Assume local disable A20
cmp A20_state,0
je xms_restore_1
inc ah ;Change to local enable A20
xms_restore_1:
call [xms_service] ;Restore A20 line state
mov A20_state,ax
skip_xms_restore:
;-----------------------------------------------------------------------------
;If using EMS memory, restore EMS mapping context.
;-----------------------------------------------------------------------------
cmp ems_flag,0
je ems_restore_skip
mov ah,48h ;Restore mapping context
mov dx,ems_handle
int 67h
ems_restore_skip:
;-----------------------------------------------------------------------------
;Restore default directory and drive
;-----------------------------------------------------------------------------
mov ah,0eh ;Set default disk
mov dl,curr_disk
int 21h
mov ah,3bh ;Set current directory
mov dx,offset curr_dir
int 21h
;-----------------------------------------------------------------------------
;Restore extended error info.
;-----------------------------------------------------------------------------
cmp word ptr dos_version,30ah ;DOS 3.1 and up
jb skip_err_restore
mov ax,5d0ah ;Restore ext error info
mov dx,offset errinfoarray ;point to Saved info
int 21h
skip_err_restore:
;-----------------------------------------------------------------------------
;Restore PSP and DTA
;-----------------------------------------------------------------------------
mov bx,saved_psp ;Get old PSP
mov ah,50h ;Restore PSP
call dospspcall
push ds
lds dx,[saved_dta]
mov ah,1ah ;Restore DTA
int 21h
;-----------------------------------------------------------------------------
;Reset the displaced interrupt 1Bh, 23h, and 24h vectors.
;-----------------------------------------------------------------------------
mov ax,2524h ;reset int 24h vector
lds dx,cs:[vector24h]
int 21h
mov ax,2523h ;reset int 24h vector
lds dx,cs:[vector23h]
int 21h
mov ax,251bh ;reset int 1Bh vector
lds dx,cs:[vector1bh]
int 21h
pop ds
;-----------------------------------------------------------------------------
;Restore register values, switch back to original stack, and return to caller.
;-----------------------------------------------------------------------------
main_exit:
call restore_regs ;Restore registers
assume ds:nothing
cli ;make sure interrupts are off
inc cs:no_switch ;Don't allow task switch
mov ss,cs:ss_register ;switch to original stack
mov sp,cs:sp_register
dec cs:[main_active] ;clear program status flag
dec cs:no_switch ;Allow task switch
sti ;interrupts on
ret ;Return to interrupt routine
main endp
;-----------------------------------------------------------------------------
; DOSPSPCALL modifies critical error flag on PSP calls to DOS is using 2.x
;-----------------------------------------------------------------------------
dospspcall proc near
assume cs:code
cmp cs:[dos_version],30Ah ;See if DOS < 3.1
jae dospspcall_ok ;no, just call DOS
push ds
push di
lds di,cs:criterr_ptr ;retrieve crit err flag adr
inc byte ptr [di] ;Set DOS in crit error state
pop di
pop ds
int 21h ;Call DOS
push ds
push di
lds di,cs:criterr_ptr ;retrieve crit err flag adr
dec byte ptr [di] ;Set DOS in crit error state
pop di
pop ds
ret
dospspcall_ok:
int 21h ;Call DOS
ret
dospspcall endp
;-----------------------------------------------------------------------------
; STOP SWITCH Signals the task switcher (if active) to not switch this
; session.
;-----------------------------------------------------------------------------
stop_switch proc near
assume cs:code
inc cs:no_switch ;Set no switch flag for TS
cmp win_enhanced,0
jne stop_switch_1
stop_switch_exit:
ret
stop_switch_1:
mov ax,1681h ;Win begin critical section
int 2fh
jmp short stop_switch_exit
stop_switch endp
;-----------------------------------------------------------------------------
; GO SWITCH Signals the task switcher (if active) it is OK to switch this
; session.
;-----------------------------------------------------------------------------
go_switch proc near
assume cs:code
dec cs:no_switch ;Clear switch flag for TS
cmp win_enhanced,0
jne go_switch_1
go_switch_exit:
ret
go_switch_1:
mov ax,1682h ;Win end critical section
int 2fh
jmp short go_switch_exit
go_switch endp
;-----------------------------------------------------------------------------
; TSR IDLE Signals the system that the TSR is idle.
;-----------------------------------------------------------------------------
TSR_idle proc near
assume cs:code
int 28h ;Old DOS Idle
cmp dos_version,300h ;No Multiplex interrupt for
jb TSR_Idle_exit ; DOS 2.x
mov ax,1680h ;Win-OS/2 release timeslice.
int 2fh
TSR_idle_exit:
ret
TSR_idle endp
;============================================================================
; SWNOTIFY Routine to parse switcher notification messages
;============================================================================
SWNotify proc far
assume cs:code,ds:nothing,es:nothing
push si
push ds
push cs
pop ds
assume ds:code
mov word ptr [SWService],di ;Save ptr to service rtn
mov word ptr [SWService+2],es
cmp ax,7
ja SWN1 ;If unknown type, skip
mov si,ax
shl si,1
call [SWNotifyJT+si] ;Call proper notification func
mov ax,0
SWN1:
pop ds
pop si
ret
;---------------------------------------------------------------------------
; SWINIT - Switcher initialization notification
;---------------------------------------------------------------------------
SWNInit proc near
assume cs:code,ds:code
mov ax,0 ;Allow switcher init
ret
SWNInit endp
;---------------------------------------------------------------------------
; SWQSUSPENDINIT - Switcher query suspend notification
;---------------------------------------------------------------------------
SWNQSuspend proc near
assume cs:code,ds:code
mov ax,no_switch ;Switch only if not in
ret ; critical section
SWNQSuspend endp
;---------------------------------------------------------------------------
; SWSUSPEND - Switcher suspend notification
;---------------------------------------------------------------------------
SWNSuspend proc near
assume cs:code,ds:code
mov ax,no_switch ;Switch only if not in
ret ; critical section
SWNSuspend endp
;---------------------------------------------------------------------------
; SWACTIVATE - Switcher going active notification
;---------------------------------------------------------------------------
SWNActivate proc near
assume cs:code,ds:code
mov ax,0 ;Allow session activate
ret
SWNActivate endp
;---------------------------------------------------------------------------
; SWACTIVE - Switcher session active notification
;---------------------------------------------------------------------------
SWNActive proc near
assume cs:code,ds:code
mov ax,0 ;Allow session activate
ret
SWNActive endp
;---------------------------------------------------------------------------
; SWCSESSION - Switcher create session notification
;---------------------------------------------------------------------------
SWNCSession proc near
assume cs:code,ds:code
mov ax,0 ;Allow session create
ret
SWNCSession endp
;---------------------------------------------------------------------------
; SWDSESSION - Switcher destroy session notification
;---------------------------------------------------------------------------
SWNDSession proc near
assume cs:code,ds:code
mov ax,0 ;Allow session destroy
ret
SWNDSession endp
;---------------------------------------------------------------------------
; SWEXIT - Switcher exit notification
;---------------------------------------------------------------------------
SWNExit proc near
assume cs:code,ds:code
mov ax,0 ;Allow switcher exit
ret
SWNExit endp
SWNotify endp
;-----------------------------------------------------------------------------
; GETEMSMEM Allocates pages of memory from the Expanded memory manager
; Entry: BX - number of 16K pages to request
; Exit: DX - handle to pages
; ZF - Set if call successful
;-----------------------------------------------------------------------------
get_emsmem proc near
mov ah,43h ;Allocate EMS pages
int 67h
or ah,ah
ret
get_emsmem endp
;-----------------------------------------------------------------------------
; FREEEMSMEM Frees pages of memory from the Expanded memory manager
; Entry: DX - handle to memory pages to free
; Exit: ZF - Set if call successful
;-----------------------------------------------------------------------------
free_emsmem proc near
mov ah,45h ;Free EMS page
int 67h
or ah,ah
ret
free_emsmem endp
;-----------------------------------------------------------------------------
; MAPEMSMEM Maps a page of Expanded memory to the EMS page frame
; Entry: AL - Physical page in page frame
; BX - logical page to map
; DX - handle to memory pages
; Exit: ZF - Set if call successful
;-----------------------------------------------------------------------------
map_emsmem proc near
mov ah,44h ;Map EMS page
int 67h
or ah,ah
ret
map_emsmem endp
;-----------------------------------------------------------------------------
; SAVEREGS saves all the registers used in the interrupt routines and sets DS.
;-----------------------------------------------------------------------------
save_regs proc near
pop cs:[ret_addr] ;Get address to return to
push ax ;save all registers
push bx
push cx
push dx
push bp
push si
push di
push ds
push es
push cs ;Set DS = CS
pop ds
assume ds:code
jmp word ptr [ret_addr] ;Return
save_regs endp
;-----------------------------------------------------------------------------
;RESTOREREGS restores register values.
;-----------------------------------------------------------------------------
restore_regs proc near
pop ret_addr ;Save return address
pop es ;restore registers
pop ds
assume ds:nothing
pop di
pop si
pop bp
pop dx
pop cx
pop bx
pop ax
jmp word ptr cs:[ret_addr] ;Return
restore_regs endp
;=============================================================================
; End of resident code. Resident stack and mouse save area sits just
; above resident code
;=============================================================================
ResCodeEnd = $
;=============================================================================
; Non-Resident data
;=============================================================================
errmsg1 db 13,10,"Usage: TEMPLATE [/U][/X][/E]$"
errmsg2 db "Bad switch$"
errmsg3 db "Expanded memory driver not found$"
errmsg4 db "DOS 2.0 or greater required$"
errmsg5 db "Not able to uninstall$"
errmsg6 db "TEMPLATE not installed$"
infomsg1 db "TEMPLATE installed$"
infomsg2 db "TEMPLATE removed$"
errmsg8 db "Program uninstalled$"
errmsg9 db "Can't install$"
installed_seg dw 0 ;Segment of installed code
TSRResident db 0 ;TSR already installed flag
def_disk db ? ;Default disk drive
ems_header db "EMMXXXX0" ;EMS driver header
mouse_savesize dw 0 ;Size of mouse save area
cmd_switches db "eu" ;Letters of valid commands.
cmd_switch_end = $
cmd_jmptbl dw offset remove ;Jump table to rouines that
dw offset use_expanded ; impliment the cmd line args
;=============================================================================
; INITIALIZE
;=============================================================================
initialize proc near
assume cs:code, ds:code
cld ;String operations UP
mov dx,offset program ;Print copyright
call message
;-----------------------------------------------------------------------------
;Get DOS version, Determine if TSR already installed.
;-----------------------------------------------------------------------------
mov ah,30h ;Get DOS version
int 21h
xchg al,ah ;Put version in proper order
mov dos_version,ax ;Save DOS version
cmp ax,200h ;See if at least DOS ver 2
ja init_0
mov dx,offset errmsg4
jmp short error_exit
init_0:
call find_copy ;See if TSR already installed
jc init_1
inc TSRResident ;Set already installed flag
mov installed_seg,es ;save installed code segment
init_1:
push cs
pop es
;-----------------------------------------------------------------------------
;Parse the command line for switches.
;-----------------------------------------------------------------------------
mov di,offset command_tail ;Point SI to command line text
xor cx,cx
or cl,[di] ;Get length of command line.
jz init_3 ;If 0, skip parse
inc di
init_2:
mov al,"/" ;Put switch in AL
repne scasb ;Scan for cmd line switches
jne init_3
mov al,[di]
or al,20h ;Make lower case
push cx
push di
mov di,offset cmd_switches
mov cx,offset cmd_switch_end - offset cmd_switches
repne scasb
mov bx,cx ;Copy index into list
pop di
pop cx
mov dx,offset errmsg2 ;Command not found msg
jne error_exit
shl bx,1 ;Convert to word offset
push cx
push di
call cs:[bx+cmd_jmptbl] ;Call command routine.
pop di
pop cx
jc error_exit ;If error terminate parse.
jcxz init_3 ;If at file end, exit parse.
jmp short init_2
init_3:
;-----------------------------------------------------------------------------
;If not installed, install.
;-----------------------------------------------------------------------------
cmp TSRResident,0 ;Is TSR installed?
je install
mov ax,4c00h ;No, terminate with RC = 0.
int 21h
;=============================================================================
;Display error message and exit with Return Code = 1.
;=============================================================================
error_exit: call message
mov es,installed_seg ;point ES to installed code
dec es:[main_active] ;enable background task.
mov ax,4c01h ;Exit RC = 1
int 21h
;=============================================================================
;Install. Get address of INDOS and DOS Critical Error flags.
;=============================================================================
install:
mov ah,34h ;Get INDOS address from DOS
int 21h
mov word ptr [indos_ptr],bx
mov word ptr [indos_ptr+2],es
call find_cefptr ;Find critical error flag
jnc ceffound
mov dx,offset errmsg9 ;Critical error flag not found
jmp short error_exit
ceffound:
mov word ptr criterr_ptr,bx ;store it
mov word ptr criterr_ptr[2],es
;-----------------------------------------------------------------------------
;Initialize task switcher structures. See if task switcher active.
;-----------------------------------------------------------------------------
cmp word ptr dos_version,300h ;DOS 3.0 and up
jb nowin
mov ax,offset TSRInstData ;Init instance memory struc
mov word ptr [InstItem1],ax
mov word ptr [InstItem1+2],cs
mov ax,offset TSRInstDataEnd - offset TSRInstData
mov [InstSize1],ax
mov ax,offset ResCodeEnd ;Init instance stack struc
mov word ptr [InstItem2],ax
mov word ptr [InstItem2+2],cs
mov ax,RESSTACKSIZE
mov [InstSize2],ax
mov ax,offset InstItem1 ;Init ptr to instance
mov word ptr [sisInstData],ax ; memory structure.
mov word ptr [sisInstData+2],cs
mov ax,offset SWNotify ;Init ptr to
mov word ptr [scbiEntryPoint],ax ; notification
mov word ptr [scbiEntryPoint+2],cs ; routine.
mov ax,4b02h ;See if switcher active
int 2fh ;Use multiplex interrupt
or ax,ax
jne noswitcher
mov word ptr [SWService],di ;Save ptr to service routine
mov word ptr [SWService+2],es
mov ax,4 ;Hook notification chain
push cs ;ES:BX point to callback struc
pop es
mov di,offset CallbackInfo
call SWService
noswitcher:
;-----------------------------------------------------------------------------
;Check for Windows active
;-----------------------------------------------------------------------------
mov ax,1600h ;See if Enhanced mode windows
int 2fh
or al,al
je nowin
inc win_enhanced ;Set enhanced mode flag
nowin:
;-----------------------------------------------------------------------------
;Determine if extended memory manager active
;-----------------------------------------------------------------------------
mov ax,4300h ;Look for HIMEM.SYS
int 2fh
or al,al
jne noxms
mov ax,4310h ;Get entry point for XMM
int 2fh
mov word ptr [xms_service],bx
mov word ptr [xms_service+2],es
push cs
pop es
inc xms_flag
noxms:
;-----------------------------------------------------------------------------
;Set up EMS memory if necessary.
;-----------------------------------------------------------------------------
cmp ems_flag,0 ;See if expanded memory
je no_emsmem ; requested
call check4ems ;See if EMS driver installed
jnc install_1
mov dx,offset errmsg3 ;EMS driver error
jmp error_exit
install_1:
mov ems_segment,bx ;Save seg of EMS page frame
mov ems_version,dl ;Save EMS version
mov bx,1 ;Allocate 1 page
call get_emsmem
mov ems_handle,dx ;Save EMS handle
xor al,al ;Map to EMS page 0
xor bx,bx
call map_emsmem
no_emsmem:
;-----------------------------------------------------------------------------
;See if mouse driver loaded
;-----------------------------------------------------------------------------
xor ax,ax
int 33h
or ax,ax
je no_mouse
inc mouse_flag ;Set mouse found flag, get
mov ax,15h ; size of mouse driver save
int 33h ; context area.
mov mouse_savesize,bx
no_mouse:
;-----------------------------------------------------------------------------
;Set interrupts used by TSR
;-----------------------------------------------------------------------------
mov al,08h ;Get/set the timer interrupt
mov dx,offset timerint
mov di,offset int08h
call set_interrupt
mov al,09h ;Get/set the keyboard int
mov dx,offset keyint
mov di,offset int09h
call set_interrupt
mov al,10h ;Get/set the video interrupt
mov dx,offset videoint
mov di,offset int10h
call set_interrupt
mov al,13h ;Get/set the disk interrupt
mov dx,offset diskint
mov di,offset int13h
call set_interrupt
mov al,16h ;Get/set the BIOS keyboard int
mov dx,offset bioskeyint
mov di,offset int16h
call set_interrupt
mov al,28h ;Get/set the DOS idle int
mov dx,offset idleint
mov di,offset int28h
call set_interrupt
cmp dos_version,300h ;DOS 3.0 and up
jb skip_hook2f
mov al,2fh ;Get/set the DOS multiplex int
mov dx,offset muxint
mov di,offset int2fh
call set_interrupt
skip_hook2f:
;-----------------------------------------------------------------------------
;Deallocate the program's environment block.
;-----------------------------------------------------------------------------
mov ax,ds:[2ch] ;get environment segment
mov es,ax
mov ah,49h ;free it
int 21h
mov dx,offset infomsg1 ;Tell user that we are
call message ; installed.
mov ax,3100h ;terminate with ERRORLEVEL = 0
mov dx,offset ResCodeEnd-offset code + RESSTACKSIZE
add dx,mouse_savesize
mov resident_sp,dx
add dx,15
mov cl,4
shr dx,cl
int 21h
initialize endp
;-----------------------------------------------------------------------------
; USE EXPANDED Sets a flag to use expanded memory
;-----------------------------------------------------------------------------
use_expanded proc near
mov ems_flag,1
ret
use_expanded endp
;-----------------------------------------------------------------------------
; REMOVE deallocates the memory block addressed by ES and restores the
; interrupt vectors displaced on installation.
; Exit: CF clear - program uninstalled
; CF set - can't uninstall
;-----------------------------------------------------------------------------
remove proc near
assume cs:code,ds:code
cmp TSRResident,0 ;See if TSR installed
jne remove_1
mov dx,offset errmsg6
jmp remove_error1
remove_1:
mov es,installed_seg
mov ax,5 ;Unhook notification chain
mov di,offset CallbackInfo
cmp word ptr es:[SWService+2],0
je remove_2
call es:[SWService]
remove_2:
mov al,8 ;check interrupt 8 vector
call checkvector
jne jmp_remove_error
mov al,9 ;check interrupt 9 vector
call checkvector
jne jmp_remove_error
mov al,10h ;check interrupt 10 vector
call checkvector
jne jmp_remove_error
mov al,13h ;check interrupt 13h vector
call checkvector
jne jmp_remove_error
mov al,16h ;check interrupt 16 vector
call checkvector
jne jmp_remove_error
mov al,28h ;check interrupt 28h vector
call checkvector
je remove_3
jmp_remove_error:
jmp remove_error
remove_3:
cmp dos_version,300h ;DOS 3.0 and up
jb skip_check2f
mov al,2Fh ;check interrupt 2Fh vector
call checkvector
jne remove_error
skip_check2f:
cmp ems_flag,0 ;If using Expanded memory
je skip_remove_ems ; free it
mov dx,ems_handle ;Free Expanded memory
call free_emsmem
jne remove_error
skip_remove_ems:
push ds ;save DS
assume ds:nothing
mov ax,2508h ;restore interrupt 8 vector
lds dx,es:[int08h]
int 21h
mov ax,2509h ;restore interrupt 9 vector
lds dx,es:[int09h]
int 21h
mov ax,2510h ;restore interrupt 10 vector
lds dx,es:[int10h]
int 21h
mov ax,2513h ;restore interrupt 13h vector
lds dx,es:[int13h]
int 21h
mov ax,2516h ;restore interrupt 16 vector
lds dx,es:[int16h]
int 21h
mov ax,2528h ;restore interrupt 28h vector
lds dx,es:[int28h]
int 21h
cmp cs:dos_version,300h ;DOS 3.0 and up
jb skip_restore2f
mov ax,252Fh ;restore interrupt 2Fh vector
lds dx,es:[int2Fh]
int 21h
skip_restore2f:
pop ds ;Restore DS
assume ds:code
not word ptr es:[begin] ;Destroy fingerprint
mov ah,49h ;Free memory given to
int 21h ; original program block
jc remove_error ;branch on error
mov dx,offset infomsg2 ;Indicate program removed
call message
clc ;clear CF for exit
remove_exit:
ret ;exit with CF intact
remove_error:
mov dx,offset errmsg5
remove_error1: stc
jmp remove_exit ;Error during remove
remove endp
;-----------------------------------------------------------------------------
; CHECKVECTOR is called by REMOVE to compare the segment pointed to by an
; interrupt vector against a segment value supplied by the caller.
; Entry: AL - interrupt number
; Exit: ZF clear - segments do not match
; ZF set - segments match
;-----------------------------------------------------------------------------
checkvector proc near
push es
mov cx,es
mov ah,35h ;get vector
int 21h
mov ax,es ;transfer segment to AX
cmp ax,cx ;compare
pop es
ret
checkvector endp
;-----------------------------------------------------------------------------
; SETINTERRUPT Get and sets an interrupt
; Entry: AL - Interrupt number
; DX - Pointer to new interrupt routine
; DI - Pointer to storage location for old interrupt vector
;-----------------------------------------------------------------------------
assume cs:code,ds:code,es:nothing
set_interrupt proc near
push es
push ax
mov ah,35h ;DOS get interrupt
int 21h
pop ax
mov word ptr [di],bx ;Save old vector
mov word ptr [di+2],es
mov ah,25h ;DOS set interrupt
int 21h
pop es
ret
set_interrupt endp
;-----------------------------------------------------------------------------
; FINDCOPY Determines if the TSR is already resident
; Exit: CF - Clear if copy found
; ES - Segment of installed code (if CF = 0)
;-----------------------------------------------------------------------------
find_copy proc near
not word ptr [begin] ;initialize fingerprint
mov bx,0a000h ;Start scan in UMBs
mov ax,cs ;keep CS value in AX
find_copy1:
inc bx ;increment search segment value
mov es,bx
cmp ax,bx ;not installed if current
je find_copy2 ; segment is looped back to
mov si,offset begin ;search this segment for ASCII
mov di,si ; fingerprint
mov cx,16
repe cmpsb
jne find_copy1 ;loop back if not found
clc ;Set copy found flag
find_copy_exit:
ret
find_copy2:
stc
jmp short find_copy_exit
ret
find_copy endp
;-----------------------------------------------------------------------------
; GETCEFPtr Returns a pointer to the DOS ErrorMode flag
; Exit: CF - Clear if ErrorMode Flag found
; ES:BX - Segment:offset of ErrorMode flag
;
; For versions of DOS before 3.1, search for following code in DOS seg
;
; 36: 80 3E ???? 00 cmp byte ptr ss:[ErrorMode],0
; 75 ?? jne near label
; CD 28 int 28h
;
; For DOS 3.1 and later, ErrorMode sits before InDOS flag
;
;-----------------------------------------------------------------------------
find_cefptr proc near
mov ah,34h ;Get ptr to INDOS
int 21h ;After DOS 3.1, the CEF is
dec bx ; documented to be the byte
cmp dos_version,30ah ; before the INDOS flag
jnc find_cef_exit
mov ax,3e80h ;CMP opcode
mov cx,-1 ;Max segment size
mov di,bx ;Start at INDOS address
find_cef_1:
repne scasb ;Scan for CMP
jcxz find_cef_notfound ;Error if CMP not found
cmp es:[di],ah ;Check other half of CMP opcode
jne find_cef_1
cmp byte ptr es:[di+4],075h ;Check for JNE
jne find_cef_1
cmp word ptr es:[di+6],028cdh ; Check for Int 28h call
jne find_cef_1 ;Resume loop if not found
find_cef_found:
inc di
mov bx,es:[di] ;Get offset of ErrorMode flag
clc
find_cef_exit:
ret
find_cef_notfound:
stc
jmp short find_cef_exit
find_cefptr endp
;-----------------------------------------------------------------------------
; CHECK4EMS Determines if an Expanded memory driver is loaded.
; Exit: BX - Segment of EMS page frame if CF clear
; DL - EMS driver version number
; CF - Clear if EMS driver found
;-----------------------------------------------------------------------------
check4ems proc near
push es
push di
mov ax,3567h ;Get EMS vector
int 21h
mov di,0ah ;Using the segment from the
mov si,offset ems_header ; 67h vector, look at offset
mov cx,8 ; 0ah. Compare the next 8
cld ; bytes with the expected
repe cmpsb ; EMS header. If they are
pop di ; the same, EMS driver
pop es ; found.
je check4ems_found
check4ems_error:
stc ;Set not found flag
jmp short check4ems_exit
check4ems_found:
mov ah,40h ;Check status
int 67h
or ah,ah
jne check4ems_error
mov ah,41h ;Get page frame segment
int 67h
or ah,ah
jne check4ems_error
mov ah,47h ;Get EMM version number
int 67h
or ah,ah
jne check4ems_error
mov dl,al ;Copy version number
check4ems_exit:
ret
check4ems endp
;----------------------------------------------------------------------
; MESSAGE Prints a message to screen
; Entry: DX - Offset of '$' terminated message
;----------------------------------------------------------------------
crlf$ db 13,10,"$"
message proc near
assume cs:code,ds:code
mov ah,9 ;Print string
int 21h
mov dx,offset crlf$ ;Append carrage return
mov ah,9
int 21h
ret
message endp
EndOfCode = $
code ends
end begin