问题
To practice assembly in MASM, I created a small program that is supposed to do the do the following:
- Print "Type a: " to the screen
- Read one character from the input buffer, which is then flushed
- 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