x86 MASM Assembly - Input Buffer holds old input despite FlushConsoleInputBuffer

余生长醉 提交于 2021-01-28 09:18:04

问题


To practice assembly in MASM, I created a small program that is supposed to do the do the following:

  1. Print "Type a: " to the screen
  2. Read one character from the input buffer, which is then flushed
  3. If the character is "a", then break away from the loop and end the program, if otherwise, repeat from step one

My code goes as follows:

.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

When typing "a", the program will exit, just like it should. However, should I type anything that is not "a" (for example, "s"), instead of inquiring "Type a: " again, only once, it will instead write "Type a: Type a: Type a:" before inquiring for another byte. Writing more than one non-a character will result in even more "Type a: "s.

I suspect this is because ReadConsole is reading the older input and therefore terminating the function early, but shouldn't FlushConsoleInputBuffer have cleaned out the old input?


回答1:


ReadConsole reads all available characters from the console input buffer and stores them in a separate buffer that is not affected by FlushConsoleInputBuffer. You haven't a direct access to that buffer and can't get information about it. So, you have to read it with ReadConsole until the end of the line. By default, the end of the line is marked with the two bytes CR (0x0D) and LF (0x0A). Since you read just one byte, there is left at least the LF in the buffer.

Replace the FlushConsoleInputBuffer with a ReadConsole loop to empty the buffer until LF is read:

.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


来源:https://stackoverflow.com/questions/53684281/x86-masm-assembly-input-buffer-holds-old-input-despite-flushconsoleinputbuffer

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!