windows - ReadConsoleInputA 引发访问冲突
问题描述
我正在尝试学习如何使用 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
现在它抛出“触发断点”。
拆卸:
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
以 nsi 结尾的函数A
表示A
nsi,以 ide 结尾的W
函数W
。微软以这种方式记录它们:
Unicode 和 ANSI 函数 当 Microsoft 将 Unicode 支持引入 Windows 时,它通过提供两组并行的 API 来简化转换,一组用于 ANSI 字符串,另一组用于 Unicode 字符串。例如,有两个函数可以设置窗口标题栏的文本:
SetWindowTextA
接受一个 ANSI 字符串。SetWindowTextW
接受一个 Unicode 字符串。
在代码的第一个版本中
您没有为
buffer
. 你有过:buffer db ?
这为缓冲区分配了一个字节。它应该是:
buffer db 128 DUP(?)
你用
STD_OUTPUT_HANDLE
而不是STD_INPUT_HANDLE
to 的最后一个参数
ReadConsoleInputA
是一个指向 DWORD 的指针,它将返回读取的事件数。更改变量名称bufferSize
可能会使代码更具可读性。从ReadConsoleInputA文档:BOOL WINAPI ReadConsoleInput( _In_ HANDLE hConsoleInput, _Out_ PINPUT_RECORD lpBuffer, _In_ DWORD nLength, _Out_ LPDWORD lpNumberOfEventsRead );
如果您正在阅读您应该使用的键盘,
ReadConsoleA
因为ReadConsoleInputA
将处理键盘和鼠标事件,并且可能会在您的字符串被读取之前过早返回。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
推荐阅读
- amazon-web-services - 在“Amazon Linux AMI”上安装 make 4.2
- gpu - Slurm 超额认购 GPU
- c - 标准 C 库中缓冲区大小的特殊宏是什么?
- ios - 子类化 UISlider 以使用 IBDesignable/IBInspectable 自定义拇指图像?
- javascript - 使用 .map() 在 jquery 中分组
- maven - requireProperty 是否不需要 Maven 强制执行器中的典型 Maven 属性?
- firebase - 带有自定义令牌的 Firebase 存储通配符规则
- mysql - OR 运算符减慢 MySQL 查询速度
- r - 如何对变量设置条件
- android - RecyclerView 在最大高度为 WRAP_CONSTRAINT 时无法正确包装其内容