【问题标题】:Low Level Console Input and Redirection低级控制台输入和重定向
【发布时间】:2011-06-10 08:01:50
【问题描述】:

我正在尝试使用低级读/写控制台功能将命令发送到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 属性除外。

屏幕上没有任何变化,但是我收到了一个从WriteConsoleSTD_INPUT_HANDLEError 6: Invalid Handle。如果我写信给(STD_OUTPUT_HANDLE),我确实会在屏幕上看到我的dir,但当然什么也没有发生。我猜SetConsoleMode() 可能会有所帮助,但我尝试了很多模式组合,没有任何帮助。我还创建了一个快速控制台应用程序,它等待输入 (scanf()) 并回显输入的任何内容,但没有工作。

我也尝试输入scanf() 提示符,然后使用PeekConsoleInput() 查看输入缓冲区,返回0,但INPUT_RECORD 数组为空。

我知道还有另一种解决方法,使用 WriteConsoleInput() 将 INPUT_RECORD 结构化事件直接注入控制台,但这太长了,我必须将每个按键都发送到其中。

我希望问题很清楚。如果您需要任何进一步的信息,请告诉我。感谢您的帮助。

更新 1:

我可以使用带有INPUT_RECORD 结构的WriteConsoleInput() 将按键发送到cmd 进程,但是,AttachConsole 有时会抛出ERROR_GEN_FAILURE #31: A device attached to the system is not functioning.,因此不会发送INPUT_RECORD (Error 6: Invalid Handle )。 Sleep(1000) after CreateProcess() before 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 及其组合,但没有任何结果。但是,如果我从键盘按回车,则会执行自动键入的 dir 命令(与我只是 WriteConsole() 的时候不同),所以我想我走在正确的轨道上。

SSH 不会通过实际的按键发送并获取实际的屏幕缓冲区(如 TAB 和 CTRL+C CTRL+D 工作)?我在追求类似的东西。

更新 2:

我发现注入返回命令的问题。应该是ir[1].Event.KeyEvent.uChar.AsciiChar = '\r';,即\r,而不是\n,超级简单。

似乎没有办法使用WriteConsole() 输入命令,应该通过发送WriteConsoleInput() INPUT_RECORD 或创建管道(这并不总是完美的,但对于大多数直接应用程序来说非常有用)。使用WriteConsoleInput() 的一大优势是您可以发送VK_UPVK_DOWN 来访问控制台历史记录(如果我们在CMD 中)和VK_TAB 用于自动完成,所有CTRL+_ 序列, ESC 和 FUNCTION 键,甚至鼠标点击。

更多信息在这里:http://msdn.microsoft.com/en-us/library/ms687403%28v=vs.85%29.aspx 加上大量的例子:http://controllingtheinter.net/forums/viewtopic.php?f=116&t=366

如果有人有其他好主意,请随时加入。感谢所有对此感兴趣的人。希望这对将来的人有所帮助。

【问题讨论】:

    标签: c windows winapi console


    【解决方案1】:

    现在您正在尝试写入自己的标准输入句柄,而不是 cmd.exe 进程的句柄。你必须做更多的工作来重定向那个输入句柄。它需要一个管道。这是显示样板代码的KB article

    顺便说一句:总是检查 API 函数的返回值。

    【讨论】:

    • 我以为我已附加到新进程的控制台。 AttachConsole() 允许这样做;当我printf() 附加后我实际上正在打印到cmd.exe。我已将我从WriteConsole() 获得的错误代码更新为STD_INPUT_HANDLE
    • 您只共享控制台窗口,仅此而已。是的,错误代码向您显示出了什么问题,您无法写入输入句柄。
    • 我已经阅读了该代码并昨天尝试了它,就像一个魅力,唉,像FTP.exeEDIT.exe这样的衍生程序有自己的缓冲区,没有重定向,这需要低级别读写控制台。本质上,我想通过将所有内容从一个重定向到另一个来克隆一个控制台窗口。
    • 我可以尝试使用管道将输入引导到生成的进程中,就像在 KB 中一样,然后通过附加到它来读取它的控制台输出缓冲区,因为stdout 不包含打印在上面的所有数据屏幕。见stackoverflow.com/questions/2537180/…
    • msdn.microsoft.com/en-us/library/ms687403%28VS.85%29.aspx WriteConsoleInput() 的社区补充显示了如何使用 INPUT_RECORD s 发送密钥以将输出发送到 system("edit") 进程,据我所知,没有问题,也没有管道.
    猜你喜欢
    • 1970-01-01
    • 2011-02-22
    • 1970-01-01
    • 1970-01-01
    • 2013-11-14
    • 1970-01-01
    • 2015-03-10
    • 2015-09-11
    • 2011-05-28
    相关资源
    最近更新 更多