handlers.asm

来自「这是一些例程」· 汇编 代码 · 共 1,284 行 · 第 1/4 页

ASM
1,284
字号
        mov     WORD PTR [si].INTR.OldHand[2], es ;   application's handler
        mov     dx, WORD PTR [si].INTR.NewHand[0] ; DS:DX points to TSR's hand
        mov     ah, 25h                         ; Request DOS Function 25h
        int     21h                             ; Set interrupt vector
        add     si, SIZEOF INTR                 ; DS:SI points to next in list
        .UNTILCXZ

; Step 4.  Disable MS-DOS break checking during disk I/O

        mov     ax, 3300h               ; Request DOS Function 33h
        int     21h                     ; Get CTRL+BREAK flag in DL
        mov     BreakCheckFlag, dl      ; Preserve it

        sub     dl, dl                  ; DL = 0 to disable I/O break checking
        mov     ax, 3301h               ; Request DOS Function 33h
        int     21h                     ; Set CTRL+BREAK flag from DL

; Step 5.  If TSR requires a disk transfer area, store address of current
; DTA and switch buffer address to this segment. See Help and section 
; "Preserving Existing Data" in Chapter 11 of the Programmer's Guide for
; more information about the DTA. 

        IFDEF   DTA_SIZ
        mov     ah, 2Fh                         ; Request DOS Function 2Fh
        int     21h                             ; Get DTA Address into ES:BX
        mov     WORD PTR OldDtaAddr[0], bx      ; Store address
        mov     WORD PTR OldDtaAddr[2], es

        mov     dx, OFFSET DtaBuff              ; DS:DX points to new DTA
        mov     ah, 1Ah                         ; Request DOS Function 1Ah
        int     21h                             ; Set DTA Address
        ENDIF

; Call main body of TSR.

        mov     ax, @data
        mov     ds, ax                          ; Initialize DS and ES
        mov     es, ax                          ;   to data segment

        call    cs:TsrAddr                      ; Call main part of TSR

        push    cs
        pop     ds                              ; Reset DS to this segment

; Undo step 5.  Restore previous DTA (if required)

        IFDEF   DTA_SIZ
        push    ds                      ; Preserve DS
        lds     dx, OldDtaAddr          ; DS:DX points to application's DTA
        mov     ah, 1Ah                 ; Request DOS Function 1Ah
        int     21h                     ; Set DTA Address
        pop     ds
        ENDIF

; Undo step 4.  Restore previous MS-DOS break checking

        mov     dl, BreakCheckFlag      ; DL = previous break state
        mov     ax, 3301h               ; Request DOS Function 33h
        int     21h                     ; Set CTRL+BREAK flag from DL

; Undo step 3.  Restore previous vectors for error-trapping handlers

        mov     cx, CTRAP
        mov     di, OFFSET TrapArray
        push    ds                      ; Preserve DS
        push    ds                      ; ES = resident code segment
        pop     es

        .REPEAT
        mov     al, es:[di]             ; AL = interrupt number
        lds     dx, es:[di].INTR.OldHand; DS:DX points to application's handler
        mov     ah, 25h                 ; Request DOS Function 25h
        int     21h                     ; Set interrupt vector from DS:DX
        add     di, SIZEOF INTR         ; ES:DI points to next in list
        .UNTILCXZ
        pop     ds

; Undo step 2.  Restore registers from stack

        pop     es
        pop     bp
        pop     di
        pop     si
        pop     dx
        pop     cx
        pop     bx
        pop     ax

; Undo step 1.  Restore address of original stack to SS:SP

        cli
        mov     sp, WORD PTR OldStackAddr[0]
        mov     ss, WORD PTR OldStackAddr[2]
        sti

; Clear request flag and return to caller (Clock or Idle procedure)

        mov     TsrRequestFlag, FALSE
        ret

Activate ENDP



;* INSTALLATION SECTION - The following code is executed only during
;* the TSR's installation phase. When the program terminates through
;* Function 31h, the above code and data remain resident; memory
;* occupied by the following code segment is returned to the operating
;* system.

DGROUP  GROUP INSTALLCODE

INSTALLCODE SEGMENT PARA PUBLIC 'CODE2'
        ASSUME  ds:@code

