真正的程序员高度无限。这是@雷军 17年前花几天写的程序RAMInit(部分),如今能写出这么高质量的代码的程序员恐怕也不多。这段代码用x86汇编写成,运行于DOS,用于清除内存的驻留程序。DOS是个单任务系统,为了释放内存,因此就需要一个程序来强制清除这些驻留在内存的程序。
---------------------------------------------------------
;
; RI.ASM Revision 2.12 [ July 12, 1994 ]
Revision equ 'V2.12 '
;
; **************************************************************************
; * *
; * RAMinit Release 2.0 *
; * Copyright (c) 1989-1994 by Yellow Rose Software Co. *
; * Written by Mr. Leijun *
; * *
; * Function: *
; * Press HotKey to remove all TSR program after this program *
; * *
; **************************************************************************
; ..........................................................................
; Removed Softwares by RI:
; SPDOS v6.0F, WPS v3.0F
; Game Busters III, IV
; NETX ( Novell 3.11 )
; PC-CACHE
; Norton Cache
; Microsoft SmartDrv
; SideKick 1.56A
; MOUSE Driver
; Crazy (Monochrome simulate CGA program)
; RAMBIOS v2.0
; 386MAX Version 6.01
; ..........................................................................
; No cancel softwares:
; Windows 3.1 MSD
;
; No removed TSR softwares:
; MS-DOS fastopen
; Buffers, Files ... (QEMM 6.0)
; QCache (386MAX 6.01)
; ..........................................................................
;
COMMENT *
V2.04 Use mouse driver software reset function to initiation mouse
2/17/1993 by Mr. Lei and Mr. Feng
V2.05 RI cannot work in Windows DOS prompt
3/9/1993 by Mr. Lei
V2.06 1. When XMS cannot allocate 1K memory, RI halts.
2. RI repeat deallocates EMS memory.
V2.07 HotKey Setup Error
4/25/1993 by Mr. Lei
V2.08 KB Buffer
V2.10 1. Release high memory blocks (EMM386 QEMM386 S-ICE 386MAX)
2. RI copies flag
V2.12 1. Exists a critical error in Init 8259 procedure
2. Save [40:F0--FF] user data area
*
dosseg
.model tiny
.code
locals @@
org 100h
Start: jmp Main
org 103h
True equ 1
False equ 0
MaxHandles equ 100h
INT3 macro
out 0ffh,al
endm
HotKey Status Test Var
--------------- ---------------
7 6 5 4 3 2 1 0 417 418 496
. . x . x . . . Left Alt is pressed 8 2
x . . . x . . . Right Alt is pressed 8 8
. . . x . x . . Left Ctrl is pressed 4 1
. x . . . x . . Right Ctrl is pressed 4 4
. . . . . . x . Left Shift is pressed 2
. . . . . . . x Right Shift is pressed 1
LeftAlt equ 00101000b
RightAlt equ 10001000b
LeftCtrl equ 00010100b
RightCtrl equ 01000100b
LeftShift equ 00000010b
RightShift equ 00000001b
HotKey db LeftCtrl or RightCtrl
DataBegin dw 0
NextDataSeg dw 0ffffh
oldInt2F_addr dw 0, 0
XMS_control dw 0, 0
Handle_begin dw 0
cvtOfs dw 0 ; DOS 3.0 equ 0 and above DOS 4.0 is 1
org 104h
db 0dh
db Revision
db ??date
db 26
org 114h
tsrLength dw 0
MachineID db 0FCh IBM PC/AT
AuxHotKey db 0 ; 2Dh ; 'X' Scan Code
AuxHotKeyName db 'XYou can't use 'macro parameter character #' in math modeYou can't use 'macro parameter character #' in math mode+2
jcxz +2
jcxz +2
jcxz +2
jcxz +2
jcxz +2
jcxz +2
jcxz +2
jcxz +2
jcxz +2
jcxz +2
jcxz +2
jcxz +2
jcxz +2
jcxz Missing open brace for subscriptMissing open brace for subscript'
jz @@2
or al, al
jz @@2
mov ah, 0eh
int 10h
jmp short @@1
@@2: mov al, cs:clsStrcolor
mov cs:clsStr, al
ret
; -----------------------------------------------------------------------
Self dw 0
clsStrcolor db 17h
clsStr db 17h ; Color (White in Blue)
db ' RAMinit Version 2.12 (c) 1989-1994 by KingSoft Ltd. Mr. Leijun'
db 0dh,0ah
db ' ['
ShowCopies db '*'
db '] Activate...',0ah,0dh,'
mcbList equ offset endTSR + 2 + 2
vecList equ mcbList + 7*10 + 2 + 10h + 1 + 400h
devLink equ vecList + 4 + 5 * 26 + 4 + 10 * 30h + 4
xmsList equ devLink + 2 + MaxHandles * 2
emsList equ xmsList + 4 + 1024
crtMode equ emsList + 2 + 1Dh + 4 + 10h
tsrLen equ crtMode + 1
;
; DOS Environment Reserved by RI
; --------------------------------------------------
; Flag 'XX' 2 bytes
; Environment Segment 1 word
; Free MCBs <=7*10 bytes
; MCB segment 1 word
; MCB 5 bytes
; End flag 'MM' 1 word
; COM LPT ports 10h bytes
; LEDs status 1 bytes
; Packed vectors list <=400h bytes
; Flag 'CV' 2 bytes
; CVT First DPB pointer 4 bytes
; DPBs data <=5*26 bytes
; First DCB pointer 4 bytes
; Pointer to NUL 4 bytes
; All device driver datas <=30h*10 bytes
; Flag 'XM' 2 bytes
; XMS free handle counter 2 bytes
; EMS free handle list <=100h*4 bytes
; Flag 'EM' 2 bytes
; EMS free handle counter 2 bytes
; EMS free handle list <=1024 bytes
; EMS handle 1 word
; Number of pages 1 word
; Flag '--' 1 word
; Equipment List 1 word
; CRT 40:49h-66h 1dh bytes
; 40:A8h 1 dword
; BIOS User Data Area 40:F0--FF 10h bytes
; ***************************************************************************
;
main: jmp main0
Print Macro Str
Lea dx, Str
call DisplayStr
endm
InstMsg db 'RAMinit Version 2.12 '
db 'Copyright (c) 1989-1994 by KingSoft Ltd. ',0dh,0ah,''
Msg_0 db 0ah,'Residents a new RAMinit copy [y/n] ? '
Msg1 db 'Activate with: '
db 'Left_Shift '
db 'Left_Alt '
db 'Right_Alt '
db 'Alt '
db 'Alt'
crlf db 0dh,0ah,''
ErrMsg db 'ERROR: Invalid options !',0dh,0ah,0ah,''
SetMsg db 7, 'Defines new Hotkey successful !',0dh,0ah,0ah,'$'
tsrOK db False
Main0:
cld
Print instMsg
call IsWinDos
or ax, ax
jz @@1
Print WinErr
mov ax, 4c00h
int 21h
@@1:
call HotKeyValid
mov cs:Status, 0
call EMS_test
call CmpDosVer
call CmpSideKick
call GetMachineID
call ModifyHotKeyPrompt
mov ax, 0c0d7h
int 2fh
mov es, ax
cmp word ptr es:[101h], 'IE' 'LEI'
jnz @@0
mov cs:Self, ax
@@0:
call CmdLine
call PrintHotKeyPrompt
cmp cs:tsrOK, true
jz @@2
call tsrReplyOK
@@2: cmp cs:tsrOK, true
jnz @@_2
call PrintCopies
@@_2:
mov word ptr cs:[100h], 'EL'
mov byte ptr cs:[102h], 'I'
push cs
pop es
push cs
pop ds
std
mov si, offset eof
mov cx, eof - offset Here
mov di, tsrLen
add di, cx
inc cx
rep movsb
cld
mov bx, tsrLen
jmp bx
Here:
mov ax,cs
mov es,ax
mov di,offset endTSR
mov cs[s:3]ataBegin, di
mov cs:NextDataSeg, -1
mov ax, 'XX'
stosw
in al, 0a1h
mov ah, al
in al, 21h
push ax
mov word ptr cs[s:6]ld_8259, ax
xor ax, ax
out 21h,al CLI
call SaveOthers
call SetSelfInt
call BackupVecList
cmp cs[s:7]ower, true
jnz @@20
call BackupCVTchain
call BackupMemoryManager
@@20:
call BackupBiosData
sti
mov cs:Flag, ' ' no busy
mov cs:StopFlag, 0
mov cs:tsrLength, di
call SetDosEnvSeg
cmp cs:Self, 0
jz @@29
push cs
pop ds
push cs
pop es
cld
mov cx, cs:tsrLength
mov si, cs[s:3]ataBegin
sub cx, si
mov di, 120h
mov cs[s:3]ataBegin, di
rep movsb
mov cs:tsrLength, di
@@29:
pop ax
out 21h, al ; STI
mov al, ah
out 0a1h, al
mov dx, cs:tsrLength
inc dx
int 27h
; ----------------------------------------------------------------------------
SetDosEnvSeg:
push ds
push es
mov ax, cs
@@10: mov es, ax
mov ax, es:[16h] Get father process psp segment
or ax, ax
jz @@11
mov bx, es
cmp ax, bx
jnz @@10
@@11:
mov es, word ptr es:[2ch] ; Get father process env segment
mov cs[s:3]osEnv, es
pop es
pop ds
ret
; ----------------------------------------------------------------------------
SaveOthers:
mov ax, cs:[2ch] Env Seg
stosw
call backupMCB ; Current MCB
mov ax, 40h ; COM LPT Port
mov ds, ax
mov si, 0h
mov cx, 8
rep movsw
mov si, 17h ; LED status
lodsb
stosb
call OpenLEDs
ret
; --------------------------------------------------------------------------
backupMCB:
mov ax, 'ZM'
stosw
push ds
push es
mov ah, 52h
int 21h ; Get MCB chain head
mov ax, es:[bx-2]
pop es
@@0: mov ds, ax
cmp byte ptr ds:[0], 'Z' End ?
jz @@20
cmp byte ptr ds:[0], 'M' Memory control block
jnz @@30
cmp word ptr ds:[3], 0 Nul mcb
jz @@10
cmp word ptr ds:[1], 0 Free MCB
jnz @@10
call SaveFreeMCB
@@10: inc ax
add ax, ds:[3]
jmp @@0
@@20:
call SaveFreeMCB
cmp ax, 0a000h
inc ax
jnb @@30
mov ax, 9fffh ; MS-DOS UMB
jmp @@0
@@30:
cmp ax, 0c000h 386MAX
ja @@90
mov ax, 0c020h
jmp @@0
@@90: ; Error ?
pop ds
mov ax, 'MM' Set MCB flag
stosw
ret
SaveFreeMCB:
stosw
xor si,si
movsb
movsw
movsw
ret
;
; push ax
; stosw
; xor si,si
; movsb
; movsw
; movsw
; pop ax
; cmp ax, 09fffh
; jnb @@3
; push ax
; push ds
; mov ds,ax
; cmp byte ptr ds:[0], 'M'
; pop ds
; pop ax
; jnz @@4
; mov ax, 09fffh MS-DOS UMB
; jmp @@0
; @@4: cmp ax, 0c000h
; ja @@3
; mov ax, 0c020h 386MAX
; jmp @@0
;
; --------------------------------------------------------------------------
OpenLEDs: push ax Open all LEDs
or al, 070h
mov ds:[17h], al
mov ah, 1
int 16h
mov cx, 4 ; Delay
@@20: push cx
xor cx, cx
@@21: loop @@21
pop cx
loop @@20
pop ax
mov ds:[17h], al
mov ah, 1
int 16h
ret
; --------------------------------------------------------------------------
SetSelfInt:
push es
push di
cmp cs:self, 0
jnz @@1
push cs
pop ds
mov ax,3509h
int 21h
mov word ptr cs[s:6]ldInt9_addr,bx
mov word ptr cs[s:6]ldInt9_addr[2],es
mov dx,offset NewInt9
mov ax,2509h
int 21h
mov ax,352Fh
int 21h
mov word ptr cs[s:6]ldInt2F_addr,bx
mov word ptr cs[s:6]ldInt2F_addr[2],es
mov dx,offset newInt2F
mov ax,252Fh
int 21h
mov ax,351Ch
int 21h
mov word ptr cs[s:6]ldInt1C_addr,bx
mov word ptr cs[s:6]ldInt1C_addr[2],es
mov dx,offset newInt1C
mov ax,251ch
int 21h
cli
jmp @@2
@@1:
mov es, cs:Self
inc es:Copies
@@_0: cmp es:NextDataSeg, -1
jz @@_1
mov es, es:NextDataSeg
jmp @@_0
@@_1: mov es:NextDataSeg, cs
@@2:
pop di
pop es
ret
; -----------------------------------------------------------------------
SaveCounter:
mov word ptr es:[di], 'EL'
mov byte ptr es:[di+2], 'I'
mov byte ptr es:[di+3], bl
xor bx, bx
add di, 4
ret
; -----------------------------------------------------------------------
DisplayStr: push cs
pop ds
mov ah, 9
int 21h
ret
; -----------------------------------------------------------------------
CmdLine:
push cs
pop ds
xor ax, ax
mov si, 80h
lodsb
or al, al
jnz @@1
ret
@@1:
mov cx, ax
dec ax
push ax
push si
@@0: lodsb
cmp al, ' '
jz @@0
cmp al, '/'
jnz @@2
lodsb
cmp al, 'S'
jz @@_2
cmp al, 's'
jnz @@2
@@_2:
call SetHotKey
Print SetMsg
mov ax, 4c00h
int 21h
@@2:
pop si
pop ax
push ax
push si
@@_3: lodsb
cmp al, 'A'
jb @@3
cmp al, 'Z'
ja @@3
add byte ptr ds:[si-1],20h DownCase
@@3: loop @@_3
pop si
pop cx
add si, cx
lodsb
cmp al, 's' ; CLS
jnz @@5
cmp word ptr ds:[si-3], 'lc'
jnz @@5
cmp cs:Self, 0
jz @Err
mov ax, 0c0d7h+1
int 2fh
@@5: cmp al, 'h' ; HELP
jz @help
cmp al, '?'
jz @help
cmp al, 't' ; RET
jnz @@6
cmp word ptr ds:[si-3], 'er'
jnz @@6
@@7:
cmp cs:Self, 0
jz @Err
mov ax, 0c0d7h+2
int 2fh
@@6: cmp al, 'w' ; NEW
jnz @@8
cmp word ptr ds:[si-3], 'en'
jnz @@8
mov cs:tsrOK, true
ret
@@8:
cmp al, 'l' ; ALL
jnz @@9
cmp word ptr ds:[si-3], 'la'
jnz @@9
mov ax, 0c0d7h+3
int 2fh
@@9:
cmp al, ' '
jnz @Err
ret
@Err:
Print ErrMsg
@help:
Print HelpMsg
mov ax, 4c00h
int 21h
;---------------------------------------------------------------------------
tsrReplyOK:
cmp cs:Self, 0
jz @@1
Print Msg0
push es
mov ax, cs:Self
@@_10: mov es, ax
mov ax, es:NextDataSeg
cmp ax, -1
jnz @@_10
mov ax, es
@@_0: push ax
dec ax
mov es, ax
mov bx, es:[3]
pop ax
add ax, bx
inc ax
mov es, ax
cmp word ptr es:[0], 'OC'
jz @@_0
mov bx, cs
cmp ax, bx
pop es
jz @@2
Print Msg_0
mov ah, 1
int 21h
push ax
Print crlf
pop ax
cmp al, 'y'
jz @@3
cmp al, 'Y'
jz @@3
@@2: Print Msg_1
mov ax, 4c01h
int 21h
@@3:
@@1: mov cs:tsrOK, true
ret
PrintCopies:
cmp cs:Self, 0
jz @@1
push es Added -by- Mr. Lei
mov es, cs:Self ; Aug 24, 1993
mov al, es:Copies
inc al Total RI copies
push ax Set es = current mcb
mov ax, cs
dec ax
mov es, ax
pop ax
mov cx, 5 ; Search end of file name
mov bx, 8
@@10: inc bx
cmp byte ptr es:[bx], 20h
jz @@20
cmp byte ptr es:[bx], 0ffh
jz @@20
cmp byte ptr es:[bx], 00h
jz @@20
loop @@10
@@20: ; Set current RI no
mov byte ptr es:[bx], ':' ; "RI:2"
mov byte ptr es:[bx+1], al
cmp bx, 8+7
jnb @@30
mov byte ptr es:[bx+2], 0
@@30:
pop es
mov cs:Msg_RI, al
Print Msg_2
@@1: ret
;---------------------------------------------------------------------------
; Backup Interrupt Vector List
;
BackupVecList:
push ds
push cs
pop es
xor si,si ; Vectors
mov ds,si
movsw
movsw
xor bx, bx
mov cx,00ffh
@@0: lodsw
xchg dx, ax
lodsw
cmp ax, es:[di-2]
jnz @@1
cmp dx, es:[di-4]
jz @@2
@@1: or bx, bx
jz @@3
call SaveCounter
@@3: xchg dx, ax
stosw
xchg dx, ax
stosw
loop @@0
jmp @@4
@@2: inc bx
loop @@0
call SaveCounter
@@4:
pop ds
ret
;
;-----------------------------------------------------------------------------
BackupCVTchain:
mov ax, 'VC'
stosw
push ax
push bx
push cx
push ds
push es
mov ah, 52h
int 21h ; ES:BX -- DOS table as described below
--------------------------------------------------------------------
push es DPB chains
push bx
lds si, es:[bx]
push cs
pop es
mov ax, si
stosw
mov ax, ds
stosw
mov bx, cs:cvtOfs
xor cx, cx
@@1: mov al, ds:[si+1]
stosb
mov ax, ds:[si+bx+12h]
stosw
mov ax, ds:[si+bx+14h]
stosw
inc cx
lds si, ds:[si+bx+18h]
cmp si, -1
jnz @@1
mov ax, 5
mul cl
add ax, 4
add cs:tsrLength, ax
pop bx
pop es
--------------------------------------------------------------------
push es DCB file control blocks
push bx
les bx, es:[bx+4]
@@11: cmp word ptr es:[bx], -1
jz @@10
les bx, es:[bx]
jmp @@11
@@10:
mov ax, es
xchg ax, bx
push cs
pop es
stosw
xchg ax, bx
stosw
pop bx
pop es
add cs:tsrLength, 4
---------------------------------------------------------------------
push es Device Driver Chains
pop ds
add bx, 22h
mov si, bx NUL
pop es
mov ax, si
stosw
mov ax, ds
stosw
xor cx, cx
xor bx, bx
@@9: push si
mov cl, 5
rep movsw
inc bx
pop si
lds si, ds:[si]
mov ax, si
inc ax
jnz @@9
pop ds
pop cx
pop bx
pop ax
ret
; ----------------------------------------------------------------------------
BackupBiosData:
mov ax, '--'
stosw
push ds
push si
mov si, 40h
mov ds, si
mov si, 10h
movsw
mov si, 0a8h
movsw
movsw
mov si, 49h
mov cx, 1dh
rep movsb
mov si, 0f0h
mov cx, 8
rep movsw
pop si
pop ds
ret
; ---------------------------------------------------------------------------
BackupMemoryManager:
push cs
pop es
push ds
push es
call SaveXMSstatus
call SaveEMSstatus
pop es
pop ds
ret
---------------------------------------------------------------------
SaveEMSstatus:
test cs:status, EMSbit
jnz @@1
ret
@@1:
mov ax, 'ME'
stosw
inc di
inc di
push di
mov ah, 4dh
int 67h
pop di
mov es:[di-2], bx
shl bx, 1
shl bx, 1
add di, bx
ret
-------------------------------------------------------------------
SaveXMSstatus:
call XMS_test
test cs:status, XMSbit
jnz @@1
ret
@@1:
mov ax, 'MX'
stosw
mov dx, 1
call XMS_alloc
jnz @@_1
xor cx, cx XMS alloc failure
stosw
ret
@@_1:
push dx
sub dx, MaxHandles * 10
@@2:
push dx
call XMS_Lock
pop dx
jnz @@3
cmp bl, 0a2h
jnz @@4
add dx, 10
jmp @@2
@@3: push dx
call XMS_unlock
pop dx
@@4:
mov cs:handle_begin, dx
pop dx
push dx
call XMS_bstat
xor cx, cx
mov cl, bl
inc cx
pop dx
call XMS_Free
mov dx, cs:Handle_begin
push cx
push cs
pop es
mov ax, cx
stosw
@@5: push dx
call XMS_Lock
pop dx
jnz @@6
cmp bl, 0a2h Handle invalid
jz @@7
@@6: call XMS_unlock
add dx, 10
jmp @@5
@@7: mov ax, dx
stosw
add dx, 10
loop @@5
pop cx
ret
------------------------------------------------------------------
XMS_test:
push es
mov ax, 4300h
int 2fh
cmp al, 80h
jnz @@9
mov ax, 4310h
int 2fh
mov cs:XMS_control, bx
mov cs:XMS_control[2], es
or cs:Status, XMSbit
@@9:
pop es
ret
XMS_stat:
mov ah, 0
call dword ptr cs:xms_control
mov hma_exist, dl
ret
hma_exist db 0
XMS_alloc:
mov ah, 9
call dword ptr cs:xms_control
or ax, ax
ret
XMS_lock:
mov ah, 0ch
call dword ptr cs:xms_control
or ax, ax
ret
XMS_unlock:
mov ah, 0dh
call dword ptr cs:xms_control
or ax, ax
ret
XMS_bstat:
mov ah, 0eh
call dword ptr cs:xms_control
or ax, ax
ret
XMS_free:
mov ah, 0ah
call dword ptr cs:xms_control
or ax, ax
ret
; ----------------------------------------------------------------------------
EMS_test:
push cs
pop ds
mov dx, offset EMMname
mov ax, 3d00h
int 21h
jc @@2
mov bx, ax
mov ah, 3eh
int 21h
or cs:Status, EMSbit
@@2:
ret
EMMname db 'EMMXXXX0',0
; -----------------------------------------------------------------------------
SetHotKey:
xor bx, bx
lodsb
push ax
@@1: lodsb
cmp al, 0dh
jz @@9
cmp al, 'C'
jnz @@2
or bl, LeftCtrl
jmp @@1
@@2:
cmp al, 'c'
jnz @@3
or bl, RightCtrl
jmp @@1
@@3:
cmp al, 'A'
jnz @@4
or bl, LeftAlt
jmp @@1
@@4:
cmp al, 'a'
jnz @@5
or bl, RightAlt
jmp @@1
@@5:
cmp al, 'S'
jnz @@6
or bl, LeftShift
jmp @@1
@@6:
cmp al, 's'
jnz @@7
or bl, RightShift
jmp @@1
@@7: pop ax
jmp @Err
@@9:
mov cs:HotKey, bl
pop ax
mov cs:AuxHotKey, 2dh ; 'X' scan key
cmp al, '1'
jz @@29
mov cs:AuxHotKey, 0
@@29:
cmp cs:Self, 0
jz @@30
push es
mov es, cs:Self
mov es:HotKey, bl
mov bl, cs:AuxHotKey
mov es:AuxHotKey, bl
pop es
@@30:
call GetRunFileName
mov ax, 3d02h
int 21h
jc @@10
push cs
pop ds
mov bx, ax
mov cx, 4
mov dx, 100h
mov ah, 40h
int 21h
jc @@10
mov ax, 4200h
xor cx, cx
mov dx, 17h
int 21h
jc @@10
mov cx, 1
mov dx, offset AuxHotKey
mov ah, 40h
int 21h
jc @@10
mov ah, 3eh
int 21h
@@10:
ret
; -----------------------------------------------------------------------
GetRunFileName:
; Return:
; DS[s:3]X Pointer of this run file name ASCIIZ string
push ax
push bx
push cx
push si
push di
push es
push cs
pop es
mov ax, es:[2ch]
mov es, ax
xor di, di
mov cx, 1000h
xor al, al
@@1: repnz scasb
cmp es:[di], al
loopnz @@1
mov dx, di
add dx, 3
push es
pop ds
pop es
pop di
pop si
pop cx
pop bx
pop ax
ret
; ---------------------------------------------------------------------------
GetMachineID:
push es
mov KBD102,True
mov ax,40h
mov es,ax
test byte ptr es:[96h], 00010000b
jnz @@1
mov Kbd102,False
@@1:
xor ax,ax
dec ax
mov es,ax
mov al,es:[0eh]
mov cs:MachineID, al
pop es
ret
; ---------------------------------------------------------------------------
ModifyHotKeyPrompt:
cmp cs:Kbd102, True
jz @@9
push cs
pop es
push cs
pop ds
mov cx, 12*4
mov si, offset KMsg2
mov di, offset KMsg1
rep movsb
@@9: cmp cs:MachineID, 0fch
jna @@10
mov cs:clsStrcolor, 70h ; Mono
mov cs:clsStr, 70h
@@10:
ret
; ---------------------------------------------------------------------------
PrintHotKeyPrompt:
Print Msg1
mov al, cs:HotKey
mov ah, al
shr al, 1
shr al, 1
and ax, 33ch
or al, ah
mov dx, offset KeyMsg
@@40:
or ax, ax Mr. Lei 4/25/1993
jz @@_42
shr al, 1
push ax
jnc @@41
push ax
call ColorDisplayStr
mov ah, 9
int 21h
pop ax
or al, al
jz @@42
push dx
200字以内,仅用于支线交流,主线讨论请采用回复功能。