Here it is...

PAGE 46,132
TITLE PRTSCFF4.ASM - PRTSCFF4.SYS DEVICE DRIVER
;====================================================================
;
; PRTSCFF4.ASM
;
;  Copyright (C) 1995 J.A. Keuter. All Rights Reserved.
;
; CONTAINS: All the code to create the PRTSCFF4.SYS device driver
;
; IMPLEMENTATION DETAILS:
;
;  This code contains a complete DOS character device. It has a device
;  header with attributes and pointers to the strategy and interrupt
;  functions.
;
;  This device driver functions as follows:
;
;  * On initial load by ??DOS.SYS and on any call made to the device driver
;    a request packet is passed to the strategy procedure. It stores the
;    packet address for the interrupt procedure that will be called next.
;
;  * The interrupt function checks the request.
;
;    + If it's the initialize request the device driver initializes by
;      installing an interrupt handler on INT 05h (the Print Screen
;      interrupt) and INT 10h (the video interrupt). Then the commandline is
;      scanned for a parameter containing a 'Q'. If it's not found a banner
;      is printed. The start address of the initialization code is returned
;      to the operating system so memory can be free'd from there on. This
;      is possible because initialize is only requested upon loading of the
;      device driver.
;
;    + If it's the open request the device driver will check if it is still
;      in possession of the INT 05h (Print Screen interrupt). If it's not
;      (another program took over) it reinstalls itself on the interrupt.
;      It also resets it's receive buffer so it can receive a new output
;      request.
;
;    + If it's the close request the device driver does nothing. It has to
;      respond to it because it responds to open.
;
;    + If it's the output status request the driver will fetch the current
;      receive status and return this.
;
;    + If it's the output or output and verify request a number of things
;      get done:
;
;      The referenced output buffer is copied into a receive buffer as
;      long as it fits. After the copy the buffer is checked if it starts
;      with a valid command, a 01h/02h byte. If not it's illegal access and
;      a write protect error is returned. If it's oke though the receive
;      buffer is scanned for a 00h byte which indicates the end of the
;      command is received. If it is, the 00h byte is replaced by a space.
;      Depending on the command byte the received data is either copied into
;      the printer codes section, so it gets printed next time, or is used
;      to set the printer port number to use. Finally the receive buffer and
;      status are cleared for the next command.
;
;    + if it's the non-destructive input request the driver will tell
;      there's no data available to read. This is added because MSDOS
;      irregularly ask if any input data is available.
;
;    + If it's neither one of these requests an unknown command error is
;      returned. This should only occur as a result of illegal access.
;
;  * Besides device requests there are two other ways to activate the device
;    driver:
;
;    + INT 05h (Print Screen). This is the primary entry. Once this
;      interrupt is called the device driver gets in full operation.
;
;    + INT 10h (video). This one is used to check if something is changed
;      about the system Print Screen routine. The device driver has to adapt
;      to this, by retaking INT 05h.
;
;  * The INT 05h handler gets the request to print the screen. It checks to
;    see whether or not the current video mode is a text mode. Depending on
;    this it will act or pass the request on to the original handler.
;    First the PCL 3 printer commands to setup the printer are send using
;    INT 17h. Then the screen characters are read line-by-line from video
;    memory using cursor positioning and send to the printer. To avoid
;    having the cursor racing about on screen we switch it off first. In
;    between lines spaces are send to center the screen print on paper. A
;    code is send to let the printer print the screen data transparently, so
;    it won't get confused about funny characters. Finally a printer reset
;    command is send to eject the page and restore the printer to its
;    original state. The cursor is restored too.
;
;  * The INT 10h handler checks the video interrupt for the set alternate
;    print screen request. If it has found it, the handler passes it through
;    to the video BIOS after which it retakes INT 05h (Print Screen
;    interrupt)
;
;
; MODIFICATIONS
;
;  January 8, 1995      0.01 : J.A. Keuter
;   Created from PASSWRD5.ASM by David Kirschbaum, Toad Hall &
;   John R. Petrocelli.
;
;  January 10, 1995     1.00 : J.A. Keuter
;   Many trial and error runs made me make several changes and improvements.
;   It's ready for release.
;
;  January 12, 1995     2.00 : J.A. Keuter
;   Difficulty with the interception of the INT 05h print screen interrupt
;   lead to another approach. Instead of INT 05h the printer interrupt
;   INT 17h is used. Added PCL 3 support.
;
;  January 15, 1995     3.00 : J.A. Keuter
;   Fix for INT 05h print screen interrupt found. Returning to original
;   design using knowledge of version 2.00, especially PCL 3 support.
;
;  February 5, 1995     4.00 : J.A. Keuter
;   Changed design to avoid video BIOS print screen routine all together.
;   Added open and close request processing to make easy reinstall possible.
;   Added output capability to be able to set username.
;
;  February 9, 1995     4.01 : J.A. Keuter
;   Changed effect of username setting. Now 'Username' string gets set
;   by the configuration utility. Added printer data transparency.
;
;  June 6, 1995         4.02 : J.A. Keuter
;   Added write() check to configuration utility.
;
;  June 20, 1995        4.03 : J.A. Keuter
;   Added printer port selection code.
;

