home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Source Code 1992 March
/
Source_Code_CD-ROM_Walnut_Creek_March_1992.iso
/
msdos
/
info
/
help_7n1.arc
/
CAPTURE.ASM
next >
Wrap
Assembly Source File
|
1987-10-30
|
16KB
|
476 lines
;from VOL7N1.ARC, PC Magazine Jan 88?
;----------------------------------------------------------------------
; CAPTURE is a resident utility which copies an 80x25 screen buffer
; to a file. Activate CAPTURE by pressing ALT-C or any other hot
; key combination defined by the symbols HOTKEY and SHIFT_MASK.
; The filename will be SCREEN.n. The extension begins with .000 and
; is incremented by one each time CAPTURE is activated.
;-----------------------------------------------------------------------
; BIOS_SEG is located in the ROM-BIOS data area
;-----------------------------------------------------------------------
BIOS_SEG SEGMENT AT 0040H
ORG 0017H
KB_FLAG DB ? ;BIOS keyboard shift status
ORG 004AH
CRT_COLS DB ? ;Current number of screen columns
ORG 0050H
CURSOR_POSN DW 8 DUP(?) ;Current cursor location
ORG 0062H
ACTIVE_PAGE DB ? ;Active page for CGA and EGA
BIOS_SEG ENDS
;=======================================================================
CSEG SEGMENT
ASSUME CS:CSEG, DS:CSEG, ES:CSEG
ORG 0100H ;Beginning for .COM programs
START: jmp Initialize ;Initialization code is at end
;-----------------------------------------------------------------------
; Data needed by this program
;-----------------------------------------------------------------------
HOTKEY EQU 2EH ;Scan code for "C" key
SHIFT_MASK EQU 00001000B ;Mask for ALT key held down
COPYRIGHT DB "CAPTURE 1.0 (c) 1987 Ziff Communications Co"
DB 13,10,"Hotkey is ALT-C$",1Ah
PROGRAMMER DB "Tom Kihlken"
INSTALLED_MSG DB 13,10,"Already Installed$"
FILENAME DB "SCREEN.000",0 ;The first filename
OLDINT09 DD ? ;Old hardware keyboard interrupt vector
OLDINT13 DD ? ;Old BIOS disk IO interrupt vector
OLDINT16 DD ? ;Old keyboard input interrupt vector
OLDINT21 DD ? ;Old DOS function interrupt vector
WRIT_FILE DB 0 ;If=1, need to write to disk
ACTIVE DB 0 ;Indicated CAPTURE is in use
DOS_STAT DB 0 ;Current DOS function indicator
BUSY_FLAGS DB 0 ;Bit masked as follows:
; 1 - DOS function is active
; 2 - BIOS disk IO is active
;-----------------------------------------------------------------------
; CAPTURE reads the screen and stores it in an internal buffer.
;-----------------------------------------------------------------------
Capture proc NEAR
ASSUME DS:CSEG, ES:BIOS_SEG
call Get_Curs_Addr ;Cursor addr for this page
PUSH ES:[BX] ;Save the cursor location
mov DI,OFFSET BUFFER ;DS:DI points to the buffer
xor DX,DX ;Start at row 0, column 0
Read_Loop:
cmp DL,CRT_COLS ;Past right edge of screen?
jl Not_Past_Edge ;If screen is less than 80
mov AX,0720H ;columns, then pad with a blank
jmp SHORT Buff_Char
Not_Past_Edge:
call Get_Curs_Addr ;Get address of BIOS cursor
mov ES:[BX],DX ;Tell BIOS where the cursor is
mov BH,ACTIVE_PAGE ;Get active page from BIOS data
mov AH,8 ;BIOS function to read character
int 10H ;Read the character/attribute
Buff_Char:
mov [DI],AX ;Put the character in buffer
inc DI ;Increment the pointer twice
inc DI ;Since we stored a word
inc DL ;Do the next char in same row
cmp DL,80 ;At the right border yet?
jl Read_Loop ;Do 80 characters in this row
inc DH ;Move to next row
xor DL,DL ;Back to left edge (Column 0)
cmp DH,25 ;Done all 25 rows yet?
jl Read_Loop ;Loop until whole screen is read
call Get_Curs_Addr ;Cursor address for this page
POP ES:[BX] ;Recover the cursor position
RET ;Then were finished
Capture ENDP
;-----------------------------------------------------------------------
; This procedure obtains the address of the cursor position for this page
;-----------------------------------------------------------------------
Get_Curs_Addr proc NEAR
ASSUME DS:CSEG, ES:BIOS_SEG
mov BL,ACTIVE_PAGE ;Get the current page number
xor BH,BH ;Convert to a word offset
SHL BX,1 ;Times two for a word
ADD BX,OFFSET CURSOR_POSN ;Add base cursor address
RET
Get_Curs_Addr ENDP
;-----------------------------------------------------------------------
; This copies the buffer contents to a file. It should only be called
; when DOS is in a stable and reentrant condition.
;-----------------------------------------------------------------------
Write_To_File proc NEAR
ASSUME DS:NOTHING, ES:NOTHING
mov WRIT_FILE,0 ;Turn off request flag
STI ;Get interrupts back on
push AX ;Must preserve all registers
push BX
push CX
push DX
push BP
push DS
push ES
push CS
pop DS
ASSUME DS:CSEG ;DS points to out code segment
mov AX,3524H ;Get DOS critical error vector
call DOS_Function ;Do the DOS function
push BX ;Save old INT 24 vector on stack
push ES
; Replace the DOS severe error interrupt with out own routine.
mov DX,OFFSET NewInt24
mov AX,2524H ;Setup to change INT 24h vector
call DOS_Function ;DOS function to change vector
; Try to open the file to determine if it already exists. If it does,
; then just close it and increment the filename.
Open_File: mov DX,OFFSET FILENAME ;DS:DX points to filename
mov AX,3D00H ;Opin file for read access
call DOS_Function ;Do the DOS function
jc Open_Error ;If open error, take jump
mov BX,AX ;Need the handle in BX
mov AH,3EH ;Close this file
call DOS_Function ;Do the DOS function
call Inc_Filename ;Try the next filename
jmp short Open_File
Open_Error:
cmp AX,2 ;Was it file not found error?
jne DOS_Err_Exit ;Exit on any other error
; Now create the file, then write buffer contents and close it.
mov DX,OFFSET FILENAME ;DS:DX points to filename
mov CX,0020H ;Attribute for new file
mov AH,3CH ;Create file for writing
call DOS_Function ;Do the DOS function
jc Close_File ;On any error, take jump
mov BX,AX ;Save handle in BX
mov DX,OFFSET BUFFER ;Point to output buffer
mov CX,4000 ;Write 4000 bytes
mov AH,40H ;DOS write to a device function
call DOS_Function ;Do the DOS function
Close_File:
mov AH,3EH ;DOS function to close the file
call DOS_Function ;Do the DOS function
call Inc_Filename ;Move to next filename
DOS_Err_Exit: pop DS ;Get INT 24H vector from stack
ASSUME DS:NOTHING
pop DX
mov AX,2524H ;Restore critical error vector
call DOS_Function ;Do the DOS function
pop ES ;Finally restore all registers
pop DS
pop BP
pop DX
pop CX
pop BX
pop AX
mov ACTIVE,0 ;CAPTURE is done now
RET ;Finished writing to disk
Write_To_File ENDP
;-----------------------------------------------------------------------
; This routine does a dos function by calling the old interrupt vector
;-----------------------------------------------------------------------
ASSUME DS:NOTHING, ES:NOTHING
DOS_Function proc NEAR
PUSHF ;These instructions simulate
CLI ;an interrupt
call CS:OLDINT21 ;Do the DOS function
STI
RET
DOS_Function ENDP
;-----------------------------------------------------------------------
; This procedure increments the extension for the filename.
;-----------------------------------------------------------------------
Inc_Filename proc NEAR
mov BX,OFFSET FILENAME+9 ;Point to last letter
Inc_Next_Char:
inc BYTE PTR [BX] ;Increment the extension
cmp BYTE PTR [BX],"9" ;Check for carry
jle Inc_Return ;If none, were finished
mov BYTE PTR [BX],"0" ;Set this digit to zero
dec BX ;Backup to next digit
cmp BX,OFFSET FILENAME+6 ;Dont increment the dot
; jle Inc_Return
; jmp short Inc_Next_Char
ja Inc_Next_Char ;TH
Inc_Return:
RET
Inc_Filename ENDP
;-----------------------------------------------------------------------
; Interrupt 09 (Keyboard) Watch for trigger key. When found, ignore
; it and execute the CAPTURE routine.
;-----------------------------------------------------------------------
NewInt09 proc FAR
ASSUME DS:NOTHING, ES:NOTHING
STI ;Allow other interrupts
push AX ;Must save processor state
IN AL,60H ;Get the scan code
cmp AL,HOTKEY ;Is it the hot key?
je Trigger ;If yes, check the mask
Int09_Exit: pop AX ;Restore the processor state
jmp CS:OLDINT09 ;Continue with ROM routine
Trigger:
push DS ;Preserve DS register
mov AX,BIOS_SEG ;Get BIOS data segment
mov DS,AX ;Put it in a segment register
ASSUME DS:BIOS_SEG
mov AL,KB_FLAG ;Shift flags
and AL,0FH ; only
cmp AL,SHIFT_MASK ;Is the ALT key down?
pop DS ;Restore DS register
ASSUME DS:NOTHING
jne Int09_Exit ;If ALT not down, ignore it
;Reset the keyboard and 8259 interrutp controller
IN AL,61H
mov AH,AL
or AL,80H ;Reset bit for keyboard
OUT 61H,AL ;Reset the keyboard
mov AL,AH
jmp SHORT $+2 ;A short delay
OUT 61H,AL ;Reenable keyboard
CLI
mov AL,20H
OUT 20H,AL ;Reset interrupt controller
STI
cmp ACTIVE,0 ;Is CAPTURE already active?
jnz Short_Ret ;If active, then exit
mov ACTIVE,1 ;Its active now
push BX ;Must preserve all registers
push CX
push DX
push BP
push DI
push DS
push ES
push CS
pop DS ;Set DS to CSEG
mov AX,BIOS_SEG ;ES points to BIOS data area
mov ES,AX
ASSUME DS:CSEG, ES:BIOS_SEG ;Assembler directives
call Capture ;Read the screen contents
mov WRIT_FILE,1 ;Indicate need to flush buffer
pop ES ;Restore all registers
pop DS
pop DI
pop BP
pop DX
pop CX
pop BX
ASSUME DS:NOTHING, ES:NOTHING
TEST BUSY_FLAGS,011B ;Is DOS or BIOS disk busy?
jnz Short_Ret ;If yes, then we must wait
call Write_To_File ;Otherwise, we'll do it now
Short_Ret:
pop AX ;Stack must be restored
IRET ;Now were all done
NewInt09 ENDP
;-----------------------------------------------------------------------
; Interrupt 13H (BIOS diskette I/O) Set the busy flag during diskette I/O
;-----------------------------------------------------------------------
NewInt13 proc FAR
ASSUME DS:NOTHING, ES:NOTHING
PUSHF
or CS:BUSY_FLAGS,010B ;Set BIOS busy bit
POPF
PUSHF ;This simulates an interrupt
call CS:OLDINT13 ;Do the BIOS function
PUSHF ;Save result flags
and BUSY_FLAGS,11111101B ;Clear BIOS busy bit
POPF ;Get back result flags
STI ;Must return with interrupts on
RET 2 ;Return BIOS result flags
NewInt13 ENDP
;-----------------------------------------------------------------------
; Interrupt 16H (BIOS keyboard interface) Check to see if the buffer
; needs to be written.
;-----------------------------------------------------------------------
NewInt16 proc FAR
ASSUME DS:NOTHING, ES:NOTHING
cmp CS:WRIT_FILE,1 ;Anything to write to disk?
je Check_DOS_Stat ;If yes, see what DOS is doing
Bios_Kb:
jmp CS:OLDINT16 ;Just do normal KB routine
Check_DOS_Stat:
cmp CS:DOS_STAT,0AH ;Doing read string?
je Begin_Now ;If yes, its safe to begin
cmp CS:DOS_STAT,08H ;Doing keybaord input?
jne Bios_Kb ;If yes, its safe to begin
Begin_Now:
call Write_To_File ;Write the buffer to disk
or CS:BUSY_FLAGS,001B ;Reset DOS busy bit
jmp CS:Bios_Kb ;Continue with BIOS routine
NewInt16 ENDP
;-----------------------------------------------------------------------
; Interrupt 21H (DOS functions) Used to keep track of DOS function calls
;-----------------------------------------------------------------------
NewInt21 proc FAR
ASSUME DS:NOTHING, ES:NOTHING
PUSHF ;Save the flags
mov CS:DOS_STAT,AH ;Store the function number
or CS:BUSY_FLAGS,001B ;Set DOS busy bit
or AH,AH ;Doing function zero?
jz Jump_To_DOS ;If yes, take the jump
cmp AH,4BH ;Doing EXEC function?
je Jump_To_DOS ;If yes, take the jump
POPF
PUSHF
call CS:OLDINT21 ;Do the DOS function
PUSHF ;Ssve the result flags
and CS:BUSY_FLAGS,11111110B ;Clear DOS busy bit
cmp CS:WRIT_FILE,1 ;Anything to write to disk?
jne No_Write ;If not just return
call Write_To_File ;Safe to access disk now
No_Write:
POPF ;Recover DOS result flags
STI ;Must return with interrupts on
RET 2 ;Return with DOS result flags
Jump_To_DOS:
POPF
jmp CS:OLDINT21
NewInt21 ENDP
;-----------------------------------------------------------------------
; Interrupt 24H (critical DOS error). This interrupt is only in
; effect during a write screen. It is required to suppress the
; 'Abort, Retry, Ignore' message. All fatal disk errors are ignored.
;-----------------------------------------------------------------------
NewInt24 proc FAR
ASSUME DS:NOTHING, ES:NOTHING
xor AL,AL ;Tells DOS to ignore the error
IRET ;Thats all we do here
NewInt24 ENDP
;----------------------------------------------------------------------
; This are is overwritten by the dynamic buffers.
;----------------------------------------------------------------------
PC = $
BUFFER = PC
PC = PC+4000
LASTBYTE = PC
;-----------------------------------------------------------------------
; Here is the code used to initialize CAPTURE. It is not keep resident.
; The buffer is located here and overlays the initialization code.
;-----------------------------------------------------------------------
ASSUME CS:CSEG, DS:CSEG, ES:NOTHING
Initialize proc NEAR
mov DX,OFFSET COPYRIGHT
mov AH,9 ;DOS display string service
int 21H ;Display title message
; Search for a previously installed copy of CAPTURE
not WORD PTR START ;Modify to avoid false match
xor BX,BX ;Start search at segment zero
mov AX,CS ;Compare to this code segment
Next_Segment:
inc BX ;Look at next segment
cmp AX,BX ;Until reaching this code seg
mov ES,BX
je Not_Installed
mov SI,OFFSET START ;Setup to compare strings
mov DI,SI
mov CX,16 ;16 bytes must match
rep CMPSB ;Compare DS:SI to ES:DI
or CX,CX ;Did the strings match?
jnz Next_Segment ;If no match, try next segment
mov DX,OFFSET INSTALLED_MSG ;else, exit with error
mov AH,9
int 21H
mov AX,4C01H
int 21H
Not_Installed:
mov AX,3509H ;Get keyboard break vector
int 21H
mov WORD PTR [OLDINT09], BX ;Save segment
mov WORD PTR [OLDINT09+2],ES ;Save offset
mov DX, OFFSET NewInt09
mov AX, 2509H
int 21H ;DOS function to change vector
mov AX,3513H ;Get BIOS disk interrupt vector
int 21H
mov WORD PTR [OLDINT13], BX ;Save the segment
mov WORD PTR [OLDINT13+2],ES ;Save the offset
mov DX, OFFSET NewInt13
mov AX, 2513H
int 21H ;DOS function to change vector
mov AX,3516H ;Get keyboard input vector
int 21H
mov WORD PTR [OLDINT16], BX ;Save the segment
mov WORD PTR [OLDINT16+2],ES ;Save the offset
mov DX, OFFSET NewInt16
mov AX, 2516H
int 21H ;DOS function to change vector
mov AX,3521H ;Get DOS function vector
int 21H
mov WORD PTR [OLDINT21], BX
mov WORD PTR [OLDINT21+2],ES
mov DX, OFFSET NewInt21
mov AX, 2521H
int 21H ;DOS function to change vector
;-----------------------------------------------------------------------
; Deallocate our copy of the enviornment.
; Leave code and space for the buffer resident.
;-----------------------------------------------------------------------
mov AX,DS:[002CH] ;Get segment of enviornment
mov ES,AX ;Put it into ES
mov AH,49H ;Release allocated memory
int 21H
mov DX,(OFFSET LASTBYTE - OFFSET CSEG + 15)SHR 4
mov AX,3100H
int 21H
Initialize ENDP
CSEG ENDS
END START