处理 ReadConsoleA 的用户输入溢出。清除以前的输入? [复制]
Posted
技术标签:
【中文标题】处理 ReadConsoleA 的用户输入溢出。清除以前的输入? [复制]【英文标题】:Handle user input overflow to ReadConsoleA. Clear previous input? [duplicate] 【发布时间】:2020-07-05 21:07:01 【问题描述】:我想使用 /masm32/lib/kernel32.lib 中的 ReadConsoleA 原型从控制台获取用户输入。
如果用户输入的字符数少于最大字符数,程序运行良好,但如果输入太多,程序会使用多余的字符进行下一次输入。
语言:MASM x86 电脑:Windows 10 x64
驱动程序.asm
.386
.model flat, C
.stack 100h
INCLUDELIB /masm32/lib/kernel32.lib
GetStdHandle PROTO Near32 STDCALL, nStdHandle: DWORD
WriteConsoleA PROTO Near32 STDCALL, handle:DWORD, lpBuffer:PTR BYTE, nNumberOfBytesToWrite:DWORD, lpNumberOfBytesWritten:PTR DWORD, lpReserved:DWORD
ReadConsoleA PROTO Near32 STDCALL, handle:DWORD, lpBuffer:PTR BYTE, nNumberOfCharsToRead:DWORD, lpNumberOfCharsRead:PTR DWORD, lpVoid:DWORD
ExitProcess PROTO STDCALL, dwExitCode:DWORD
StrInput PROTO, addrStr:DWORD, dNumCharsToRead:DWORD
StrPrint PROTO, addrStr:DWORD
StrLen PROTO, addrStr:DWORD
.DATA
strPromptName db "Enter your name: ", 0
strInputName db 10 DUP(0)
strNewLine db 13, 10, 0
.CODE
Main PROC
MOV EAX, 0
; Ask for name, store it, print it, new line
INVOKE StrPrint, ADDR strPromptName
INVOKE StrInput, ADDR strInputName, LENGTHOF strInputName
INVOKE StrPrint, ADDR strInputName
INVOKE StrPrint, ADDR strNewLine
; Ask for name, store it, print it, new line
INVOKE StrPrint, ADDR strPromptName
INVOKE StrInput, ADDR strInputName, LENGTHOF strInputName
INVOKE StrPrint, ADDR strInputName
INVOKE StrPrint, ADDR strNewLine
INVOKE ExitProcess, 0
Main ENDP
StrInput PROC PUBLIC addrStr:DWORD, dNumCharsToRead:DWORD
.DATA
dNumCharsRead dd ? ; Holds the number of chars read from console
.CODE
PUSHAD ; Store all registers, don't trust others' functions
INVOKE GetStdHandle, -10 ; Standard input = -10, handle in EAX
INVOKE ReadConsoleA, EAX, addrStr, dNumCharsToRead, OFFSET dNumCharsRead, 0
MOV EDI, addrStr ; Goto front of string
ADD EDI, dNumCharsRead ; Goto just after last inputted char
SUB EDI, 2 ; Go back 2, to carriage return char
MOV BYTE PTR [EDI], 0 ; Change to 0 for null termination
POPAD ; Restore all registers
RET ; No return value, return to caller
StrInput ENDP
StrPrint PROC PUBLIC addrStr:DWORD
PUSHAD ; Store all registers, don't trust others' functions
INVOKE StrLen, addrStr ; Length in ECX
DEC ECX ; Don't print null terminator
INVOKE GetStdHandle, -11 ; Standard output = -11, handle in EAX
INVOKE WriteConsoleA, EAX, addrStr, ECX, 0, 0
POPAD ; Restore all registers
RET ; No return value, return to caller
StrPrint ENDP
StrLen PROC PUBLIC uses AX EDI addrStr:DWORD
MOV EDI, addrStr ; Store address for scanning
XOR AL, AL ; Store null term for scanning
MOV ECX, -1 ; ECX = len, will decrement over string (neg len)
CLD ; Clear direction flag, search forward
REPNE SCASB ; While char not 0, continue scanning
NEG ECX ; Make length positive
DEC ECX ; Off by one
RET ; Len in ECX, return to caller
StrLen ENDP
END Main
良好的终端输出
Enter your name: abcdef << Allowed user input
abcdef
Enter your name: new << Allowed user input
new
Press any key to continue . . .
用户输入溢出
Enter your name: reallylongname << Allowed user input
reallylo
Enter your name: name << Didn't allow user input
Press any key to continue . . . << Also didn't print
【问题讨论】:
谢谢,我不知道我是怎么错过的,但它确实很好地回答了我的问题! 【参考方案1】:谢谢Michael Petch!我更改了 StrInput 并添加了 FlushInputBuffer PROC,如下所示。
感谢任何关于更简洁代码的提示或建议,但我的问题得到了适当的回答。
StrInput PROC PUBLIC addrStr:DWORD, dNumCharsToRead:DWORD
.DATA
dNumCharsRead dd ? ; Holds the number of chars read from console
.CODE
PUSHAD ; Store all registers, don't trust others' functions
INVOKE GetStdHandle, -10 ; Standard input = -10, handle in EAX
INVOKE ReadConsoleA, EAX, addrStr, dNumCharsToRead, OFFSET dNumCharsRead,
MOV EDI, addrStr ; Goto front of string
ADD EDI, dNumCharsRead ; Goto last inputted char
DEC EDI ; Back one, to last inputted char
CMP BYTE PTR [EDI], 0Ah ; Check if is line feed char
JE done ; If is, done
INVOKE FlushInputBuffer ; Else, clear all input
done:
DEC EDI ; Goto 0Dh char (2nd last char)
MOV BYTE PTR [EDI], 0 ; Set to zero for null termination
POPAD ; Restore all registers
RET ; No return value, return to caller
StrInput ENDP
FlushInputBuffer PROC
.DATA
strDummy db 255 DUP (?) ; Holds input overflow, dummy variable
dNumRead dd ? ; Holds number of chars read
.CODE
PUSHAD ; Store all registers, don't trust others' functions
flush_loop:
INVOKE GetStdHandle, -10 ; Standard input = -10, handle in EAX
INVOKE ReadConsoleA, EAX, ADDR strDummy, 255, ADDR dNumRead, 0
MOV EAX, dNumRead ; Store num read for comparison
CMP EAX, 255 ; If is less than 255, done reading
JE flush_loop ; Else keep reading
POPAD ; Restore all registers
RET ; Return to caller
FlushinputBuffer ENDP
【讨论】:
以上是关于处理 ReadConsoleA 的用户输入溢出。清除以前的输入? [复制]的主要内容,如果未能解决你的问题,请参考以下文章