;* Install - Prepares for installation of a TSR by chaining interrupt
;* handlers and initializing pointers to DOS flags. Install does not
;* call the Terminate-and-Stay-Resident function.
;*
;* This library of routines accommodates both keyboard-activated and
;* time-activated TSRs. The latter are TSRs that activate at a preset
;* time. If the first parameter (Param1) is a valid scan code, Install
;* assumes the TSR is activated from the keyboard and sets up a keyboard
;* handler to search for the hot key. If Param1 is null, Install assumes
;* the next two parameters (Param2 and Param3) are respectively the hour
;* and minute at which the TSR is to activate. In this case, Install 
;* calls GetTimeToElapse to initialize the variable CountDown and sets
;* up KeybrdMonitor as the keyboard handler. CountDown and the secondary
;* counter Tick91 serve here the same functions as they do for the
;* ALARM.ASM program presented in Chapter 11 of the Programmer's Guide.
;* Install is callable from a high-level language.
;*
;* Uses:   InDosAddr, CritErrAddr, CHAND,
;*         HandArray, CTRAP, TrapArray
;*
;*                  Keyboard-activated                 Time-activated
;*                  ------------------                 --------------
;* Params: Param1 - Scan code for hot key              0
;*         Param2 - Bit value for shift hot key        Hour to activate
;*         Param3 - Bit mask for shift hot key         Minute to activate
;*         Param4 - Far address of main TSR procedure  (same)
;*
;* Return: AX = 0 if successful, or one of the following codes:
;*         IS_INSTALLED           FLAGS_NOT_FOUND        NO_IDNUM
;*         ALREADY_INSTALLED      WRONG_DOS

Install PROC    FAR USES ds si di,
        Param1:WORD, Param2:WORD, Param3:WORD, Param4:FAR PTR FAR

        mov     ax, @code
        mov     ds, ax                          ; Point DS to code segment

; Get and store parameters passed from main program module

        mov     al, BYTE PTR Param1
        mov     HotScan, al                     ; Store hot-key scan code
        mov     al, BYTE PTR Param2             ;   or flag for time activate
        mov     HotShift, al                    ; Store hot-key shift value
        mov     al, BYTE PTR Param3             ;   or hour value
        mov     HotMask, al                     ; Store hot-key shift mask
                                                ;   or minute value
        mov     ax, WORD PTR Param4[0]
        mov     bx, WORD PTR Param4[2]
        mov     WORD PTR TsrAddr[0], ax         ; Store segment:offset of
        mov     WORD PTR TsrAddr[2], bx         ;   TSR's main code

; Get addresses of DOS flags, then check for prior installation

        call    GetDosFlags             ; Find DOS service flags
        or      ax, ax
        jnz     exit                    ; If flags not found, quit

        sub     al, al                  ; Request multiplex function 0
        call    CallMultiplex           ; Invoke Interrupt 2Fh
        cmp     ax, NOT_INSTALLED       ; Check for presence of resident TSR

        .IF     !zero?                  ; If TSR is installed,
        cmp     ax, IS_INSTALLED        ;   return with appropriate
        jne     exit                    ;   error code
        mov     ax, ALREADY_INSTALLED
        jmp     exit
        .ENDIF

; Check if TSR is to activate at the hour:minute specified by Param2:Param3.
; If so, determine the number of 5-second intervals that must elapse before
; activation, then set up the code at the far LABEL KeybrdMonitor to serve
; as the keyboard handler.

        .IF     HotScan == 0            ; If valid scan code given,
        mov     ah, HotShift            ;   AH = hour to activate
        mov     al, HotMask             ;   AL = minute to activate
        call    GetTimeToElapse         ; Get number of 5-second intervals
        mov     CountDown, ax           ;   to elapse before activation

        .ELSE                           ; Force use of KeybrdMonitor as
                                        ;   keyboard handler
        cmp     Version, 031Eh          ; DOS Version 3.3 or higher?
        jb      setup                   ; No?  Skip next step

; Test for IBM PS/2 series. If not PS/2, use Keybrd and SkipMiscServ as
; handlers for Interrupts 09 and 15h respectively. If PS/2 system, set up
; KeybrdMonitor as the Interrupt 09 handler. Audit keystrokes with MiscServ
; handler, which searches for the hot key by handling calls to Interrupt 15h
; (Miscellaneous System Services). For more information about keyboard
; handlers, refer to the section "Auditing Hardware Events for TSR Requests"
; in Chapter 11 of the Programmer's Guide

        mov     ax, 0C00h               ; Function 0Ch (Get System
        int     15h                     ;   Configuration Parameters)
        sti                             ; Compaq ROM may leave interrupts
                                        ;   disabled

        jc      setup                   ; If carry set,
        or      ah, ah                  ;   or if AH not 0,
        jnz     setup                   ;   services are not supported

        test    BYTE PTR es:[bx+5], 00010000y   ; Test bit 4 to see if
        jz      setup                           ;   intercept is implemented

        mov     ax, OFFSET MiscServ             ; If so, set up MiscServ as
        mov     WORD PTR intMisc.NewHand, ax    ;   Interrupt 15h handler
        .ENDIF

        mov     ax, OFFSET KeybrdMonitor        ; Set up KeybrdMonitor as
        mov     WORD PTR intKeybrd.NewHand, ax  ;   Interrupt 09 handler