;====================================================================
;Useful symbol definitions and device request structure.

;Semaphores

SEMCLEAR        EQU     0
SEMSET          EQU     1

;ASCII characters

ESCAPE          EQU     01Bh
LF              EQU     0Ah
CR              EQU     0Dh
TAB             EQU     08h
SPACE           EQU     020h

;Printer numbers

LPT1            EQU     00h
LPT2            EQU     01h
LPT3            EQU     02h

;Device requests

REQINIT         EQU     000h
REQNDINPUT      EQU     005h
REQOUTPUT       EQU     008h
REQOUTVER       EQU     009h
REQOUTSTAT      EQU     00Ah
REQOPEN         EQU     00Dh
REQCLOSE        EQU     00Eh

;Device replies

REPERROR        EQU     08000h
REPDONE         EQU     00100h
REPBUSY         EQU     00200h
REPUNKWN        EQU     00003h

;Device request structure

DevReq  STRUC
        bLen    DB ?
        bUnitNo DB ?
        bCmd    DB ?
        rStatus DW ?
        res     DB 8 DUP (?)
        bData   DB ?
        pfBuff  DD ?
        wLen    DW ?
DevReq  ENDS

;Command codes

CMDSETNAME      EQU     01h
CMDSETPORT      EQU     02h

;Miscellaneous

RXSIZE          EQU     30
BIOSDSEG        EQU     00040h
ROWSMINUSONE    EQU     00084h

;====================================================================
;The start of the device driver segment

DEV_SEG SEGMENT
        ORG     0

;====================================================================
;The following lines are the device header, which must exist for
;every device. This file has only one device, and it works with
;character I/O. It can be opened and closed.

PrtScFF_Device  PROC FAR

PrtScFF_dev_header      LABEL   BYTE    ;start of the device driver

next_dev_ptr	DD  -1		;only 1 device is defined in this file
dev_attribute   DW  1000100000000000B   ;character device, supports open/close
strategy_ptr    DW  Strategy    ;the proc that receives the request
interrupt_ptr   DW  Interrupt   ;the proc that handles all services
device_name     DB  'PRTSCFF$'  ;device name string, used to open device

;The Strategy proc stores es:bx request header pointer here
;The Interrupt proc retrieves it

request_ptr	LABEL	DWORD
request_off     DW      0
request_seg     DW      0

;Command receive buffer

RxStatus        DB      0FFh
CharOff         DW      0
CharReceive     DB      RXSIZE DUP (' ')

;Print screen handler address store

int05h_ptr      LABEL   DWORD
int05h_off      DW      0
int05h_seg      DW      0

;Video handler address store and semaphore

int10h_ptr      LABEL   DWORD
int10h_off      DW      0
int10h_seg      DW      0
int10h_sem      DB      SEMCLEAR

;Cursor location and size storage

cursorloc       DW      0
cursorsize      DW      0

;Printer port

Port            DW      LPT1

