ReadConsoleInputA 引发访问冲突
ReadConsoleInputA throws an Access Violation
我正在尝试学习如何使用 windows api(而不是仅使用 C 调用、irvine32 或 masm32)并且 运行 遇到 ReadConsoleInputA 问题(WriteConsoleA 有效很好)。
此外,我不明白为什么在函数的 PROC 原型中,大多数示例在 ReadConsoleInput/WriteConsole 的末尾附加一个 A 或 W,您能解释一下为什么吗?
.data
consoleOutHandle dd ?
consoleInHandle dd ?
bufferlen dd ?
buffer db ?
bufferSize DWORD ?
message db "Enter a number:", 0
lmessage equ $-message
.code
main PROC
invoke GetStdHandle, STD_OUTPUT_HANDLE
mov consoleOutHandle, eax
invoke ReadConsoleInputA, consoleOutHandle, offset buffer, 128, bufferSize
main endp
end main
它抛出:访问冲突写入位置 0x00000004。
根据 Michael Petch 的建议,我现在有了这段代码:
.data
consoleOutHandle dd ?
consoleInHandle dd ?
byteswritten dd ?
bufferlen dd ?
buffer db 128 DUP(?)
bufferSize dd ?
message db "Enter a number:", 0
lmessage equ $-message
.code
main PROC
invoke GetStdHandle, STD_INPUT_HANDLE
mov consoleInHandle, eax
invoke GetStdHandle, STD_OUTPUT_HANDLE
mov consoleOutHandle, eax
mov eax, lmessage
invoke WriteConsoleA, consoleOutHandle, offset message, eax, bytesWritten, 0
invoke ReadConsoleInputA, consoleInHandle, offset buffer, 128, offset bufferSize
main endp
end main
现在它抛出 "triggered a breakpoint"。
反汇编:
invoke ReadConsoleInputA, consoleInHandle, offset buffer, 128, offset bufferSize
00E71066 push offset bufferSize (0E74090h)
00E7106B push 80h
00E71070 push offset buffer (0E74010h)
00E71075 push dword ptr [consoleInHandle (0E74004h)]
00E7107B call _ReadConsoleInputA@16 (0E7100Ah)
--- No source file -------------------------------------------------------------
00E71080 int 3 **---> Breakpoint here**
00E71081 int 3
您询问了 WinAPI 函数末尾的 A
和 W
后缀的用途。以A
结尾的函数表示A
nsi,以W
结尾的函数是W
ide。 Microsoft 以这种方式记录它们:
Unicode and ANSI Functions
When Microsoft introduced Unicode support to Windows, it eased the transition by providing two parallel sets of APIs, one for ANSI strings and the other for Unicode strings. For example, there are two functions to set the text of a window's title bar:
SetWindowTextA
takes an ANSI string.
SetWindowTextW
takes a Unicode string.
第一版代码
您没有分配 buffer
所需的 space。你有:
buffer db ?
这为缓冲区分配了一个字节。应该是:
buffer db 128 DUP(?)
您使用了 STD_OUTPUT_HANDLE
而不是 STD_INPUT_HANDLE
ReadConsoleInputA
的最后一个参数是一个指向 DWORD 的指针,它将 return 读取的事件数。更改变量名称 bufferSize
可能会使代码更具可读性。来自 ReadConsoleInputA 文档:
BOOL WINAPI ReadConsoleInput(
_In_ HANDLE hConsoleInput,
_Out_ PINPUT_RECORD lpBuffer,
_In_ DWORD nLength,
_Out_ LPDWORD lpNumberOfEventsRead
);
如果您只阅读键盘,您应该使用 ReadConsoleA
,因为 ReadConsoleInputA
将处理键盘和鼠标事件,并且可能会在您的字符串出现之前过早地 return读。 ReadConsoleA
需要一个额外的参数,你可以将它设置为 NULL:
BOOL WINAPI ReadConsole(
_In_ HANDLE hConsoleInput,
_Out_ LPVOID lpBuffer,
_In_ DWORD nNumberOfCharsToRead,
_Out_ LPDWORD lpNumberOfCharsRead,
_In_opt_ LPVOID pInputControl
);
要退出您需要调用的程序 ExitProcess
.
第二版代码
您的代码:
invoke WriteConsoleA, consoleOutHandle, offset message, eax, bytesWritten, 0
bytesWritten
需要是一个指针,因为它是一个输出参数。来自 WriteConsoleA 文档:
BOOL WINAPI WriteConsole(
_In_ HANDLE hConsoleOutput,
_In_ const VOID *lpBuffer,
_In_ DWORD nNumberOfCharsToWrite,
_Out_ LPDWORD lpNumberOfCharsWritten,
_Reserved_ LPVOID lpReserved
);
根据您的第二个代码示例,使用 ReadConsoleA
而不是 ReadConsoleInputA
的代码版本可能如下所示:
.data
consoleOutHandle dd ?
consoleInHandle dd ?
bytesWritten dd ?
bufferlen dd ?
buffer db 128 DUP(?)
numEvents dd ?
message db "Enter a number:", 0
lmessage equ $-message
.code
main PROC
invoke GetStdHandle, STD_INPUT_HANDLE
mov consoleInHandle, eax
invoke GetStdHandle, STD_OUTPUT_HANDLE
mov consoleOutHandle, eax
mov eax, lmessage
invoke WriteConsoleA, consoleOutHandle, offset message, eax, offset bytesWritten, 0
invoke ReadConsoleA, consoleInHandle, offset buffer, 128, offset numEvents, 0
invoke ExitProcess, 0
main endp
end main
可以使用 MASM 的 sizeof
运算符稍微清理此代码。代码可以写成:
.data
consoleOutHandle dd ?
consoleInHandle dd ?
buffer db 128 DUP(?)
bytesWritten dd ?
numEvents dd ?
message db "Enter a number:", 0
.code
main PROC
invoke GetStdHandle, STD_INPUT_HANDLE
mov consoleInHandle, eax
invoke GetStdHandle, STD_OUTPUT_HANDLE
mov consoleOutHandle, eax
invoke WriteConsoleA, consoleOutHandle, offset message, sizeof message, offset bytesWritten, 0
invoke ReadConsoleA, consoleInHandle, offset buffer, sizeof buffer, offset numEvents, 0
invoke ExitProcess, 0
main endp
end main
我正在尝试学习如何使用 windows api(而不是仅使用 C 调用、irvine32 或 masm32)并且 运行 遇到 ReadConsoleInputA 问题(WriteConsoleA 有效很好)。
此外,我不明白为什么在函数的 PROC 原型中,大多数示例在 ReadConsoleInput/WriteConsole 的末尾附加一个 A 或 W,您能解释一下为什么吗?
.data
consoleOutHandle dd ?
consoleInHandle dd ?
bufferlen dd ?
buffer db ?
bufferSize DWORD ?
message db "Enter a number:", 0
lmessage equ $-message
.code
main PROC
invoke GetStdHandle, STD_OUTPUT_HANDLE
mov consoleOutHandle, eax
invoke ReadConsoleInputA, consoleOutHandle, offset buffer, 128, bufferSize
main endp
end main
它抛出:访问冲突写入位置 0x00000004。
根据 Michael Petch 的建议,我现在有了这段代码:
.data
consoleOutHandle dd ?
consoleInHandle dd ?
byteswritten dd ?
bufferlen dd ?
buffer db 128 DUP(?)
bufferSize dd ?
message db "Enter a number:", 0
lmessage equ $-message
.code
main PROC
invoke GetStdHandle, STD_INPUT_HANDLE
mov consoleInHandle, eax
invoke GetStdHandle, STD_OUTPUT_HANDLE
mov consoleOutHandle, eax
mov eax, lmessage
invoke WriteConsoleA, consoleOutHandle, offset message, eax, bytesWritten, 0
invoke ReadConsoleInputA, consoleInHandle, offset buffer, 128, offset bufferSize
main endp
end main
现在它抛出 "triggered a breakpoint"。
反汇编:
invoke ReadConsoleInputA, consoleInHandle, offset buffer, 128, offset bufferSize
00E71066 push offset bufferSize (0E74090h)
00E7106B push 80h
00E71070 push offset buffer (0E74010h)
00E71075 push dword ptr [consoleInHandle (0E74004h)]
00E7107B call _ReadConsoleInputA@16 (0E7100Ah)
--- No source file -------------------------------------------------------------
00E71080 int 3 **---> Breakpoint here**
00E71081 int 3
您询问了 WinAPI 函数末尾的 A
和 W
后缀的用途。以A
结尾的函数表示A
nsi,以W
结尾的函数是W
ide。 Microsoft 以这种方式记录它们:
Unicode and ANSI Functions When Microsoft introduced Unicode support to Windows, it eased the transition by providing two parallel sets of APIs, one for ANSI strings and the other for Unicode strings. For example, there are two functions to set the text of a window's title bar:
SetWindowTextA
takes an ANSI string.SetWindowTextW
takes a Unicode string.
第一版代码
您没有分配
buffer
所需的 space。你有:buffer db ?
这为缓冲区分配了一个字节。应该是:
buffer db 128 DUP(?)
您使用了
STD_OUTPUT_HANDLE
而不是STD_INPUT_HANDLE
ReadConsoleInputA
的最后一个参数是一个指向 DWORD 的指针,它将 return 读取的事件数。更改变量名称bufferSize
可能会使代码更具可读性。来自 ReadConsoleInputA 文档:BOOL WINAPI ReadConsoleInput( _In_ HANDLE hConsoleInput, _Out_ PINPUT_RECORD lpBuffer, _In_ DWORD nLength, _Out_ LPDWORD lpNumberOfEventsRead );
如果您只阅读键盘,您应该使用
ReadConsoleA
,因为ReadConsoleInputA
将处理键盘和鼠标事件,并且可能会在您的字符串出现之前过早地 return读。ReadConsoleA
需要一个额外的参数,你可以将它设置为 NULL:BOOL WINAPI ReadConsole( _In_ HANDLE hConsoleInput, _Out_ LPVOID lpBuffer, _In_ DWORD nNumberOfCharsToRead, _Out_ LPDWORD lpNumberOfCharsRead, _In_opt_ LPVOID pInputControl );
要退出您需要调用的程序
ExitProcess
.
第二版代码
您的代码:
invoke WriteConsoleA, consoleOutHandle, offset message, eax, bytesWritten, 0
bytesWritten
需要是一个指针,因为它是一个输出参数。来自 WriteConsoleA 文档:BOOL WINAPI WriteConsole( _In_ HANDLE hConsoleOutput, _In_ const VOID *lpBuffer, _In_ DWORD nNumberOfCharsToWrite, _Out_ LPDWORD lpNumberOfCharsWritten, _Reserved_ LPVOID lpReserved );
根据您的第二个代码示例,使用 ReadConsoleA
而不是 ReadConsoleInputA
的代码版本可能如下所示:
.data
consoleOutHandle dd ?
consoleInHandle dd ?
bytesWritten dd ?
bufferlen dd ?
buffer db 128 DUP(?)
numEvents dd ?
message db "Enter a number:", 0
lmessage equ $-message
.code
main PROC
invoke GetStdHandle, STD_INPUT_HANDLE
mov consoleInHandle, eax
invoke GetStdHandle, STD_OUTPUT_HANDLE
mov consoleOutHandle, eax
mov eax, lmessage
invoke WriteConsoleA, consoleOutHandle, offset message, eax, offset bytesWritten, 0
invoke ReadConsoleA, consoleInHandle, offset buffer, 128, offset numEvents, 0
invoke ExitProcess, 0
main endp
end main
可以使用 MASM 的 sizeof
运算符稍微清理此代码。代码可以写成:
.data
consoleOutHandle dd ?
consoleInHandle dd ?
buffer db 128 DUP(?)
bytesWritten dd ?
numEvents dd ?
message db "Enter a number:", 0
.code
main PROC
invoke GetStdHandle, STD_INPUT_HANDLE
mov consoleInHandle, eax
invoke GetStdHandle, STD_OUTPUT_HANDLE
mov consoleOutHandle, eax
invoke WriteConsoleA, consoleOutHandle, offset message, sizeof message, offset bytesWritten, 0
invoke ReadConsoleA, consoleInHandle, offset buffer, sizeof buffer, offset numEvents, 0
invoke ExitProcess, 0
main endp
end main