;Copyright (C) 1996 Donald Bindner ; ;This program is free software; you can redistribute it and/or ;modify it under the terms of the GNU General Public License ;as published by the Free Software Foundation; either version 2 ;of the License, or (at your option) any later version. ; even 16 end_of_resident equ ($-$$ + 0100h) ; ------------ nonresident data begins here ------------------------ alloc_strat dw 0 relocation_adr dw 0 link_state db 0 mult_available db 0 ; non-zero indicates there is a free m-number no_mult_mess db 'No free multiplex number.',13,10,'$' install_mess db 'Dvorak96 installed. Written by Donald J. Bindner.',13,10,'$' disable_mess db 'Dvorak96 disabled.',13,10,'$' enable_mess db 'Dvorak96 enabled.',13,10,'$' ; ------------ nonresident code begins here ------------------------ main: call check_if_installed ; check to see if already installed if_c jmp toggle_translation ; if already installed toggle resident ; disabled flag and quit test byte [mult_available],0FFh ; see if a multiplex # was available if_c jmp no_multi_number ; if not, print error and quit mov ax, cs ; look at cs cmp ax, 0B800h ; did we load lower than video memory? ja .S0 ; if not, continue call install_high ; otherwise load us high ; return indicates failure .S0: mov es,[envseg] ; ES=PSP's environ seg v0.01 mov ah,49h ; DOS Fcn 49h = Release Memory int 21h ; Release it via DOS interrupt. push word offset hook_list call hook_interrupts ; hook all of the interrupts push word offset install_mess ; print the installed message call print mov dx, end_of_resident/16 ; number of paragraphs to keep mov ax, 3100h ; terminate resident w/ 0 return code int 21h allocate_high_block: mov ax, 5800h ; get allocation strategy int 21h ; do it mov [alloc_strat], ax ; save it mov ax, 5802h ; get link state int 21h ; do it mov [link_state], al ; save it mov ax, 5801h ; set allocation strategy mov bx, 0041h ; high-best fit int 21h ; do it mov ax, 5803h ; set link state mov bx, 0001h ; use upper memory int 21h mov ax, 5802h ; get link state int 21h ; do it cmp al, 1 ; see if UMBs actually available je .L1 ; if so, continue stc ; otherwise indicate failure pushf ; save carry flag jmp short .L98 ; get out of here .L1: mov ah, 48h ; allocate memory mov bx, end_of_resident/16 ; # of paragraphs int 21h ; get it pushf ; remember flags i.e. if we got it jc .L98 ; if failed get out mov [relocation_adr], ax ; otherwise remember where to relocate dec ax ; address the MCB for our new memory mov es, ax ; block inc ax ; back to relocation segment mov word [es:1], ax ; make the memory block own itself mov ah, 51h ; get current PSP int 21h dec bx ; back to MCB for main memory block push ds push si push di mov ds, bx ; point at MCB mov si, 8 mov di, si cld ; copy forward movsw ; copy the DOS 4.0+ program name into movsw ; the new memory block's MCB movsw movsw pop di pop si pop ds .L98: popf .L99: pushf ; store flags, especially CF mov ax, 5801h ; set allocation strategy mov bx, [alloc_strat] ; restore saved value int 21h mov ax, 5803h ; set UMB link status mov bh, 0 mov bl, [link_state] ; restore saved value int 21h popf ; get back flags ret relocate_program: push cx push si push di push es mov si, 0 ; zero these mov di, si mov es, [relocation_adr] ; destination segment mov cx, end_of_resident/2 ; # words to copy rep movsw ; do the copy pop es pop di pop si pop cx ret install_high: mov ax,3000h ; get DOS version int 21h cmp al,5 ; DOS 5.0 or higher? if_b ret ; if not, just return (for normal install) cmp al,10 ; OS/2 penalty box? if_ae ret ; if so, just return (for normal install) mov ax,2B01h mov cx,4445h mov dx,5351h int 21h ; check if DESQview running cmp al,0FFh ; if yes, no UMB's to be allocated if_ne ret ; so return (for normal install) call allocate_high_block ; make space in high memory for program if_c ret ; if error return (for normal install) call relocate_program ; copy the resident portion push ds mov ds, [relocation_adr] push word offset hook_list call hook_interrupts ; hook all of the interrupts pop ds push word offset install_mess ; print the installed message call print mov ax, 4c00h ; exit program int 21h check_if_installed: mov bx, 0FFh ; count down the multiplex numbers .L1: mov ah, bl ; multiplex number mov al, 0 ; installation check int 2Dh ; do it or al, al ; is it zero? jnz .L2 ; if not, it isn't free mov [multiplex_number], ah ; otherwise remember it mov byte [mult_available], 1 ; and set bl=1 free-flag jmp short .L3 .L2: cmp al, 255 ; indicates number in use jne .L3 ; if not, continue the loop call check_signature jne .L3 ; if not equal to ours continue the loop stc ; otherwise set carry -- installed already ret .L3: dec bx jns .L1 clc ; clear carry -- not installed ret check_signature: push cx push si push di push es mov es, dx ; segment of signature to compare mov si, offset signature_string mov cx, 8 ; number of words to compare repe cmpsw ; compare while equal pop es pop di pop si pop cx ret hook_interrupts: push bp mov bp, sp ; stack frame push ax push bx push dx push si push di push ds push es mov di, [bp+4] ; address of the hook_list .L1: mov ah, 35h ; get interrupt vector mov al, [ds:di] ; vector to change int 21h ; do it mov si, [ds:di+1] ; where our handler lives mov [ds:si+2], bx ; old routine's offset mov [ds:si+4], es ; old routine's segment mov dx, si ; ds:dx now points to new routine mov ah, 25h ; set interrupt vector mov al, [ds:di] ; vector to change int 21h cmp byte [ds:di], 2Dh ; 2Dh marks the end of the list je .L99 ; so we would exit add di, 3 jmp short .L1 .L99: pop es pop ds pop di pop si pop dx pop bx pop ax pop bp ret 2 toggle_translation: mov es, dx ; es = segment of resident program xor byte [es:dvorak_disabled], 1 ; toggle the flag jnz .L1 ; print enabled message push word offset enable_mess jmp short .L99 .L1: ; print disabled message push word offset disable_mess .L99: call print mov ax, 4c00h ; quit with 0 errorlevel int 21h no_multi_number: push word offset no_mult_mess ; print error call print mov ax, 4c01h ; quit with 1 errorlevel int 21h print: push bp mov bp, sp push ax push dx mov dx, [bp+4] ; offset of message DS=CS assumed mov ah, 09h ; function to print message int 21h ; do it pop dx pop ax pop bp ret 2