;PCL 3 printer codes: - First part to setup the printer: Reset, ISOA4,
;                       Portrait, Pitch 12, PC-8, 6 lines/inch, and 6
;                       linefeeds to outrun the company logo. Username
;                       gets tucked in between.
;                     - Last part is used before every print line: roll-
;                       over to next line, spaces for left margin and code
;                       for printer data transparency.

printerreset    LABEL   BYTE
printerset      DB      ESCAPE, 'E'

PRINTERRESETLEN EQU     $ - printerreset

                DB      ESCAPE, '&l26A', ESCAPE, '&l0O'
                DB      ESCAPE, '(s12H', ESCAPE, '(10U', ESCAPE, '&l6D'
                DB      CR, LF, LF, '                        '
username        DB      RXSIZE DUP (' ')
                DB      LF, LF, LF, LF

PRINTERSETLEN   EQU     $ - printerset

lineheader      DB      LF, CR, '       ', ESCAPE, '&p'
columnascii     DB      '@@@X'  ;column count set by interrupt handler

LINEHEADERLEN   EQU     $ - lineheader

PrtScFF_Device  ENDP

;====================================================================
;Strategy procedure
;Just saves the request packet pointer for the Interrupt procedure.

Strategy        PROC FAR
        ASSUME  cs:DEV_SEG

        mov     cs:[request_off], bx    ;store request offset
        mov     cs:[request_seg], es    ;and segment

        ret

Strategy        ENDP

;====================================================================
;Interrupt procedure
;Processes the request indicated in the request packet.

Interrupt       PROC FAR
        ASSUME cs:DEV_SEG, ds:DEV_SEG, es:NOTHING

        push    ax                      ;save only what we need
        push    bx                      ;for first test
        push    es
        push    ds

        mov     ax, cs
        mov     ds, ax                  ;set data segment for general use

        les     bx, ds:[request_ptr]    ;pointer to our request packet
        mov     al, es:[bx+bCmd]        ;check the request

        cmp     al, REQINIT
        jne     maybeopen
        jmp     Init                    ;go initialize

maybeopen:
        cmp     al, REQOPEN
        je      Open                    ;open device
        cmp     al, REQCLOSE
        je      Close                   ;close device

        cmp     al, REQOUTSTAT
        je      OutputStatus            ;output status check
        cmp     al, REQOUTPUT
        je      Output                  ;output to device
        cmp     al, REQOUTVER
        je      OutputVerify            ;output with verify

        cmp     al, REQNDINPUT
        je      NonDestInput            ;non-destructive input

        mov     word ptr es:[bx+rStatus], REPERROR+REPDONE+REPUNKWN
                                        ;indicate error & done &
                                        ;unknown request
        pop     ds                      ;restore those we disturbed
        pop     es
        pop     bx
	pop	ax
	ret				;RET FAR from drivers

Interrupt       ENDP

;====================================================================
;Open device checks Int 05h vector and retakes it if changed. Also
;resets the receive buffer.

Open    PROC FAR
        ASSUME cs:DEV_SEG, ds:DEV_SEG, es:NOTHING

        mov     word ptr es:[bx+rStatus], REPDONE

        call    RetakeInt05h

        mov     ds:[CharOff], 0         ;reset rx buffer
        mov     ds:[RxStatus], 0FFh     ;reset receive error

        pop     ds                      ;restore those we disturbed
        pop     es
        pop     bx
	pop	ax
        ret                             ;RET FAR from driver

Open    ENDP

;====================================================================
;Close has to be handled because open is, thats all.

Close   PROC FAR
        ASSUME cs:DEV_SEG, ds:DEV_SEG, es:NOTHING

        mov     word ptr es:[bx+rStatus], REPDONE

        pop     ds                      ;restore those we disturbed
        pop     es
        pop     bx
	pop	ax
        ret                             ;RET FAR from driver

Close   ENDP

;====================================================================
;Non-destructive input request is answered here. It is irregularly
;asked by MSDOS.

NonDestInput    PROC FAR
        ASSUME cs:DEV_SEG, ds:DEV_SEG, es:NOTHING

        mov     word ptr es:[bx+rStatus], REPDONE+REPBUSY

        pop     ds                      ;restore those we disturbed
        pop     es
        pop     bx
	pop	ax
        ret                             ;RET FAR from driver

