Category : Files from Magazines
Archive   : VOL7N1.ZIP
Filename : CAPTURE.ASM
Output of file : CAPTURE.ASM contained in archive : VOL7N1.ZIP
; 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 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 INC_NEXT_CHAR
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
Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!
This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.
But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/