home *** CD-ROM | disk | FTP | other *** search
- ;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