NonDestInput    ENDP

;====================================================================
;Output status check answered here.

OutputStatus    PROC FAR
        ASSUME cs:DEV_SEG, ds:DEV_SEG, es:NOTHING

        mov     ax, REPDONE

        mov     al, byte ptr ds:[RxStatus]
        cmp     al, 0FFh                ;0FFh means no error
        je      retstatus

        add     ax, REPERROR            ;set error flag

retstatus:
        mov     word ptr es:[bx+rStatus], ax

        pop     ds                      ;restore registers
        pop     es
        pop     bx
        pop     ax
        ret                             ;RET FAR from driver

OutputStatus    ENDP

;====================================================================
;Output is collected in a buffer and checked for the right header (to be
;command byte). If it's not right a write protect violation error is
;returned. Otherwise an ASCIIZ string is expected (possibly in parts) of
;26 characters, excluding the null-character. Once the null-character is
;received the string is copied into the printer codes area.

Output  PROC FAR
        ASSUME cs:DEV_SEG, ds:DEV_SEG, es:NOTHING

OutputVerify:
        mov     word ptr es:[bx+rStatus], REPDONE

        push    si
        push    di
        push    cx
        push    dx

        mov     ax, word ptr es:[bx+pfBuff+2]   ;get buffer segment
        push    ax                              ;save for later
        mov     si, word ptr es:[bx+pfBuff]     ;get buffer offset

        mov     di, OFFSET CharReceive
        add     di, word ptr ds:[CharOff]       ;set buffer offset

        mov     ax, RXSIZE
        sub     ax, word ptr ds:[CharOff]       ;get dest buffer size
        jnz     buffnotfull

        mov     word ptr es:[bx+wLen], 0        ;set # of processed chars
        mov     byte ptr ds:[RxStatus], 0Ah     ;set write fault
        pop     ax                              ;clear stack
        jmp     cmddone

buffnotfull:
        mov     cx, word ptr es:[bx+wLen]       ;get source buffer size
        cmp     ax, cx
        jae     noclip

        mov     cx, ax                          ;clip size to avail. space
        mov     word ptr es:[bx+wLen], cx       ;set # of processed chars
        mov     byte ptr ds:[RxStatus], 0Ah     ;set write fault

noclip:
        add     ds:[CharOff], cx        ;calculate new end

        pop     ds                      ;ds:si -> source buffer

        push    cs                      ;store segments
        push    es

        push    cs                      ;get buffer segment
        pop     es                      ;es:di -> dest buffer

        cld
        rep     movsb                   ;copy source to dest

        pop     es                      ;restore segment
        pop     ds                      ;restore data segment

        mov     al, ds:[CharReceive]
        cmp     al, CMDSETNAME          ;check headerbyte
        je      checkEOS

        cmp     al, CMDSETPORT          ;check headerbyte
        je      checkportnum

        mov     word ptr es:[bx+wLen], 0        ;set # of processed chars
        mov     byte ptr ds:[RxStatus], 00h     ;set write protect error
        jmp     cmddone

checkEOS:
        push    es
        mov     ax, ds
        mov     es, ax                  ;buffer segment
        mov     ax, 0                   ;search for null-character
        mov     cx, RXSIZE              ;buffer size
        mov     di, OFFSET CharReceive  ;buffer offset
        cld
        repne   scasb                   ;scan buffer for null-character
        pop     es

        cmp     ax, cx                  ;count down to 0
        je      cmddone                 ;if not end of string found

        dec     di
        mov     byte ptr ds:[di], SPACE ;to avoid rewrite/recheck problems
        mov     ax, RXSIZE-1            ;-1 for header byte
        sub     ax, cx                  ;calc string length
        mov     cx, ax

        mov     si, OFFSET CharReceive
        inc     si                      ;string start offset

        push    es
        push    ds
        pop     es                      ;username segment

        mov     di, OFFSET username     ;uername offset

        cld
        rep     movsb                   ;copy string to printer codes area

        pop     es

        mov     ds:[CharOff], 0         ;reset rx buffer
        mov     ds:[RxStatus], 0FFh     ;reset receive error
        jmp cmddone