; Interrupt structure is now initialized for either PC/AT or PS/2 system.
; Get existing handler addresses from interrupt vector table, store in
; OldHand member, and replace with addresses of new handlers.

setup:
        mov     cx, CHAND               ; CX = count of handlers
        mov     si, OFFSET HandArray    ; SI = offset of handler structures

        .REPEAT
        mov     ah, 35h                 ; Request DOS Function 35h
        mov     al, [si]                ; AL = interrupt number
        int     21h                     ; Get interrupt vector in ES:BX
        mov     WORD PTR [si].INTR.OldHand[0], bx ; Save far address
        mov     WORD PTR [si].INTR.OldHand[2], es ;  of current handler
        mov     dx, WORD PTR [si].INTR.NewHand[0] ; DS:DX points to TSR handler
        mov     ah, 25h                 ; Request DOS Function 25h
        int     21h                     ; Set interrupt vector from DS:DX
        add     si, SIZEOF INTR         ; DS:SI points to next in list
        .UNTILCXZ

        sub     ax, ax                  ; Clear return code
exit:
        ret                             ; Return to caller

Install ENDP


;* Deinstall - Prepares for deinstallation of a TSR. Deinstall is the
;* complement of the Install procedure. It restores to the vector table
;* the original addresses replaced during installation, thus unhooking
;* the TSR's handlers. Checks to see if another TSR has installed handlers
;* for the interrupts in array HandArray. If so, the procedure fails with
;* an appropriate error code. Callable from a high-level language.
;*
;* Params: None
;*
;* Return: AX = Segment address of resident portion's PSP or 
;*              one of the following error codes:
;*              CANT_DEINSTALL           WRONG_DOS
                
Deinstall PROC  FAR USES ds si di

        mov     ax, @code
        mov     ds, ax                  ; Point DS to code segment

        sub     al, al                  ; Request multiplex function 0
        call    CallMultiplex           ; Get resident code segment in ES

        cmp     ax, IS_INSTALLED        ; If not resident,
        jne     exit                    ;   exit with error
        push    es                      ; Else point DS to
        pop     ds                      ;   resident code segment
        mov     cx, CHAND               ; Count of handlers
        mov     si, OFFSET HandArray    ; SI points to handler structures

; Read current vectors for TSR's interrupt handlers and compare with far
; addresses. If mismatch, another TSR has installed new handlers and ours
; cannot be safely deinstalled.

        .REPEAT
        mov     al, [si]                ; AL = interrupt number
        mov     ah, 35h                 ; Request DOS Function 35h
        int     21h                     ; Get interrupt vector in ES:BX
        cmp     bx, WORD PTR [si].INTR.NewHand[0] ; If offset different,
        jne     e_exit                            ;   error
        mov     ax, es
        cmp     ax, WORD PTR [si].INTR.NewHand[2] ; If segment different,
        jne     e_exit                            ;   error
        add     si, SIZEOF INTR         ; DS:SI points to next in list
        .UNTILCXZ

; If no interrupts replaced, call TSR's multiplex handler to locate
; address of resident portion's PSP. Although the PSP is not required
; until memory is returned to DOS, the call must be done now before
; unhooking the multiplex handler.

        mov     al, 1                   ; Request multiplex function 1
        call    CallMultiplex           ; Get resident code's PSP in ES
        push    es                      ; Save it

; Unhook all handlers by restoring the original vectors to vector table.

        mov     cx, CHAND               ; Count of installed handlers
        mov     si, OFFSET HandArray    ; SI points to handler structures

        .REPEAT
        mov     al, [si]                ; AL = interrupt number
        push    ds                      ; Preserve DS segment
        lds     dx, [si].INTR.OldHand   ; Put vector in DS:DX
        mov     ah, 25h                 ; Request DOS Function 25h
        int     21h                     ; Set interrupt vector from DS:DX
        pop     ds
        add     si, SIZEOF INTR         ; DS:SI points to next in list
        .UNTILCXZ

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?