home *** CD-ROM | disk | FTP | other *** search
- ;
- ; Name: snap
- ;
- ; Description: This RAM-resident (terminate-and-stay-resident) utility
- ; produces a video "snapshot" by copying the contents of the
- ; video regeneration buffer to a disk file. It may be used
- ; in 80-column alphanumeric video modes on IBM PCs and PS/2s.
- ;
- ; Comments: Assemble and link to create SNAP.EXE.
- ;
- ; Execute SNAP.EXE to make resident.
- ;
- ; Press Alt-Enter to dump current contents of video buffer
- ; to a disk file.
- ;
-
- MultiplexID EQU 0CAh ; unique INT 2FH ID value
-
- TSRStackSize EQU 100h ; resident stack size in bytes
-
- KB_FLAG EQU 17h ; offset of shift-key status flag in
- ; ROM BIOS keyboard data area
-
- KBIns EQU 80h ; bit masks for KB_FLAG
- KBCaps EQU 40h
- KBNum EQU 20h
- KBScroll EQU 10h
- KBAlt EQU 8
- KBCtl EQU 4
- KBLeft EQU 2
- KBRight EQU 1
-
- SCEnter EQU 1Ch
-
- CR EQU 0Dh
- LF EQU 0Ah
- TRUE EQU -1
- FALSE EQU 0
-
- PAGE
- ;------------------------------------------------------------------------------
- ;
- ; RAM-resident routines
- ;
- ;------------------------------------------------------------------------------
-
- RESIDENT_GROUP GROUP RESIDENT_TEXT,RESIDENT_DATA,RESIDENT_STACK
-
- RESIDENT_TEXT SEGMENT byte public 'CODE'
- ASSUME cs:RESIDENT_GROUP,ds:RESIDENT_GROUP
-
- ;------------------------------------------------------------------------------
- ; System verification routines
- ;------------------------------------------------------------------------------
-
- VerifyDOSState PROC near ; Returns: carry flag set if MS-DOS
- ; is busy
-
- push ds ; preserve these registers
- push bx
- push ax
-
- lds bx,cs:ErrorModeAddr
- mov ah,[bx] ; AH = ErrorMode flag
-
- lds bx,cs:InDOSAddr
- mov al,[bx] ; AL = InDOS flag
-
- xor bx,bx ; BH = 00H, BL = 00H
- cmp bl,cs:InISR28 ; carry flag set if INT 28H handler
- ; is running
- rcl bl,01h ; BL = 01H if INT 28H handler is running
-
- cmp bx,ax ; carry flag zero if AH = 00H
- ; and AL <= BL
-
- pop ax ; restore registers
- pop bx
- pop ds
- ret
-
- VerifyDOSState ENDP
-
-
- VerifyIntState PROC near ; Returns: carry flag set if hardware
- ; or ROM BIOS unstable
-
- push ax ; preserve AX
-
- ; Verify hardware interrupt status by interrogating Intel 8259A Programmable
- ; Interrupt Controller
-
- mov ax,00001011b ; AH = 0
- ; AL = 0CW3 for Intel 8259A (RR = 1,
- ; RIS = 1)
- out 20h,al ; request 8259A's in-service register
- jmp short L10 ; wait a few cycles
- L10: in al,20h ; AL = hardware interrupts currently
- ; being serviced (bit = 1 if in-service)
- cmp ah,al
- jc L11 ; exit if any hardware interrupts still
- ; being serviced
-
- ; Verify status of ROM BIOS interrupt handlers
-
- xor al,al ; AL = 00H
-
- cmp al,cs:InISR5
- jc L11 ; exit if currently in INT 05H handler
-
- cmp al,cs:InISR9
- jc L11 ; exit if currently in INT 09H handler
-
- cmp al,cs:InISR10
- jc L11 ; exit if currently in INT 10H handler
-
- cmp al,cs:InISR13 ; set carry flag if currently in
- ; INT 13H handler
-
- L11: pop ax ; restore AX and return
- ret
-
- VerifyIntState ENDP
-
-
- VerifyTSRState PROC near ; Returns: carry flag set if TSR
- ; inactive
-
- rol cs:HotFlag,1 ; carry flag set if (HotFlag = TRUE)
- cmc ; carry flag set if (HotFlag = FALSE)
- jc L20 ; exit if no hot key
-
- ror cs:ActiveTSR,1 ; carry flag set if (ActiveTSR = TRUE)
- jc L20 ; exit if already active
-
- call VerifyDOSState
- jc L20 ; exit if MS-DOS unstable
-
- call VerifyIntState ; set carry flag if hardware or BIOS
- ; unstable
-
- L20: ret
-
- VerifyTSRState ENDP
-
- PAGE
- ;------------------------------------------------------------------------------
- ; System monitor routines
- ;------------------------------------------------------------------------------
-
- ISR5 PROC far ; INT 05H handler
- ; (ROM BIOS print screen)
-
- inc cs:InISR5 ; increment status flag
-
- pushf
- cli
- call cs:PrevISR5 ; chain to previous INT 05H handler
-
- dec cs:InISR5 ; decrement status flag
- iret
-
- ISR5 ENDP
-
-
- ISR8 PROC far ; INT 08H handler (timer tick, IRQ0)
-
- pushf
- cli
- call cs:PrevISR8 ; chain to previous handler
-
- cmp cs:InISR8,0
- jne L31 ; exit if already in this handler
-
- inc cs:InISR8 ; increment status flag
-
- sti ; interrupts are ok
- call VerifyTSRState
- jc L30 ; jump if TSR is inactive
-
- mov byte ptr cs:ActiveTSR,TRUE
- call TSRapp
- mov byte ptr cs:ActiveTSR,FALSE
-
- L30: dec cs:InISR8
-
- L31: iret
-
- ISR8 ENDP
-
-
- ISR9 PROC far ; INT 09H handler
- ; (keyboard interrupt IRQ1)
-
- push ds ; preserve these registers
- push ax
- push bx
-
- push cs
- pop ds ; DS -> RESIDENT_GROUP
-
- in al,60h ; AL = current scan code
-
- pushf ; simulate an INT
- cli
- call ds:PrevISR9 ; let previous handler execute
-
- mov ah,ds:InISR9 ; if already in this handler ..
- or ah,ds:HotFlag ; .. or currently processing hot key ..
- jnz L43 ; .. jump to exit
-
- inc ds:InISR9 ; increment status flag
- sti ; now interrupts are ok
-
- ; Check scan code sequence
-
- cmp ds:HotSeqLen,0
- je L40 ; jump if no hot sequence to match
-
- mov bx,ds:HotIndex
- cmp al,[bx+HotSequence] ; test scan code sequence
- jne L41 ; jump if no match
-
- inc bx
- cmp bx,ds:HotSeqLen
- jb L42 ; jump if not last scan code to match
-
- ; Check shift-key state
-
- L40: push ds
- mov ax,40h
- mov ds,ax ; DS -> ROM BIOS data area
- mov al,ds:[KB_FLAG] ; AH = ROM BIOS shift-key flags
- pop ds
-
- and al,ds:HotKBMask ; AL = flags AND "don't care" mask
- cmp al,ds:HotKBFlag
- jne L42 ; jump if shift state does not match
-
- ; Set flag when hot key is found
-
- mov byte ptr ds:HotFlag,TRUE
-
- L41: xor bx,bx ; reinitialize index
-
- L42: mov ds:HotIndex,bx ; update index into sequence
- dec ds:InISR9 ; decrement status flag
-
- L43: pop bx ; restore registers and exit
- pop ax
- pop ds
- iret
-
- ISR9 ENDP
-
-
- ISR10 PROC far ; INT 10H handler (ROM BIOS video I/O)
-
- inc cs:InISR10 ; increment status flag
-
- pushf
- cli
- call cs:PrevISR10 ; chain to previous INT 10H handler
-
- dec cs:InISR10 ; decrement status flag
- iret
-
- ISR10 ENDP
-
-
- ISR13 PROC far ; INT 13H handler
- ; (ROM BIOS fixed disk I/O)
-
- inc cs:InISR13 ; increment status flag
-
- pushf
- cli
- call cs:PrevISR13 ; chain to previous INT 13H handler
-
- pushf ; preserve returned flags
- dec cs:InISR13 ; decrement status flag
- popf ; restore flags register
-
- sti ; enable interrupts
- ret 2 ; simulate IRET without popping flags
-
- ISR13 ENDP
-
-
- ISR1B PROC far ; INT 1BH trap (ROM BIOS Ctrl-Break)
-
- mov byte ptr cs:Trap1B,TRUE
- iret
-
- ISR1B ENDP
-
-
- ISR23 PROC far ; INT 23H trap (MS-DOS Ctrl-C)
-
- mov byte ptr cs:Trap23,TRUE
- iret
-
- ISR23 ENDP
-
-
- ISR24 PROC far ; INT 24H trap (MS-DOS critical error)
-
- mov byte ptr cs:Trap24,TRUE
-
- xor al,al ; AL = 00H (MS-DOS 2.x):
- ; ignore the error
- cmp cs:MajorVersion,2
- je L50
-
- mov al,3 ; AL = 03H (MS-DOS 3.x):
- ; fail the MS-DOS call in which
- ; the critical error occurred
- L50: iret
-
- ISR24 ENDP
-
-
- ISR28 PROC far ; INT 28H handler
- ; (MS-DOS idle interrupt)
-
- pushf
- cli
- call cs:PrevISR28 ; chain to previous INT 28H handler
-
- cmp cs:InISR28,0
- jne L61 ; exit if already inside this handler
-
- inc cs:InISR28 ; increment status flag
-
- call VerifyTSRState
- jc L60 ; jump if TSR is inactive
-
- mov byte ptr cs:ActiveTSR,TRUE
- call TSRapp
- mov byte ptr cs:ActiveTSR,FALSE
-
- L60: dec cs:InISR28 ; decrement status flag
-
- L61: iret
-
- ISR28 ENDP
-
-
- ISR2F PROC far ; INT 2FH handler
- ; (MS-DOS multiplex interrupt)
- ; Caller: AH = handler ID
- ; AL = function number
- ; Returns for function 0: AL = 0FFH
- ; for all other functions: nothing
-
- cmp ah,MultiplexID
- je L70 ; jump if this handler is requested
-
- jmp cs:PrevISR2F ; chain to previous INT 2FH handler
-
- L70: test al,al
- jnz MultiplexIRET ; jump if reserved or undefined function
-
- ; Function 0: get installed state
-
- mov al,0FFh ; AL = 0FFh (this handler is installed)
-
- MultiplexIRET: iret ; return from interrupt
-
- ISR2F ENDP
-
- PAGE
- ;
- ;
- ; AuxInt21--sets ErrorMode while executing INT 21h to force use of the
- ; AuxStack instead of the IOStack.
- ;
- ;
-
- AuxInt21 PROC near ; Caller: registers for INT 21H
- ; Returns: registers from INT 21H
-
- push ds
- push bx
- lds bx,ErrorModeAddr
- inc byte ptr [bx] ; ErrorMode is now nonzero
- pop bx
- pop ds
-
- int 21h ; perform MS-DOS function
-
- push ds
- push bx
- lds bx,ErrorModeAddr
- dec byte ptr [bx] ; restore ErrorMode
- pop bx
- pop ds
- ret
-
- AuxInt21 ENDP
-
-
- Int21v PROC near ; perform INT 21H or AuxInt21,
- ; depending on MS-DOS version
-
- cmp DOSVersion,30Ah
- jb L80 ; jump if earlier than 3.1
-
- int 21h ; version 3.1 and later
- ret
-
- L80: call AuxInt21 ; versions earlier than 3.1
- ret
-
- Int21v ENDP
-
- PAGE
- ;------------------------------------------------------------------------------
- ; RAM-resident application
- ;------------------------------------------------------------------------------
-
- TSRapp PROC near
-
- ; Set up a safe stack
-
- push ds ; save previous DS on previous stack
-
- push cs
- pop ds ; DS -> RESIDENT_GROUP
-
- mov PrevSP,sp ; save previous SS:SP
- mov PrevSS,ss
-
- mov ss,TSRSS ; SS:SP -> RESIDENT_STACK
- mov sp,TSRSP
-
- push es ; preserve remaining registers
- push ax
- push bx
- push cx
- push dx
- push si
- push di
- push bp
-
- cld ; clear direction flag
-
- ; Set break and critical error traps
-
- mov cx,NTrap
- mov si,offset RESIDENT_GROUP:StartTrapList
-
- L90: lodsb ; AL = interrupt number
- ; DS:SI -> byte past interrupt number
-
- mov byte ptr [si],FALSE ; zero the trap flag
-
- push ax ; preserve AX
- mov ah,35h ; INT 21H function 35H
- ; (get interrupt vector)
- int 21h ; ES:BX = previous interrupt vector
- mov [si+1],bx ; save offset and segment ..
- mov [si+3],es ; .. of previous handler
-
- pop ax ; AL = interrupt number
- mov dx,[si+5] ; DS:DX -> this TSR's trap
- mov ah,25h ; INT 21H function 25H
- int 21h ; (set interrupt vector)
- add si,7 ; DS:SI -> next in list
-
- loop L90
-
- ; Disable MS-DOS break checking during disk I/O
-
- mov ax,3300h ; AH = INT 21H function number
- ; AL = 00H (request current break state)
- int 21h ; DL = current break state
- mov PrevBreak,dl ; preserve current state
-
- xor dl,dl ; DL = 00H (disable disk I/O break
- ; checking)
- mov ax,3301h ; AL = 01H (set break state)
- int 21h
-
- ; Preserve previous extended error information
-
- cmp DOSVersion,30Ah
- jb L91 ; jump if MS-DOS version earlier
- ; than 3.1
- push ds ; preserve DS
- xor bx,bx ; BX = 00H (required for function 59H)
- mov ah,59h ; INT 21H function 59H
- call Int21v ; (get extended error info)
-
- mov cs:PrevExtErrDS,ds
- pop ds
- mov PrevExtErrAX,ax ; preserve error information
- mov PrevExtErrBX,bx ; in data structure
- mov PrevExtErrCX,cx
- mov PrevExtErrDX,dx
- mov PrevExtErrSI,si
- mov PrevExtErrDI,di
- mov PrevExtErrES,es
-
- ; Inform MS-DOS about current PSP
-
- L91: mov ah,51h ; INT 21H function 51H (get PSP address)
- call Int21v ; BX = foreground PSP
-
- mov PrevPSP,bx ; preserve previous PSP
-
- mov bx,TSRPSP ; BX = resident PSP
- mov ah,50h ; INT 21H function 50H (set PSP address)
- call Int21v
-
- ; Inform MS-DOS about current DTA (not really necessary in this application
- ; because DTA is not used)
-
- mov ah,2Fh ; INT 21H function 2FH
- int 21h ; (get DTA address) into ES:BX
- mov PrevDTAoffs,bx
- mov PrevDTAseg,es
-
- push ds ; preserve DS
- mov ds,TSRPSP
- mov dx,80h ; DS:DX -> default DTA at PSP:0080
- mov ah,1Ah ; INT 21H function 1AH
- int 21h ; (set DTA address)
- pop ds ; restore DS
-
- ; Open a file, write to it, and close it
-
- mov ax,0E07h ; AH = INT 10H function number
- ; (Write Teletype)
- ; AL = 07H (bell character)
- int 10h ; emit a beep
-
- mov dx,offset RESIDENT_GROUP:SnapFile
- mov ah,3Ch ; INT 21H function 3CH
- ; (create file handle)
- mov cx,0 ; file attribute
- int 21h
- jc L94 ; jump if file not opened
-
- push ax ; push file handle
- mov ah,0Fh ; INT 10H function 0FH
- ; (get video status)
- int 10h ; AL = video mode number
- ; AH = number of character columns
- pop bx ; BX = file handle
-
- cmp ah,80
- jne L93 ; jump if not 80-column mode
-
- mov dx,0B800h ; DX = color video buffer segment
- cmp al,3
- jbe L92 ; jump if color alphanumeric mode
-
- cmp al,7
- jne L93 ; jump if not monochrome mode
-
- mov dx,0B000h ; DX = monochrome video buffer segment
-
- L92: push ds
- mov ds,dx
- xor dx,dx ; DS:DX -> start of video buffer
- mov cx,80*25*2 ; CX = number of bytes to write
- mov ah,40h ; INT 21H function 40H (write file)
- int 21h
- pop ds
-
- L93: mov ah,3Eh ; INT 21H function 3EH (close file)
- int 21h
-
- mov ax,0E07h ; emit another beep
- int 10h
-
- ; Restore previous DTA
-
- L94: push ds ; preserve DS
- lds dx,PrevDTA ; DS:DX -> previous DTA
- mov ah,1Ah ; INT 21H function 1AH (set DTA address)
- int 21h
- pop ds
-
- ; Restore previous PSP
-
- mov bx,PrevPSP ; BX = previous PSP
- mov ah,50h ; INT 21H function 50H
- call Int21v ; (set PSP address)
-
- ; Restore previous extended error information
-
- mov ax,DOSVersion
- cmp ax,30AH
- jb L95 ; jump if MS-DOS version earlier than 3.1
- cmp ax,0A00h
- jae L95 ; jump if MS OS/2-DOS 3.x box
-
- mov dx,offset RESIDENT_GROUP:PrevExtErrInfo
- mov ax,5D0Ah
- int 21h ; (restore extended error information)
-
- ; Restore previous MS-DOS break checking
-
- L95: mov dl,PrevBreak ; DL = previous state
- mov ax,3301h
- int 21h
-
- ; Restore previous break and critical error traps
-
- mov cx,NTrap
- mov si,offset RESIDENT_GROUP:StartTrapList
- push ds ; preserve DS
-
- L96: lods byte ptr cs:[si] ; AL = interrupt number
- ; ES:SI -> byte past interrupt number
-
- lds dx,cs:[si+1] ; DS:DX -> previous handler
- mov ah,25h ; INT 21H function 25H
- int 21h ; (set interrupt vector)
- add si,7 ; DS:SI -> next in list
- loop L96
-
- pop ds ; restore DS
-
- ; Restore all registers
-
- pop bp
- pop di
- pop si
- pop dx
- pop cx
- pop bx
- pop ax
- pop es
-
- mov ss,PrevSS ; SS:SP -> previous stack
- mov sp,PrevSP
- pop ds ; restore previous DS
-
- ; Finally, reset status flag and return
-
- mov byte ptr cs:HotFlag,FALSE
- ret
-
- TSRapp ENDP
-
-
- RESIDENT_TEXT ENDS
-
-
- RESIDENT_DATA SEGMENT word public 'DATA'
-
- ErrorModeAddr DD ? ; address of MS-DOS ErrorMode flag
- InDOSAddr DD ? ; address of MS-DOS InDOS flag
-
- NISR DW (EndISRList-StartISRList)/8 ; number of installed ISRs
-
- StartISRList DB 05h ; INT number
- InISR5 DB FALSE ; flag
- PrevISR5 DD ? ; address of previous handler
- DW offset RESIDENT_GROUP:ISR5
-
- DB 08h
- InISR8 DB FALSE
- PrevISR8 DD ?
- DW offset RESIDENT_GROUP:ISR8
-
- DB 09h
- InISR9 DB FALSE
- PrevISR9 DD ?
- DW offset RESIDENT_GROUP:ISR9
-
- DB 10h
- InISR10 DB FALSE
- PrevISR10 DD ?
- DW offset RESIDENT_GROUP:ISR10
-
- DB 13h
- InISR13 DB FALSE
- PrevISR13 DD ?
- DW offset RESIDENT_GROUP:ISR13
-
- DB 28h
- InISR28 DB FALSE
- PrevISR28 DD ?
- DW offset RESIDENT_GROUP:ISR28
-
- DB 2Fh
- InISR2F DB FALSE
- PrevISR2F DD ?
- DW offset RESIDENT_GROUP:ISR2F
-
- EndISRList LABEL BYTE
-
- TSRPSP DW ? ; resident PSP
- TSRSP DW TSRStackSize ; resident SS:SP
- TSRSS DW seg RESIDENT_STACK
- PrevPSP DW ? ; previous PSP
- PrevSP DW ? ; previous SS:SP
- PrevSS DW ?
-
- HotIndex DW 0 ; index of next scan code in sequence
- HotSeqLen DW EndHotSeq-HotSequence ; length of hot-key sequence
-
- HotSequence DB SCEnter ; hot sequence of scan codes
- EndHotSeq LABEL BYTE
-
- HotKBFlag DB KBAlt ; hot value of ROM BIOS KB_FLAG
- HotKBMask DB (KBIns OR KBCaps OR KBNum OR KBScroll) XOR 0FFh
- HotFlag DB FALSE
-
- ActiveTSR DB FALSE
-
- DOSVersion LABEL WORD
- DB ? ; minor version number
- MajorVersion DB ? ; major version number
-
- ; The following data is used by the TSR application:
-
- NTrap DW (EndTrapList-StartTrapList)/8 ; number of traps
-
- StartTrapList DB 1Bh
- Trap1B DB FALSE
- PrevISR1B DD ?
- DW offset RESIDENT_GROUP:ISR1B
-
- DB 23h
- Trap23 DB FALSE
- PrevISR23 DD ?
- DW offset RESIDENT_GROUP:ISR23
-
- DB 24h
- Trap24 DB FALSE
- PrevISR24 DD ?
- DW offset RESIDENT_GROUP:ISR24
-
- EndTrapList LABEL BYTE
-
- PrevBreak DB ? ; previous break-checking flag
-
- PrevDTA LABEL DWORD ; previous DTA address
- PrevDTAoffs DW ?
- PrevDTAseg DW ?
-
- PrevExtErrInfo LABEL BYTE ; previous extended error information
- PrevExtErrAX DW ?
- PrevExtErrBX DW ?
- PrevExtErrCX DW ?
- PrevExtErrDX DW ?
- PrevExtErrSI DW ?
- PrevExtErrDI DW ?
- PrevExtErrDS DW ?
- PrevExtErrES DW ?
- DW 3 dup(0)
-
- SnapFile DB '\snap.img' ; output filename in root directory
-
- RESIDENT_DATA ENDS
-
- RESIDENT_STACK SEGMENT word stack 'STACK'
-
- DB TSRStackSize dup(?)
-
- RESIDENT_STACK ENDS
-
- PAGE
- ;------------------------------------------------------------------------------
- ;
- ; Transient installation routines
- ;
- ;------------------------------------------------------------------------------
-
- TRANSIENT_TEXT SEGMENT para public 'TCODE'
- ASSUME cs:TRANSIENT_TEXT,ds:RESIDENT_DATA,ss:RESIDENT_STACK
-
- InstallSnapTSR PROC far ; At entry: CS:IP -> InstallSnapTSR
- ; SS:SP -> stack
- ; DS,ES -> PSP
- ; Save PSP segment
-
- mov ax,seg RESIDENT_DATA
- mov ds,ax ; DS -> RESIDENT_DATA
-
- mov TSRPSP,es ; save PSP segment
-
- ; Check the MS-DOS version
-
- call GetDOSVersion ; AH = major version number
- ; AL = minor version number
-
- ; Verify that this TSR is not already installed
- ;
- ; Before executing INT 2Fh in MS-DOS versions 2.x, test whether INT 2FH
- ; vector is in use. If so, abort if PRINT.COM is using it.
- ;
- ; (Thus, in MS-DOS 2.x, if both this program and PRINT.COM are used,
- ; this program should be made resident before PRINT.COM.)
-
- cmp ah,2
- ja L101 ; jump if version 3.0 or later
-
- mov ax,352Fh ; AH = INT 21H function number
- ; AL = interrupt number
- int 21h ; ES:BX = INT 2FH vector
-
- mov ax,es
- or ax,bx ; jump if current INT 2FH vector ..
- jnz L100 ; .. is nonzero
-
- push ds
- mov ax,252Fh ; AH = INT 21H function number
- ; AL = interrupt number
- mov dx,seg RESIDENT_GROUP
- mov ds,dx
- mov dx,offset RESIDENT_GROUP:MultiplexIRET
-
- int 21h ; point INT 2FH vector to IRET
- pop ds
- jmp short L103 ; jump to install this TSR
-
- L100: mov ax,0FF00h ; look for PRINT.COM:
- int 2Fh ; if resident, AH = print queue length;
- ; otherwise, AH is unchanged
-
- cmp ah,0FFh ; if PRINT.COM is not resident ..
- je L101 ; .. use multiplex interrupt
-
- mov al,1
- call FatalError ; abort if PRINT.COM already installed
-
- L101: mov ah,MultiplexID ; AH = multiplex interrupt ID value
- xor al,al ; AL = 00H
- int 2Fh ; multiplex interrupt
-
- test al,al
- jz L103 ; jump if ok to install
-
- cmp al,0FFh
- jne L102 ; jump if not already installed
-
- mov al,2
- call FatalError ; already installed
-
- L102: mov al,3
- call FatalError ; can't install
-
- ; Get addresses of InDOS and ErrorMode flags
-
- L103: call GetDOSFlags
-
- ; Install this TSR's interrupt handlers
-
- push es ; preserve PSP segment
-
- mov cx,NISR
- mov si,offset StartISRList
-
- L104: lodsb ; AL = interrupt number
- ; DS:SI -> byte past interrupt number
- push ax ; preserve AX
- mov ah,35h ; INT 21H function 35H
- int 21h ; ES:BX = previous interrupt vector
- mov [si+1],bx ; save offset and segment ..
- mov [si+3],es ; .. of previous handler
-
- pop ax ; AL = interrupt number
- push ds ; preserve DS
- mov dx,[si+5]
- mov bx,seg RESIDENT_GROUP
- mov ds,bx ; DS:DX -> this TSR's handler
- mov ah,25h ; INT 21H function 25H
- int 21h ; (set interrupt vector)
- pop ds ; restore DS
- add si,7 ; DS:SI -> next in list
- loop L104
-
- ; Free the environment
-
- pop es ; ES = PSP segment
- push es ; preserve PSP segment
- mov es,es:[2Ch] ; ES = segment of environment
- mov ah,49h ; INT 21H function 49H
- int 21h ; (free memory block)
-
- ; Terminate and stay resident
-
- pop ax ; AX = PSP segment
- mov dx,cs ; DX = paragraph address of start of
- ; transient portion (end of resident
- ; portion)
- sub dx,ax ; DX = size of resident portion
-
- mov ax,3100h ; AH = INT 21H function number
- ; AL = 00H (return code)
- int 21h
-
- InstallSnapTSR ENDP
-
-
- GetDOSVersion PROC near ; Caller: DS = seg RESIDENT_DATA
- ; ES = PSP
- ; Returns: AH = major version
- ; AL = minor version
- ASSUME ds:RESIDENT_DATA
-
- mov ax,30h ; INT 21h function 30H:
- ; (get MS-DOS version)
- int 21h
- cmp al,2
- jb L110 ; jump if version 1.x
-
- xchg ah,al ; AH = major version
- ; AL = minor version
- mov DOSVersion,ax ; save with major version in
- ; high-order byte
- ret
-
- L110: mov al,00h
- call FatalError ; abort if version 1.x
-
- GetDOSVersion ENDP
- GetDOSFlags PROC near ; Caller: DS = seg RESIDENT_DATA
- ; Returns: InDOSAddr -> InDOS
- ; ErrorModeAddr -> ErrorMode
- ; Destroys: AX,BX,CX,DI
- ASSUME ds:RESIDENT_DATA
-
- ; Get InDOS address from MS-DOS
-
- push es
-
- mov ah,34h ; INT 21H function number
- int 21h ; ES:BX -> InDOS
- mov word ptr InDOSAddr,bx
- mov word ptr InDOSAddr+2,es
-
- ; Determine ErrorMode address
-
- mov word ptr ErrorModeAddr+2,es ; assume ErrorMode is
- ; in the same segment
- ; as InDOS
-
- mov ax,DOSVersion
- cmp ax,30Ah
- jb L120 ; jump if MS-DOS version earlier
- ; than 3.1 ..
- cmp ax,0A00h
- jae L120 ; .. or MS OS/2-DOS 3.x box
-
- dec bx ; in MS-DOS 3.1 and later, ErrorMode
- mov word ptr ErrorModeAddr,bx ; is just before InDOS
- jmp short L125
-
- L120: ; scan MS-DOS segment for ErrorMode
-
- mov cx,0FFFFh ; CX = maximum number of bytes to scan
- xor di,di ; ES:DI -> start of MS-DOS segment
-
- L121: mov ax,word ptr cs:LF2 ; AX = opcode for INT 28H
-
- L122: repne scasb ; scan for first byte of fragment
- jne L126 ; jump if not found
-
- cmp ah,es:[di] ; inspect second byte of opcode
- jne L122 ; jump if not INT 28H
-
- mov ax,word ptr cs:LF1 + 1 ; AX = opcode for CMP
- cmp ax,es:[di][LF1-LF2]
- jne L123 ; jump if opcode not CMP
-
- mov ax,es:[di][(LF1-LF2)+2] ; AX = offset of ErrorMode
- jmp short L124 ; in DOS segment
-
- L123: mov ax,word ptr cs:LF3 + 1 ; AX = opcode for TEST
- cmp ax,es:[di][LF3-LF4]
- jne L121 ; jump if opcode not TEST
-
- mov ax,es:[di][(LF3-LF4)+2] ; AX = offset of ErrorMode
-
- L124: mov word ptr ErrorModeAddr,ax
-
- L125: pop es
- ret
-
- ; Come here if address of ErrorMode not found
-
- L126: mov al,04H
- call FatalError
-
-
- ; Code fragments for scanning for ErrorMode flag
-
- LFnear LABEL near ; dummy labels for addressing
- LFbyte LABEL byte
- LFword LABEL word
- ; MS-DOS versions earlier than 3.1
- LF1: cmp ss:LFbyte,0 ; CMP ErrorMode,0
- jne LFnear
- LF2: int 28h
- ; MS-DOS versions 3.1 and later
-
- LF3: test ss:LFbyte,0FFh ; TEST ErrorMode,0FFH
- jne LFnear
- push ss:LFword
- LF4: int 28h
-
- GetDOSFlags ENDP
-
- FatalError PROC near ; Caller: AL = message number
- ; ES = PSP
- ASSUME ds:TRANSIENT_DATA
-
- push ax ; save message number on stack
-
- mov bx,seg TRANSIENT_DATA
- mov ds,bx
-
- ; Display the requested message
-
- mov bx,offset MessageTable
- xor ah,ah ; AX = message number
- shl ax,1 ; AX = offset into MessageTable
- add bx,ax ; DS:BX -> address of message
- mov dx,[bx] ; DS:BX -> message
- mov ah,09h ; INT 21H function 09H (display string)
- int 21h ; display error message
-
- pop ax ; AL = message number
- or al,al
- jz L130 ; jump if message number is zero
- ; (MS-DOS versions 1.x)
-
- ; Terminate (MS-DOS 2.x and later)
-
- mov ah,4Ch ; INT 21H function 4CH
- int 21h ; (terminate process with return code)
-
- ; Terminate (MS-DOS 1.x)
-
- L130 PROC far
-
- push es ; push PSP:0000H
- xor ax,ax
- push ax
- ret ; far return (jump to PSP:0000H)
-
- L130 ENDP
-
- FatalError ENDP
-
-
- TRANSIENT_TEXT ENDS
-
- PAGE
- ;
- ;
- ; Transient data segment
- ;
- ;
-
- TRANSIENT_DATA SEGMENT word public 'DATA'
-
- MessageTable DW Message0 ; MS-DOS version error
- DW Message1 ; PRINT.COM found in MS-DOS 2.x
- DW Message2 ; already installed
- DW Message3 ; can't install
- DW Message4 ; can't find flag
-
- Message0 DB CR,LF,'TSR requires MS-DOS 2.0 or later version',CR,LF,'$'
- Message1 DB CR,LF,'Can''t install TSR: PRINT.COM active',CR,LF,'$'
- Message2 DB CR,LF,'This TSR is already installed',CR,LF,'$'
- Message3 DB CR,LF,'Can''t install this TSR',CR,LF,'$'
- Message4 DB CR,LF,'Unable to locate MS-DOS ErrorMode flag',CR,LF,'$'
-
- TRANSIENT_DATA ENDS
-
- END InstallSnapTSR
-