下一个程序的输入工作正常,但是当我要求显示输出时,DOS 根本不显示任何东西!这怎么可能?
ORG 256
mov dx, msg1
mov ah, 09h ;DOS.WriteString
int 21h
mov dx, buf
mov ah, 0Ah ;DOS.BufferedInput
int 21h
mov dx, msg2
mov ah, 09h ;DOS.WriteString
int 21h
mov dx, buf
mov ah, 09h ;DOS.WriteString
int 21h
mov ax, 4C00h ;DOS.TerminateWithExitcode
int 21h
; --------------------------------------
msg1: db 'Input : ', '$'
buf: db 20 dup ('$')
msg2: db 13, 10, 'Output : ', '$'
; --------------------------------------
答案 0 :(得分:3)
看看你如何定义输入缓冲区(buf: db 20 dup ('$')
),我明白了
你想要偷工减料并且输入已经为$ -terminated准备好了
重新显示它。遗憾的是,这会扰乱DOS输入所需的设置
功能0Ah和您的程序遇到潜在缓冲区的严重问题
超限。
此外,使用$ -termination并不是您可以做出的最明智的选择
因为$字符可能已经出现在输入的字符中。
我在下面介绍的所有示例程序都将使用零终止
代替。
int 21h AH=0Ah
此Buffered STDIN Input函数从键盘获取字符
继续这样做,直到用户按下 Enter 键。所有
字符和最终回车符放在存储空间中
从调用程序提供的输入缓冲区的第3个字节开始
通过DS:DX
中的指针
不包括最终回车的字符数存储在
输入缓冲区的第二个字节
调用程序的责任是告诉DOS有多大
存储空间是。因此,您必须将其长度放在第1个字节中
调用此函数前输入缓冲区。允许输入1
您将存储大小设置为2的字符。允许输入254
您将存储大小设置为255的字符
如果您不希望能够从模板中调用之前的任何输入,
那么最好也将第二个字节归零。基本上模板是
调用程序的输入缓冲区中预先存在的(和有效的)内容
提供。如果预先存在的内容无效,则模板不是
可用。
令人惊讶的是,此功能的编辑功能有限。
可以使用更多编辑键。它们都让人想起 EDLIN.EXE , 古老的DOS行编辑器,它是每个前一行的文本编辑器 成为构建下一行的模板。
此功能扩展了标签。标签扩展是替换的过程 ASCII 9由一系列一个或多个空格(ASCII 32)直到光标到达 列位置是8的倍数 此选项卡扩展仅在屏幕上发生。存储空间将保留ASCII 9。
此函数执行 ctrl C / ctrl Break 检查。
当此功能完成时,光标将位于最左侧的列中 当前行。
示例1,缓冲STDIN输入。
ORG 256 ;Create .COM program
cld
mov si, msg1
call WriteStringDOS
mov dx, buf
mov ah, 0Ah ;DOS.BufferedInput
int 21h
mov si, msg2
call WriteStringDOS
mov si, buf+2
movzx bx, [si-1] ;Get character count
mov word [si+bx+1], 10 ;Keep CR, append LF and 0
call WriteStringDOS
mov ax, 4C00h ;DOS.TerminateWithExitcode
int 21h
; --------------------------------------
; IN (ds:si) OUT ()
WriteStringDOS:
pusha
jmps .b
.a: mov dl, al
mov ah, 02h ;DOS.DisplayCharacter
int 21h ; -> AL
.b: lodsb
test al, al
jnz .a
popa
ret
; --------------------------------------
buf: db 255, 16, "I'm the template", 13, 255-16-1+2 dup (0)
msg1: db 'Choose color ? ', 0
msg2: db 10, 'You chose ', 0
; --------------------------------------
int 21h AH=3Fh
与预定义句柄0(BX
)一起使用时Read From File Or Device
函数从键盘获取字符并继续这样做,直到
用户按 Enter 。所有字符(从不超过127)和
最后的回车加上额外的换行符放在私人中
DOS内核中的缓冲区。这现在成为新模板
此后,该函数将写入DS:DX
提供的缓冲区中的金额
CX
参数中请求的字节数。如果CX
指定了一个数字
它小于此输入生成的一个或多个字节数
需要额外调用此函数才能检索完整的输入。
只要有剩余的字符被拿起,这个功能就会
不使用键盘启动另一个输入会话!这之间甚至是如此
不同的程序或同一程序的会话。
上一节中描述的所有编辑键都可用。
标签仅在屏幕上展开,而不是在模板中展开。
此函数执行 ctrl C / ctrl Break 检查。
当此功能完成时,光标将位于
的最左列示例2a,从文件或设备读取,一次全部接收。
ORG 256 ;Create .COM program
cld
mov si, msg1
call WriteStringDOS
mov dx, buf
mov cx, 127+2 ;Max input is 127 chars + CR + LF
xor bx, bx ;STDIN=0
mov ah, 3Fh ;DOS.ReadFileOrDevice
int 21h ; -> AX CF
jc Exit
mov bx, ax ;Bytes count is less than CX
mov si, msg2
call WriteStringDOS
mov si, buf
mov [si+bx], bh ;Keep CR and LF, append 0 (BH=0)
call WriteStringDOS
Exit: mov ax, 4C00h ;DOS.TerminateWithExitcode
int 21h
; --------------------------------------
; IN (ds:si) OUT ()
WriteStringDOS:
pusha
jmps .b
.a: mov dl, al
mov ah, 02h ;DOS.DisplayCharacter
int 21h ; -> AL
.b: lodsb
test al, al
jnz .a
popa
ret
; --------------------------------------
buf: db 127+2+1 dup (0)
msg1: db 'Choose color ? ', 0
msg2: db 'You chose ', 0
; --------------------------------------
示例2b,从文件或设备读取,一次拾取一个字节。
ORG 256 ;Create .COM program
cld
mov si, msg1
call WriteStringDOS
mov dx, buf
mov cx, 1
xor bx, bx ;STDIN=0
mov ah, 3Fh ;DOS.ReadFileOrDevice
int 21h ; -> AX CF
jc Exit
mov si, msg2
call WriteStringDOS
mov si, dx ;DX=buf, CX=1, BX=0
Next: mov ah, 3Fh ;DOS.ReadFileOrDevice
int 21h ; -> AX CF
jc Exit
call WriteStringDOS ;Display a single byte
cmp byte [si], 10
jne Next
Exit: mov ax, 4C00h ;DOS.TerminateWithExitcode
int 21h
; --------------------------------------
; IN (ds:si) OUT ()
WriteStringDOS:
pusha
jmps .b
.a: mov dl, al
mov ah, 02h ;DOS.DisplayCharacter
int 21h ; -> AL
.b: lodsb
test al, al
jnz .a
popa
ret
; --------------------------------------
msg1: db 'Choose color ? ', 0
msg2: db 10, 'You chose '
buf: db 0, 0
; --------------------------------------
int 2Fh AX=4810h
此DOSKEY Buffered STDIN Input函数只能调用if the DOSKEY.COM TSR was installed。它的运行方式与常规的Buffered非常相似 STDIN输入功能0Ah(见上文),但具有相同的编辑功能 作为DOS命令行的可能性,包括使用所有的能力 DOSKEY特殊键。
在DOS 6.2上,存储空间始终限制为128个字节,允许输入
127个字符和强制回车的空间。不是
可以预先加载模板,因此始终设置输入的第二个字节
缓冲到零。
在DOS Win95上,如果安装了,则存储空间可以大到255个字节
DOSKEY.COM TSR使用doskey /line:255
之类的命令。它有可能
使用模板预加载存储空间。这带来了Win95版本
非常接近输入函数0Ah可行的。
此函数执行 ctrl C / ctrl Break 检查。
当此功能完成时,光标将位于最左侧的列中
当前行。如果字符数为零,则表示用户输入了
尚未展开的DOSKEY宏的名称。你没有
去看看未展开的线!需要第二次调用该函数
并且在这次返回时,光标将位于最后一个字符的后面
扩展文本。
一个特点是,当多命令宏($T
)扩展时,您只能
获取第一个命令的扩展文本。额外的调用
获取其他扩展文本需要函数。虽然这一切都是
在COMMAND.COM等命令shell中,从用户内部非常有用
应用它真的很烦人,你不知道什么时候发生这种情况。
由于输入的文本被添加到命令历史中,因此不可避免 历史填补了无关的项目。当然不是你想看到的 在DOS提示符下!
示例3,调用DOSKEY.COM。
ORG 256 ;Create .COM program
cld
mov ax, 4800h ;DOSKEY.CheckInstalled
int 2Fh ; -> AL
test al, al
mov si, err1
jz Exit_
Again: mov si, msg1
call WriteStringDOS
mov dx, buf
mov ax, 4810h ;DOSKEY.BufferedInput
int 2Fh ; -> AX
test ax, ax
mov si, err2
jnz Exit_
cmp [buf+1], al ;AL=0
je Again ;Macro expansion needed
mov si, msg2
call WriteStringDOS
mov si, buf+2
movzx bx, [si-1] ;Get character count (is GT 0)
mov word [si+bx+1], 10 ;Keep CR, append LF and 0
Exit_: call WriteStringDOS
Exit: mov ax, 4C00h ;DOS.TerminateWithExitcode
int 21h
; --------------------------------------
; IN (ds:si) OUT ()
WriteStringDOS:
pusha
jmps .b
.a: mov dl, al
mov ah, 02h ;DOS.DisplayCharacter
int 21h ; -> AL
.b: lodsb
test al, al
jnz .a
popa
ret
; --------------------------------------
buf: db 128, 0, 128+2 dup (0)
msg1: db 'Choose color ? ', 0
msg2: db 13, 10, 'You chose ', 0
err1: db 'N/A', 13, 10, 0
err2: db 'Failed', 13, 10, 0
; --------------------------------------
int 21h AH=08h
由于Stack Overflow强加的30000字节限制,文本在下面的答案中继续...
了解来源的问题?我使用的汇编程序:
push cx si
转换为push cx
push si
。答案 1 :(得分:2)
int 21h AH=08h
到目前为止所描述的所有三种输入方法(在上面的答案!中)都是明确量身定制的,以适应像EDLIN.EXE和COMMAND.COM这样的Microsoft工具。
如果您正在编写自己的应用程序,那么可以获得更好的结果
通过制作自己的输入程序。这种程序的核心
将是DOS单字符输入函数之一。我选择了STDIN
Input函数08h,因为我想允许
ctrl C / ctrl 打破检查和我
打算通过BIOS Int 10h AH=09h
自己回应这些角色
Write Character And Attribute At Cursor Position。这样我就可以
避免弄乱任何重定向输出。
以编程方式使用此 BufferedInput 过程没有区别 或 DOS.BufferedInput 系统调用。但是对于键盘上的用户 输入将更容易,因为所有键与旧和 困难的模板编辑已被解雇并被通常的替换 编辑键,使您可以自由移动光标。
如果输入缓冲区的第二个字节保持非零值,则存储空间 应该包含一个旧字符串(可能来自以前的输入)。 DOS会 把这称为模板。与DOS不同的是:
当输入正在进行时,标签不展开且输入为
仅限于留在当前行内。较长的文本将水平滚动。
最后完成输入后,已完成的文本将带选项卡一次写入
扩展(在屏幕上,存储空间将始终保持ASCII 9)并且不再局限于单行。
此程序执行 ctrl C / ctrl Break 检查。
当此过程完成时,光标将位于最左侧的列中 当前行。
此程序是用input redirection and output redirection编写的
记住,因此非常适合控制台应用。
输入重定向的一个影响是将任何临时输出回显到屏幕是没用的。用户不在那里凝视屏幕,或者临时输出将在眨眼之间消失。
示例4,改进的缓冲STDIN输入。
ORG 256 ;Create .COM program
cld
mov si, msg1
call WriteStringDOS
mov dx, buf
call BufferedInput ;Replaces 'mov ah, 0Ah : int 21h'
mov si, msg2
call WriteStringDOS
mov si, buf+2
movzx bx, [si-1] ;Get character count
mov word [si+bx+1], 10 ;Keep CR, append LF and 0
call WriteStringDOS
mov ax, 4C00h ;DOS.TerminateWithExitcode
int 21h
; --------------------------------------
; IN (ds:si) OUT ()
WriteStringDOS:
pusha
jmps .b
.a: mov dl, al
mov ah, 02h ;DOS.DisplayCharacter
int 21h ; -> AL
.b: lodsb
test al, al
jnz .a
popa
ret
; --------------------------------------
; IN (ds:dx) OUT ()
BufferedInput:
; Entry DS:DX Buffer of max 1+1+255 bytes
; 1st byte is size of storage space starting at 3rd byte
; 2nd byte is size of old (CR-terminated) string, 0 if none
; Storage space can contain old (CR-terminated) string
; Exit DS:DX Nothing changed if header bytes were invalid
; 1st byte unchanged
; 2nd byte is size of new CR-terminated string
; Storage space contains new CR-terminated string
; Local [bp-1] PAGE Display page
; [bp-2] STORE Size of storage space
; [bp-3] ROW Row of input box
; [bp-4] COL Column of input box
; [bp-5] SHIFT Number of characters shifted out on the leftside
; [bp-6] INBOX Size of input box
; [bp-7] LIX Number of characters in current input string
; [bp-8] CIX Position of cursor in current input string
; [bp-10] FLAGS Bit[0] is ON for normal keyboard input
pusha
mov si, dx
lodsw ; -> SI points at storage space
test al, al ;AL is size of storage space
jz .Quit ;No storage space!
cmp ah, al ;AH is size of old string
jnb .Quit ;Old string too long!
mov bl, al
sub sp, 256 ;Local edit buffer (max size)
mov bp, sp
mov ah, 0Fh ;BIOS.GetVideoMode
int 10h ; -> AL=Mode AH=Cols BH=Page
push bx ;STORE and PAGE
mov bl, ah
mov ah, 03h ;BIOS.GetCursor
int 10h ; -> CX=Shape DL=Col DH=Row
push dx ;COL and ROW
sub bl, dl ;Size of the widest inbox
xor bh, bh
push bx ;INBOX and SHIFT
push bx ;CIX and LIX (replaces 'sub sp, 2')
call .ESC ;Clear edit buffer, reset some vars
mov cl, [si-1] ;Size of old string (starts at SI)
jmps .b
.a: lodsb ;Storage space gives old string
push cx si
call .Asc ;Input old string
pop si cx
.b: sub cl, 1
jnb .a
xor bx, bx ;STDIN
mov ax, 4400h ;DOS.GetDeviceInformation
int 21h ; -> AX DX CF
jc .c ;Go default to keyboard
test dl, dl
jns .d ;Block device, not keyboard
shr dl, 1
.c: adc bx, bx ; -> BX=1 if Keyboard
.d: push bx ;FLAGS
.Main: call .Show ;Refresh input box on screen
call .Key ;Get key from DOS -> AX
mov bx, .Scans
test ah, ah
jz .f ;Not an extended ASCII
mov [cs:.Fail], ah ;Sentinel
.e: lea bx, [bx+3]
cmp ah, [cs:bx-1]
jne .e
.f: call [cs:bx]
jmps .Main
.Quit: popa ;Silently quiting just like DOS
ret
; - - - - - - - - - - - - - - - - - - -
.Scans: db .Asc
db 4Bh, .s4B ;<LEFT>
db 4Dh, .s4D ;<RIGHT>
db 47h, .s47 ;<HOME>
db 4Fh, .s4F ;<END>
db 77h, .s77 ;<CTRL-HOME>
db 75h, .s75 ;<CTRL-END>
db 53h, .s53 ;<DELETE>
.Fail: db ?, .Beep
; - - - - - - - - - - - - - - - - - - -
.Beep: mov ax, 0E07h ;BIOS.TeletypeBell
int 10h
ret
; - - - - - - - - - - - - - - - - - - -
.Key: call :1
test ah, ah ;Extended ASCII requires 2 calls
jnz :2
:1: mov ah, 08h ;DOS.STDINInput
int 21h ; -> AL
mov ah, 0
:2: xchg al, ah
ret
; - - - - - - - - - - - - - - - - - - -
.Show: test word [bp-10], 1 ;FLAGS.Keyboard ?
jz :Ready ;No, input is redirected
movzx di, [bp-6] ;INBOX
movzx si, [bp-5] ;SHIFT
mov dx, [bp-4] ;COL and ROW
mov cx, 1 ;Replication count
mov bh, [bp-1] ;PAGE
mov bl, 07h ;WhiteOnBlack
:Next: mov ah, 02h ;BIOS.SetCursor
int 10h
mov al, [bp+si]
mov ah, 09h ;BIOS.WriteCharacterAndAttribute
int 10h
inc dl ;Next column
inc si ;Next character
dec di
jnz :Next ;Process all of the input box
mov dx, [bp-4] ;COL and ROW
add dl, [bp-8] ;CIX
sub dl, [bp-5] ;SHIFT
mov ah, 02h ;BIOS.SetCursor
int 10h
:Ready: ret
; - - - - - - - - - - - - - - - - - - -
.BS: cmp byte [bp-8], 0 ;CIX
jne :1
ret
:1: call .s4B ;<LEFT>
; --- --- --- --- --- --- --
; <DELETE>
.s53: movzx di, [bp-8] ;CIX
movzx cx, [bp-7] ;LIX
sub cx, di
je :2 ;Cursor behind the current input
:1: mov dl, [bp+di+1] ;Move down in edit buffer
mov [bp+di], dl
inc di
dec cx
jnz :1
dec byte [bp-7] ;LIX
:2: ret
; - - - - - - - - - - - - - - - - - - -
.RET: xor si, si
mov bx, [bp+256+10] ;pusha.DX -> DS:BX
mov al, [bp-7] ;LIX
inc bx
mov [bx], al ;2nd byte is size of new string
inc bx
jmps :2
:1: mov dl, [bp+si]
mov [bx+si], dl ;Storage space receives new string
inc si
:2: sub al, 1
jnb :1
mov byte [bx+si], 13 ;Terminating CR
push bx ;(1)
call .ESC ;Wipe clean the input box
call .Show ; and reset cursor
pop si ;(1) -> DS:SI
:3: lodsb ;Final unrestricted display,
mov dl, al ; expanding tabs
mov ah, 02h ;DOS.DisplayCharacter
int 21h ; -> AL
cmp dl, 13 ;Cursor ends in far left column
jne :3
lea sp, [bp+256] ;Free locals and edit buffer
popa
ret
; - - - - - - - - - - - - - - - - - - -
.ESC: mov di, 256 ;Fill edit buffer with spaces
:1: sub di, 2
mov word [bp+di], " "
jnz :1
mov [bp-8], di ;DI=0 -> CIX=0 LIX=0
mov byte [bp-5], 0 ;SHIFT=0
ret
; - - - - - - - - - - - - - - - - - - -
.Asc: cmp al, 8 ;<BACKSPACE>
je .BS
cmp al, 13 ;<RETURN>
je .RET
cmp al, 27 ;<ESCAPE>
je .ESC
cmp al, 10 ;Silently ignoring linefeed
jne :1 ; in favor of input redirection
ret
:1: movzx di, [bp-8] ;CIX
movzx si, [bp-7] ;LIX
lea dx, [si+1]
cmp dl, [bp-2] ;STORE
jb :3
jmp .Beep ;Storage capacity reached
:2: mov dl, [bp+si-1] ;Move up in edit buffer
mov [bp+si], dl
dec si
:3: cmp si, di
ja :2
mov [bp+si], al ;Add newest character
inc byte [bp-7] ;LIX
; --- --- --- --- --- --- --
; <RIGHT>
.s4D: inc byte [bp-8] ;CIX
mov al, [bp-7] ;LIX
cmp [bp-8], al ;CIX
jbe .Shift
mov [bp-8], al ;CIX
ret
; - - - - - - - - - - - - - - - - - - -
; <LEFT>
.s4B: sub byte [bp-8], 1 ;CIX
jnb .Shift
; --- --- --- --- --- --- --
; <HOME>
.s47: mov byte [bp-8], 0 ;CIX
jmps .Shift
; - - - - - - - - - - - - - - - - - - -
; <END>
.s4F: mov al, [bp-7] ;LIX
mov [bp-8], al ;CIX
; --- --- --- --- --- --- --
.Shift: mov dl, [bp-5] ;SHIFT
mov al, [bp-8] ;CIX
cmp al, dl
jb :1
add dl, [bp-6] ;INBOX
sub al, dl
jb :2
inc al
add al, [bp-5] ;SHIFT
:1: mov [bp-5], al ;SHIFT
:2: ret
; - - - - - - - - - - - - - - - - - - -
; <CTRL-HOME>
.s77: call .BS
cmp byte [bp-8], 0 ;CIX
ja .s77
ret
; - - - - - - - - - - - - - - - - - - -
; <CTRL-END>
.s75: call .s53 ;<DELETE>
mov al, [bp-8] ;CIX
cmp al, [bp-7] ;LIX
jb .s75
ret
; --------------------------------------
buf: db 255, 16, "I'm an OldString", 13, 255-16-1+2 dup (0)
msg1: db 'Choose color ? ', 0
msg2: db 10, 'You chose ', 0
; --------------------------------------
了解来源的问题?我使用的汇编程序:
push cx si
转换为push cx
push si
。要获得真正高效的输入程序,请查看Rich Edit Form Input,即代码审核贡献。