checkportnum:
        push    es
        mov     ax, ds
        mov     es, ax                  ;buffer segment
        mov     ax, 0                   ;search for null-character
        mov     cx, RXSIZE              ;buffer size
        mov     di, OFFSET CharReceive  ;buffer offset
        cld
        repne   scasb                   ;scan buffer for null-character
        pop     es

        cmp     ax, cx                  ;count down to 0
        je      cmddone                 ;if not end of string found

        dec     di
        mov     byte ptr ds:[di], SPACE ;to avoid rewrite/recheck problems

        dec     di
        mov     al, byte ptr ds:[di]

        cmp     al, '1'
        jge     checkporthigh
        mov     byte ptr ds:[RxStatus], 0Ah     ;set write fault
        jmp     cmddone

checkporthigh:
        cmp     al, '3'
        jle     portoke
        mov     byte ptr ds:[RxStatus], 0Ah     ;set write fault
        jmp     cmddone

portoke:
        mov     ah, 0
        sub     al, '1'
        mov     word ptr ds:[Port], ax          ;store printer port

        mov     ds:[CharOff], 0         ;reset rx buffer
        mov     ds:[RxStatus], 0FFh     ;reset receive error

cmddone:
        mov     ax, REPDONE

        mov     al, byte ptr ds:[RxStatus]
        cmp     al, 0FFh                ;0FFh means no error
        je      exitout

        add     ax, REPERROR            ;set error flag

exitout:
        mov     word ptr es:[bx+rStatus], ax

        pop     dx
        pop     cx
        pop     di
        pop     si

        pop     ds                      ;restore those we disturbed
        pop     es
        pop     bx
	pop	ax
        ret                             ;RET FAR from driver

Output  ENDP

;====================================================================
;Retake int 05h if it changed.

RetakeInt05h    PROC NEAR
        ASSUME cs:DEV_SEG, ds:DEV_SEG, es:NOTHING

        push    ax
        push    bx
        push    dx
        push    es

        mov     ax, 03505h              ;get interrupt vector for
        int     21h                     ;interrupt 05h
        mov     ax, es
        cmp     ds:[int05h_seg], ax     ;check with stored segment
        jne     retake
        cmp     ds:[int05h_off], bx     ;check with stored offset
        je      dontretake

retake:
        mov     ds:[int05h_seg], es     ;store segment
        mov     ds:[int05h_off], bx

        mov     dx, OFFSET Int05h       ;new vector for interrupt 05h
        mov     ax, 02505h
        int     21h                     ;set new vector

dontretake:
        pop     es                      ;restore registers
        pop     dx
        pop     bx
        pop     ax
        ret

RetakeInt05h    ENDP

;====================================================================
;Convert column count to ASCII string and set printer escape sequence

ColToASCII      PROC NEAR
        ASSUME cs:DEV_SEG, ds:DEV_SEG, es:NOTHING

        push    ax                      ;save registers
        push    bx
        push    cx

        mov     cx, 2                   ;# figures min 1

figureloop:
        push    cx

        mov     cx, 0
        mov     cl, ah                  ;setup counter
        mov     ax, 0

numberloop:
        inc     al
        aaa                             ;ascii adjust after addition
        loop    numberloop

        pop     cx
        add     al, '0'                 ;make real ASCII figure
        mov     bx, cx
        mov     byte ptr ds:[bx+columnascii], al        ;write in ESC seq.
        loop    figureloop

        add     ah, '0'                 ;make real ASCII figure
        mov     byte ptr ds:[columnascii], ah           ;write in ESC seq.

        pop     cx                      ;restore registers
        pop     bx
        pop     ax
        ret

ColToASCII      ENDP

;====================================================================
;Print Screen handler

