Сборка MASM x86 - входной буфер содержит старый ввод, несмотря на FlushConsoleInputBuffer - PullRequest
0 голосов
/ 08 декабря 2018

Чтобы попрактиковаться в ассемблере в MASM, я создал небольшую программу, которая должна выполнять следующие действия:

  1. Вывести «Type a:» на экран
  2. Читать однусимвол из входного буфера, который затем сбрасывается
  3. Если символ «а», то оторвитесь от цикла и завершите программу, в противном случае повторите с первого шага

Мой код выглядит следующим образом:

.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» (например, «s»), вместо того, чтобы снова запрашивать «Type a:», только один раз, вместо этого будет написано «Type a: Type a: Type a:» beforeзапрашивая еще один байт.Запись более одного не-символа приведет к еще большему количеству «Type a:».

Я подозреваю, что это потому, что ReadConsole читает старый ввод и поэтому рано завершает функцию, но не долженFlushConsoleInputBuffer очистили старый ввод?

1 Ответ

0 голосов
/ 09 декабря 2018

ReadConsole читает все доступные символы из буфера ввода консоли и сохраняет их в отдельном буфере, на который не влияет 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
...