【问题标题】:Cannot read output of processes launched under cmd.exe pipe无法读取在 cmd.exe 管道下启动的进程的输出
【发布时间】:2017-10-13 14:44:53
【问题描述】:

我希望你的编程进展顺利。

由于我缺乏知识,我有一个问题希望能得到一个简单的答案。

我已经使用了这个问题的代码 - CreateProcess cmd.exe read/write pipes deadlock

一切正常。

问题是当我从需要交互的 cmd.exe shell 运行其他命令时,例如 python 或 powershell,我得到初始输出,然后没有任何内容写入管道。

这就是我的输入/输出的样子:

static PCSTR commands[] = { "powershell\r\n", "dir\r\n", "help\r\n"};
ULONG n = RTL_NUMBER_OF(commands);
PCSTR* psz = commands;
do 
{
    if (MessageBoxW(0,0, L"force close ?", MB_YESNO) == IDYES)
    {
        DisconnectNamedPipe(hFile);
        break;
    }
    if (p = new U_IRP(&obj))
    {
        PCSTR command = *psz++;
        p->Write(command, (ULONG)strlen(command) * sizeof(CHAR));
        p->Release();
    }
} while (--n)

当代码运行时,我得到初始的 powershell.exe 提示符

PS C:\Users>

但在那之后没有任何东西被写入管道。

代码正在使用 CreateProcess(... "cmd.exe" ...) 我尝试将其从 "cmd.exe" 更改为 "cmd.exe /c" 和 "cmd.exe /k",两者都不起作用。

也许您会知道我需要从 CreateProcess() 诱导管道读取/写入输出以解释诸如 python 或 powershell 的内容吗?感谢您的帮助!

【问题讨论】:

  • 至少显示U_IRP的代码和调用CreateProcess的部分。但更好的是,阅读How to Ask 并提供minimal reproducible example
  • 寻求调试帮助的问题必须包括具体问题以及在问题本身中重现该问题所需的最短代码。请阅读如何创建minimal reproducible exampleHow to Ask
  • C != C++。仅使用您正在使用的语言进行标记,除非两者确实相关。
  • 两者实际上都是相关的,如果您点击我发布的完整代码的链接...
  • do {...} 错过了while 语句。

标签: c++ winapi visual-c++ cmd


【解决方案1】:

你执行 cmd.exe 并通过管道向它发送命令到 exec powershell。那么一切都依赖于 powershell 实现

在window7上:

powershell 使用ReadConsoleW 获取输入。所以它不使用你命名的管道 - 不从中读取。并且你可以注意到在你执行 powershell 之后控制台窗口变成了交互式的。所以 powershell 不接受你写入管道的内容(它根本不从它读取),而是从屏幕读取用户输入。但是,在您手动输入一些命令到控制台并按 Enter 后 - 您可以获得管道输出 - powershell 使用(混合)两者 - WriteFileWriteConsoleW 进行输出。部分信息通过WriteFile输出,部分信息通过WriteConsoleW输出

在 windows10 上:

powershell 使用 ReadFile 获取输入。和WriteFile 用于输出。所以它从管道中读取你的命令并将结果写入它。一切都很完美。您还可以注意到在这种情况下控制台窗口处于非活动状态 - 您不能向其中输入任何文本(与 win7 不同)

所以代码绝对没问题。问题仅在于 3-rd 程序如何读取和写入数据。如果它没有从你的管道中读取 - 你在这里无能为力

【讨论】:

  • 很奇怪,因为我知道其他程序可以做到这一点。你是说不可能吗?
  • @TimCollins - 什么是不可能的?如果程序使用ReadConsoleW 而不是ReadFile - 你可以在这里做什么?当然,如果存在一些命令行开关来选择ReadConsoleW vs ReadFile,但我对此表示怀疑
  • 如果应用在连接到控制台时调用ReadConsoleW,请尝试使用创建标志DETACHED_PROCESS 运行它(即不要自动继承或分配控制台)。
  • 如果失败,并且您提前知道这一点,请确保您连接到同一个控制台并通过WriteConsoleInput 写入输入缓冲区。如果它也在写入控制台屏幕缓冲区,在简单的情况下,您可以调用 CreateConsoleScreenBuffer 并将其设置为 9999 行全部初始化为 NUL,暂时将其设置为活动屏幕,等待进程,并通过 @ 读取输出987654336@。但是,如果您需要超过 9999 行的输出,那就没那么简单了。
  • @eryksun - 如何使用 DETACHED_PROCESS 标志运行 powershell?我不是通过 CreateProcess() 调用 powershell,它是从命令行调用的。调用 CreateProcess(cmd.exe, DETACHED_PROCESS) 导致 powershell 完全与管道分离,不再提供任何输出,甚至不提供第一行,并在它自己的窗口中打开,这是我不想要的......所以如果什么你说会工作请在代码中提供上下文。
猜你喜欢
  • 2015-07-03
  • 1970-01-01
  • 2017-01-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-05
  • 1970-01-01
相关资源
最近更新 更多