【问题标题】:Process STDOUT Redirection hanging with GUI apps处理与 GUI 应用程序挂起的 STDOUT 重定向
【发布时间】:2014-12-21 03:28:10
【问题描述】:

我正在尝试创建一个模仿 cmd.exe 的应用程序。

我的应用程序应该能够启动新进程,打印它们的输出,并在子进程完成后完成。

这适用于控制台应用程序,但我在使用 GUI 应用程序时遇到问题。

我的逻辑如下:

  1. 在父进程中,创建一个 STDOUT 重定向管道(将由子进程使用)。 该管道将​​被继承给子级,并将用作 STDOUT。 这是通过使用 CreateProcess + StartupInformation 结构来实现的(更多信息here)。

  2. 创建子进程后,我使用 ReadFile 从管道中读取。 一旦 ReadFile 失败(或读取 0 个字节),我知道会话已经结束。

我对 GUI 应用程序的问题是它们挂在 ReadFile 上并且永远不会结束,只有在进程已终止时。

可以说这是一种正常的行为(我同意),但这不是 cmd.exe 的工作方式。

可以打开 cmd.exe 并启动 calc.exe,你会发现 cmd 并没有挂起,而是直接准备好进行新的输入。

就像 cmd.exe “知道”这是一个 GUI 应用程序,他们不需要等待。

我的问题是如何模仿 cmd.exe,防止在 GUI 应用程序上挂起的解决方案是什么?

非常感谢,

迈克尔。

【问题讨论】:

  • 非常感谢您的评论.. :(
  • 判断进程是否退出,检查进程句柄是否有信号。如果要轮询,可以使用超时为零的 WaitForSingleObject。将输出重定向到管道将改变许多命令行应用程序的行为,即它们将开始缓冲输出,这通常是不可取的,而且往往是致命的。默认情况下,输出将转到控制台,这就是 cmd.exe 所做的。
  • 我不确定 cmd.exe 如何确定子进程是控制台还是 GUI 进程。一种解决方案是自己读取可执行文件头,格式已记录在案。您也许可以尝试启动该进程,然后使用 GetConsoleProcessList 来查看该进程是否已附加到控制台。 (为了避免竞争情况,我想你应该启动暂停的进程,只有在检查控制台进程列表后才能恢复它。)

标签: windows user-interface process io-redirection


【解决方案1】:

感谢您的回复,但他们没有解决问题。

我自己找到了答案我的逆向cmd.exe和它的尴尬简单。

cmd.exe不会通过改变子进程STD句柄来重定向IO,在程序集中可以看得很清楚。

那么子进程输出是如何打印到屏幕上的呢?

似乎如果一个控制台应用程序尝试在另一个控制台应用程序上调用 CreateProcess,则不会打开新的控制台。面对新进程将“活”在父进程的控制台中。如果希望打开 2 个控制台,则应指定 CREATE_NEW_CONSOLE 标志。

那么 cmd.exe 是如何工作的呢?

它只是调用 CreateProcess,没有花哨的管道或类似的东西。

如果子进程是一个控制台应用程序,它的输出将被打印到 cmd.exe 控制台(因为只有一个控制台存在)。

如果子进程不是控制台应用程序,它将被创建并且 cmd.exe 将准备就绪。

下面的代码就是你所需要的:

STARTUPINFO si;
PROCESS_INFORMATION pi;

memset(&pi, 0, sizeof(pi));
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
CreateProcessA(NULL, "ipconfig", NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);

【讨论】:

  • 这就是我说的:“输出默认会到控制台,这就是cmd.exe的作用。”不过,您仍然需要确定子项是否是控制台应用程序,因为如果它控制台应用程序,您需要等待它退出。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多