我正在尝试使用低级读/写控制台功能将命令发送到cmd.exe
应用程序的输入。在连接到进程控制台后,使用ReadConsole...()
和WriteConsole()
函数读取文本(抓取)没有问题,但我还没想出如何编写例如"dir"
和让控制台将其解释为已发送命令。
这是我的一些代码:
CreateProcess(NULL, "cmd.exe", NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);
AttachConsole(pi.dwProcessId);
strcpy(buffer, "dir");
WriteConsole(GetStdHandle(STD_INPUT_HANDLE), buffer, strlen(buffer), &charRead, NULL);
过程的 STARTUPINFO
属性都设置为零,当然除了.cb
属性。
屏幕上没有任何变化,但是我从Error 6: Invalid Handle
返回WriteConsole
到STD_INPUT_HANDLE
。如果我写信给(STD_OUTPUT_HANDLE)
,我会在屏幕上写下dir
,但当然没有任何事情发生。我猜SetConsoleMode()
可能会有所帮助,但我尝试了很多模式组合,没有任何帮助。我还创建了一个快速控制台应用程序,它等待输入(scanf()
)并回送任何进入,无法正常工作。
我也尝试输入scanf()
提示,然后使用PeekConsoleInput()
查看输入缓冲区,返回0,但INPUT_RECORD
数组为空。
我知道还有另外一种方法可以使用WriteConsoleInput()
直接将INPUT_RECORD结构化事件注入控制台,但这太长了,我必须将每个按键发送到它。 / p>
我希望问题很清楚。如果您需要任何进一步的信息,请告诉我。谢谢你的帮助。
更新1:
我可以使用带有cmd
结构的WriteConsoleInput()
向INPUT_RECORD
进程发送按键,但AttachConsole
有时会抛出ERROR_GEN_FAILURE #31: A device attached to the system is not functioning.
,因此INPUT_RECORD
未发送Error 6: Invalid Handle
。在Sleep(1000)
解决此问题之前CreateProcess()
之后的AttachConsole()
。字符dir
会自动输入,但我无法弄清楚如何发送RETURN
密钥:
ir[0].EventType = KEY_EVENT;
ir[0].Event.KeyEvent.bKeyDown = TRUE;
ir[0].Event.KeyEvent.dwControlKeyState = 0;
ir[0].Event.KeyEvent.uChar.UnicodeChar = '\n';
ir[0].Event.KeyEvent.wRepeatCount = 1;
ir[0].Event.KeyEvent.wVirtualKeyCode = VK_RETURN;
ir[0].Event.KeyEvent.wVirtualScanCode = MapVirtualKey(VK_RETURN, MAPVK_VK_TO_VSC);
ir[1].EventType = KEY_EVENT;
ir[1].Event.KeyEvent.bKeyDown = FALSE;
ir[1].Event.KeyEvent.dwControlKeyState = 0;
ir[1].Event.KeyEvent.uChar.UnicodeChar = '\n';
ir[1].Event.KeyEvent.wRepeatCount = 1;
ir[1].Event.KeyEvent.wVirtualKeyCode = VK_RETURN;
ir[1].Event.KeyEvent.wVirtualScanCode = MapVirtualKey(VK_RETURN, MAPVK_VK_TO_VSC);
WriteConsoleInput(GetStdHandle(STD_INPUT_HANDLE), ir, 2, &charRead);
WriteConsoleInput
会返回0
,但在控制台中没有任何反应,我尝试将SetConsoleMode()
设置为ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT
及其组合,但没有结果。但是,如果我按下键盘上的Enter键,则会执行自动键入的dir
命令(与我WriteConsole()
的时间不同),所以我想我的方向正确。
SSH是否通过实际的按键发送并获取实际的屏幕缓冲区(如TAB和CTRL + C CTRL + D工作)?我正在追求类似的东西。
更新2:
我发现了注入return命令的问题。应该是ir[1].Event.KeyEvent.uChar.AsciiChar = '\r';
,即\r
而不是\n
,非常简单。
似乎没有办法使用WriteConsole()
来输入命令,应该通过发送WriteConsoleInput()
INPUT_RECORD或创建管道(这并不总是完美的,但对于大多数直截了当而言都很好)应用程序)。使用WriteConsoleInput()
的一个巨大优势是,您可以发送VK_UP
和VK_DOWN
来访问控制台历史记录(如果我们在CMD中)和VK_TAB
用于自动完成,所有CTRL + _序列,ESC和FUNCTION键,甚至MOUSE CLICKS。
此处提供更多信息:http://msdn.microsoft.com/en-us/library/ms687403%28v=vs.85%29.aspx 加上大量的例子:http://controllingtheinter.net/forums/viewtopic.php?f=116&t=366
如果有其他人有其他伟大的想法,请随时插入。感谢所有对此感兴趣的人。希望这可以帮助将来的某个人。
答案 0 :(得分:2)
现在你正在尝试写入自己的stdin句柄,而不是cmd.exe进程的句柄。您将需要做更多的工作来重定向该输入句柄的输入句柄。它需要一根管子。这是显示样板代码的KB article。
Btw:总是检查API函数的返回值。