Int05h  PROC FAR
        ASSUME cs:DEV_SEG, ds:DEV_SEG, es:NOTHING

        push    ds                      ;save registers
        push    ax
        push    bx
        push    cx
        push    dx
        push    es
        push    si
        push    di

        mov     ax, cs
        mov     ds, ax                  ;get data segment

        mov     ah, 00Fh                ;get current video mode
        int     10h

        and     al, 07Fh                ;mask bit 7
        cmp     al, 0                   ;video mode 0
        je      supped
        cmp     al, 1                   ;video mode 1
        je      supped
        cmp     al, 2                   ;video mode 2
        je      supped
        cmp     al, 3                   ;video mode 3
        je      supped
        cmp     al, 7                   ;video mode 7
        je      supped

        pop     di                      ;restore registers
        pop     si
        pop     es
        pop     dx
        pop     cx
        pop     bx
        pop     ax
        pop     ds

        jmp     dword ptr cs:[int05h_ptr]       ;chain for other video modes

supped:
        call    ColToASCII              ;convert column count into ASCII
                                        ;and fill printer escape sequence

        mov     cl, ah                  ;store column count

        mov     al, SEMSET
        mov     ds:[int10h_sem], al     ;set semaphore for speed

        mov     ax, BIOSDSEG            ;BIOS data segment
        mov     es, ax
        mov     al, es:[ROWSMINUSONE]   ;get rows on screen minus one
        inc     al
        mov     ch, al                  ;cx = row:column

        push    cx
        mov     ah, 003h                ;get cursor position
        int     10h
        mov     word ptr ds:[cursorloc], dx     ;store cursor location
        mov     word ptr ds:[cursorsize], cx    ;store cursor size

        mov     ah, 001h                ;set text mode cursor shape
        mov     cx, 02000h              ;invisible cursor
        int     10h

        mov     di, OFFSET printerset
        mov     cx, PRINTERSETLEN

prtsetloop:
        mov     dx, word ptr ds:[Port]
        mov     ah, 000h                ;print character
        mov     al, byte ptr ds:[di]    ;character from printer set
        int     17h
        inc     di
        loop    prtsetloop              ;loop until all printed
        pop     cx

        mov     dh, 0                   ;start with row 0

rowloop:
        push    dx
        push    cx
        mov     di, OFFSET lineheader
        mov     cx, LINEHEADERLEN

prtlhdrloop:
        mov     dx, word ptr ds:[Port]
        mov     ah, 000h                ;print character
        mov     al, byte ptr ds:[di]    ;character from line header
        int     17h
        inc     di
        loop    prtlhdrloop             ;loop until all printed
        pop     cx
        pop     dx

        mov     dl, 0                   ;start with column 0

prtlineloop:
        push    dx

        mov     ah, 002h                ;set cursor position
        int     10h

        mov     ah, 008h                ;read char and attrib from cursor loc
        int     10h
        mov     dx, word ptr ds:[Port]
        mov     ah, 000h                ;print character
        int     17h
        pop     dx

        inc     dl                      ;count column
        cmp     dl, cl
        jne     prtlineloop

        inc     dh                      ;count row
        cmp     dh, ch
        jne     rowloop

        mov     di, OFFSET printerreset
        mov     cx, PRINTERRESETLEN

prtresetloop:
        mov     dx, word ptr ds:[Port]
        mov     ah, 000h                ;print character
        mov     al, byte ptr ds:[di]    ;character from printer reset
        int     17h
        inc     di
        loop    prtresetloop            ;loop until all printed

        mov     ah, 002h                ;set cursor location
        mov     dx, word ptr ds:[cursorloc]     ;get stored location
        int     10h

        mov     ah, 001h                ;set text mode cursor shape
        mov     cx, word ptr ds:[cursorsize]    ;get cursor size
        int     10h

        mov     al, SEMCLEAR
        mov     ds:[int10h_sem], al     ;clear semaphore

done:
        pop     di                      ;restore registers
        pop     si
        pop     es
        pop     dx
        pop     cx
        pop     bx
        pop     ax
        pop     ds
        iret                            ;done

Int05h  ENDP

;====================================================================
;Video interrupt handler

Int10h  PROC FAR
        ASSUME cs:DEV_SEG, ds:DEV_SEG, es:NOTHING

        push    ds
        push    ax

        mov     ax, cs
        mov     ds, ax                  ;get data segment

        mov     al, ds:[int10h_sem]
        cmp     al, SEMCLEAR
        je      semclear10h             ;semaphore clear

