为远程进程的子进程捕获标准输出

Posted

技术标签:

【中文标题】为远程进程的子进程捕获标准输出【英文标题】:Capture stdout for a remote process' child process 【发布时间】:2018-03-06 07:13:43 【问题描述】:

目前正在处理我需要为外部进程的子进程捕获标准输出/标准错误的情况。对于这种情况,我需要一个命名管道吗?

我目前尝试了以下方法:

SECURITY_ATTRIBUTES saAttr;
HANDLE hStdOutRd = NULL;
HANDLE hStdOutWr = NULL;
HANDLE hDupStdOutWr = NULL;

saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); 
saAttr.bInheritHandle = TRUE; 
saAttr.lpSecurityDescriptor = NULL; 

CreatePipe(&hStdOutRd, &hStdOutWr, &saAttr, 0) ) 
SetHandleInformation(hStdOutRd, HANDLE_FLAG_INHERIT, 0) )

HANDLE hExProc = OpenProcess(PROCESS_DUP_HANDLE, false, EXTERNAL_PROC);
DuplicateHandle(GetCurrentProcess(), 
                hStdOutWr, 
                hExProc,
                &hDupStdOutWr, 
                0,
                TRUE,
                DUPLICATE_SAME_ACCESS);

// Child process for EXTERNAL_PROC executes and should inherit the duplicated handle
// Read from hStdOutRd

从管道读取时,它要么挂起,要么不返回任何内容。我假设这是一个匿名管道,只适用于父子进程而不是外部进程。我宁愿不使用命名管道,是否可以 DuplicateHandle() 管道从远程进程返回到我的进程,然后访问数据?如果是这样,那会是什么样子?

【问题讨论】:

这是特定于操作系统的。如果不提及操作系统,您的问题就不清楚了。也许你应该考虑像POCO 或Qt这样的框架 @BasileStarynkevitch 有问题的代码使用的是 Win32 API 函数,因此很明显它只能在 Windows 上运行。 命名管道与未命名或所谓的匿名管道相同。在你需要使用异步 io 来实现永不挂起。而CreatePipe 对这个目标不利。更好地使用CreateNamedPipe +CreateFileDuplicateHandle - 以及如何通知孩子重复值? 在 win7 之前 - CreatePipe 只需创建 2 个随机命名的命名管道。从 win7 开始 - 可能创建完全未命名的对。说CreatePipe 总是创建同步管道。但我们可以自己创建它,直接作为异步。可以只创建一个可继承的和一个 - 不。可以创建双工。真的 CreatePipe 非常受限的 api。 这非常相关 - 需要清楚地理解 - 不存在 2 种不同的管道类型(命名与未命名或随机命名) - 仅存在管道和所有。仅存在单个记录的 api 调用 CreatePipe,它创建未命名的管道对 - 具有简单的接口但限制自定义(设置管道属性)。全部。操作是一样的。并可能直接(仅通过本机调用)创建具有任何所需属性的未命名对 【参考方案1】:

不,您不需要使用命名管道,匿名管道就可以了。 MSDN 提供了从子进程捕获输出的完整示例:

Creating a Child Process with Redirected Input and Output

【讨论】:

命名管道和匿名管道——绝对是同一个对象。和我认为的 msdn 示例非常糟糕。 OP 询问如何从他未启动的进程(通过OpenProcess() 获得的句柄)中捕获输出,我认为这不是(容易)可行的。 @zett42 我没有注意到OpenProcess() 部分。在这种情况下,您无法为自己未启动的进程重定向输出。 如果我自己使用 CreateProcess() 和 STARTUPINFOEX + PROC_THREAD_ATTRIBUTE_PARENT_PROCESS 启动进程会怎样?将句柄复制到我指定的远程父级并设置 bInheritHandle 是否可以让我访问孩子的标准输出? @NotWarrenBuffet:无论您指定哪个进程作为子进程的父进程,当您直接调用CreateProcess() 时,您都可以通过STARTUPINFO/EX 结构为新子进程提供自己的STD(IN|OUT|ERR) 管道,就像我在回答中链接到的文章所展示的那样。你不需要复制任何东西。在dwFlags字段中启用STARTF_USESTDHANDLES标志,然后将管道的读取端分配给hStdOuthStdError字段。

以上是关于为远程进程的子进程捕获标准输出的主要内容,如果未能解决你的问题,请参考以下文章

Python 子进程丢失了程序标准输出的 10%

使用 libuv 捕获子进程的标准输出

从子进程中实时捕获标准输出

检查 python 中正在运行的子进程的标准输出

从提升的子进程获取错误和标准输出

使用 Wmi win32_Process 执行远程进程 - 获取进程的标准输出