处理 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 的用户输入溢出。清除以前的输入? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

CS1.5在控制台输入啥,能战绩清零?

是否可以清除窗体文本框中的内存?

当我开始输入 textField 它溢出颤动

STM32F0 DMA“输入溢出”

高标清双向变换 万能 视频格式转换器

异常处理