chain10h:
        pop     ax
        pop     ds
        jmp     dword ptr cs:[int10h_ptr]       ;chain to original handler

semclear10h:
        pop     ax
        push    ax                      ;restore ax
        cmp     ah, 12h
        jne     chain10h                ;special functions

        cmp     bl, 20h
        jne     chain10h                ;alternate print screen

        mov     al, SEMSET
        mov     ds:[int10h_sem], al     ;set semaphore

        pop     ax                      ;restore ax
        push    ax

        int     10h                     ;call original video

        mov     al, SEMCLEAR
        mov     ds:[int10h_sem], al     ;clear semaphore

        call    RetakeInt05h            ;retake int 05h is changed

        pop     ax
        pop     ds
        iret                            ;don't chain

Int10h  ENDP

;====================================================================
;Initialize the device driver. From here on memory will be released
;to DOS. es:bx points to the request packet.

Init    PROC FAR
        ASSUME cs:DEV_SEG, ds:DEV_SEG, es:NOTHING

        push    cx                      ;already pushed ax, bx and es
        push    dx                      ;so gotta save the rest now
	push	si
	push	di
        push    ds

        mov     word ptr es:[bx+00Eh], OFFSET Init       ;release from
        mov     word ptr es:[bx+010h], cs                ;here on
        mov     word ptr es:[bx+003h], REPDONE           ;flag done

        push    es
        push    bx

        mov     ax, 03510h              ;get interrupt vector for
        int     21h                     ;interrupt 10h
        mov     ds:[int10h_seg], es     ;and store it for later use
        mov     ds:[int10h_off], bx

        mov     dx, OFFSET Int10h       ;new vector for interrupt 10h
        mov     ax, 02510h
        int     21h                     ;set new vector

        mov     ax, 03505h              ;get interrupt vector for
        int     21h                     ;interrupt 05h
        mov     ds:[int05h_seg], es     ;and store it for later use
        mov     ds:[int05h_off], bx

        mov     dx, OFFSET Int05h       ;new vector for interrupt 05h
        mov     ax, 02505h
        int     21h                     ;set new vector

        pop     bx
        pop     es

        les     bx, dword ptr es:[bx+wLen]   ;get end of DEVICE= line

nextchar:
        cmp     byte ptr es:[bx], CR
        je      prtbanner
        cmp     byte ptr es:[bx], LF
        je      prtbanner
        cmp     byte ptr es:[bx], SPACE ;find first parameter
        je      foundparm

        inc     bx
        jmp     nextchar

foundparm:
        inc     bx

        cmp     byte ptr es:[bx], CR
        je      prtbanner
        cmp     byte ptr es:[bx], LF
        je      prtbanner
        cmp     byte ptr es:[bx], 'Q'   ;found parameter
        je      nobanner
        cmp     byte ptr es:[bx], 'q'   ;found parameter
        je      nobanner

        jmp     foundparm

prtbanner:
        mov     dx, OFFSET banner
        mov     ah, 9                   ;DOS display the banner
        int     21h

nobanner:
        pop     ds                      ;clean up the stack
	pop	di
	pop	si
	pop	dx
	pop	cx
        pop     ds                      ;the ones we first pushed
        pop     es
        pop     bx
	pop	ax
        ret                             ;RET FAR from drivers

Init    ENDP

;====================================================================
;This is the installation message

banner  DB      '嬪様様様様様様様様様様様様様様様様様様様様', CR, LF
        DB      '    Print Screen FormFeeder installed    ', CR, LF
        DB      '   Ver 4.03   (C) 1995  by J.A. Keuter   ', CR, LF
        DB      '塒様様様様様様様様様様様様様様様様様様様様', CR, LF
        DB      '$'

DEV_SEG ENDS

        END PrtScFF_Device

;====================================================================


Written by my own two hands and an ASCII editor. Problems? write me Last updated May 21, 1997 Back home

Page best viewed with viewable with Anybrowser