x86 MASM组装-尽管FlushConsoleInputBuffer,输入缓冲区仍保留旧输入

时间:2018-12-08 16:00:14

标签: windows winapi assembly x86 masm32

要在MASM中练习汇编,我创建了一个小程序,该程序应该执行以下操作:

  1. 在屏幕上打印“键入a:”
  2. 从输入缓冲区读取一个字符,然后将其刷新
  3. 如果字符为“ a”,则退出循环并结束程序,否则,从第一步开始重复

我的代码如下:

.386


.model flat,stdcall


include \masm32\include\kernel32.inc ; Defines Symbols To Be Used for the kernel32 library


includelib \masm32\lib\kernel32.lib



STD_OUTPUT_HANDLE equ -11
STD_INPUT_HANDLE equ -10

.code



entryPt proc
    local inHandle:DWORD
    local outHandle:DWORD
    local noOfCharsWritten:DWORD
    ; Get Standard Output Handle
    push STD_OUTPUT_HANDLE
    call GetStdHandle
    mov outHandle,eax

    ; Get Standard Input Handle
    push STD_INPUT_HANDLE
    call GetStdHandle
    mov inHandle,eax

    .while (eax == eax) ; while (true)

        ; Print "Type a: "
        push 0
        lea eax,noOfCharsWritten
        push eax
        push sizeof txt
        push offset txt
        push outHandle
        call WriteConsoleA

        ; Poll for a byte
        call getChar

        .if (al == "a") ; if the byte was "a"...
            .break ; ...then end the loop
        .endif

    .endw

    ; Leave with exit code 0
    push 0
    call ExitProcess
entryPt endp

getChar proc
    local inHandle:DWORD
    local noOfCharsRead:DWORD
    local resBt:BYTE
    ; Get the Standard Input Handle
    push STD_INPUT_HANDLE
    call GetStdHandle
    mov inHandle,eax
    ; Read one char from the console, put the result in resBt and the number of chars read in noOfCharsRead
    push 0
    lea eax,noOfCharsRead
    push eax
    push 1
    lea eax,resBt
    push eax
    push inHandle
    call ReadConsoleA

    ; Flush Console Input Buffer
    push inHandle
    call FlushConsoleInputBuffer

    ; Return the result in the accumulator
    movzx eax,resBt
    ret
getChar endp
.data

txt db "Type a: "

end entryPt

输入“ a”时,程序将退出,就像应该的那样。但是,我应该键入不是“ a”的任何内容(例如“ s”),而不是再次询问“ Type a:”,而只询问一次,而是在之前输入“ Type a:Type a:Type a:”查询另一个字节。写入多个非字符将导致更多“ Type a:” s。

我怀疑这是因为ReadConsole正在读取较旧的输入并因此提早终止了该功能,但是FlushConsoleInputBuffer是否不应该清除旧的输入?

1 个答案:

答案 0 :(得分:1)

ReadConsole从控制台输入缓冲区读取 all 个可用字符,并将它们存储在不受FlushConsoleInputBuffer影响的单独缓冲区中。您无法直接访问该缓冲区,也无法获取有关该缓冲区的信息。因此,您必须使用ReadConsole进行阅读,直到行尾为止。默认情况下,该行的末尾标记有两个字节CR(0x0D)和LF(0x0A)。由于您只读取一个字节,因此缓冲区中至少留有LF。

FlushConsoleInputBuffer循环替换ReadConsole,以清空缓冲区,直到读取LF:

.model flat,stdcall

include \masm32\include\kernel32.inc ; Defines Symbols To Be Used for the kernel32 library
includelib \masm32\lib\kernel32.lib

STD_OUTPUT_HANDLE equ -11
STD_INPUT_HANDLE equ -10

.code

entryPt proc
    local inHandle:DWORD
    local outHandle:DWORD
    local noOfCharsWritten:DWORD
    ; Get Standard Output Handle
    push STD_OUTPUT_HANDLE
    call GetStdHandle
    mov outHandle,eax

    ; Get Standard Input Handle
    push STD_INPUT_HANDLE
    call GetStdHandle
    mov inHandle,eax

    .while (eax == eax) ; while (true)

        ; Print "Type a: "
        push 0
        lea eax,noOfCharsWritten
        push eax
        push sizeof txt
        push offset txt
        push outHandle
        call WriteConsoleA

        ; Poll for a byte
        call getChar

        .if (al == "a") ; if the byte was "a"...
            .break ; ...then end the loop
        .endif

    .endw

    ; Leave with exit code 0
    push 0
    call ExitProcess
entryPt endp

getChar proc
    local inHandle:DWORD
    local noOfCharsRead:DWORD
    local resBt:BYTE, dummy:BYTE

    ; Get the Standard Input Handle
    push STD_INPUT_HANDLE
    call GetStdHandle
    mov inHandle,eax

    ; Read one char from the console, put the result in resBt and the number of chars read in noOfCharsRead
    push 0
    lea eax,noOfCharsRead
    push eax
    push 1
    lea eax,resBt
    push eax
    push inHandle
    call ReadConsoleA

    ; Flush
    mov al, resBt
    mov dummy, al
    FlushLoop:
    cmp dummy, 0Ah
    je EndOfFlush
    invoke ReadConsoleA, inHandle, ADDR dummy, 1, ADDR noOfCharsRead, 0
    jmp FlushLoop
    EndOfFlush:

    ; Return the result in the accumulator

    movzx eax,resBt
    ret
getChar endp
.data

txt db "Type a: "

end entryPt