如何在 Windows 中访问继承的匿名管道句柄,而不是 stdout、stderr 和 stdin?

Posted

技术标签:

【中文标题】如何在 Windows 中访问继承的匿名管道句柄,而不是 stdout、stderr 和 stdin?【英文标题】:How to access an inherited anonymous pipe HANDLE, other than stdout, stderr & stdin, in Windows? 【发布时间】:2015-09-17 23:15:44 【问题描述】:

我正在尝试通过 Windows 中的匿名管道从子进程接收数据。我知道如何使用标准 I/O 流来做到这一点,但这些正在用于其他目的。我也知道如何在 Linux 或 OSX 中使用 fork()pipe()execv() 来做到这一点。

在 Windows 中,您可以使用CreatePipe() 创建一个管道,并使用SetHandleInformation() 使一端可继承。然后对于标准输出和标准错误,您可以将STARTUPINFO(设置了hStdOutputhStdError)传递给CreateProcess(),以将另一端传递给孩子。在调用CreateProcess() 之后,父级最接近它的句柄到管道的子端。这在 MSDN 上的Creating a Child Process with Redirected Input and Output 中有详细解释。但是,除了通过 stderr、stdout 或 stdin 之外,我还没有找到将HANDLE 传递给孩子的方法。

我尝试将HANDLE 转换为类似这样的字符串:

std::ostringstream str;
str << hex << "0x" << handle;
std::string handleArg = str.str();

然后将其作为命令行参数传递,并将其转换回HANDLE,这只是子进程中的void *。虽然子进程显然继承了管道 HANDLE,但 HANDLE 的实际值必须与父进程中的不同,因为以这种方式传递它不起作用。

我知道我可以使用命名管道来执行此操作,但似乎应该可以使用匿名管道来执行此操作。

那么如何将管道 HANDLE 传递给 Windows 中的子进程?

更新 1:this MSDN article 中的示例代码似乎表明,至少对于套接字句柄,您可以将它们作为字符串传递给孩子。

Update2:原来我犯了一个错误。请参阅下面的答案。

【问题讨论】:

【参考方案1】:

原来您可以HANDLE 作为命令行参数传递给子进程,方法是将其转换为字符串,然后在子进程中返回HANDLE(即只是一个void *)。使用HANDLE 到套接字的示例代码可以是found here。

要完成这项工作,您需要确保密切关注Creating a Child Process with Redirected Input and Output。请务必在调用 CreateProcess() 后关闭子进程的管道末端并正确设置所有继承设置。

注意,我之前尝试在命令行上将HANDLE 作为字符串传递,但我做错了。我的错误是将HANDLE 作为int 传递给boost::iostreams::file_descriptor(),这使其将其视为文件描述符而不是Windows HANDLE

【讨论】:

【参考方案2】:

为什么不使用here所示的方法?

调用GetStdHandle函数获取当前标准输出 处理;保存此句柄,以便您可以恢复原始标准 子进程创建后的输出句柄。

调用 SetStdHandle 函数将标准输出句柄设置为 管道的写句柄。现在父进程可以创建 子进程。

调用 CloseHandle 函数关闭管道的写句柄。 子进程继承写句柄后,父进程 不再需要它的副本。

调用 SetStdHandle 恢复原来的标准输出句柄。

【讨论】:

以上是关于如何在 Windows 中访问继承的匿名管道句柄,而不是 stdout、stderr 和 stdin?的主要内容,如果未能解决你的问题,请参考以下文章

Win32:匿名管道上的事务

共享内存——如何在本地没有句柄的两个地方互传数据

Unix管道机制

在 Windows 中创建匿名管道

Windows DuplicateHandle 命名管道句柄奇怪错误 183“文件已存在”

关闭其它进程占用的文件句柄