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

How to access an inherited anonymous pipe HANDLE, other than stdout, stderr & stdin, in Windows?

本文关键字:stdout stderr stdin HANDLE 管道 Windows 访问 继承      更新时间:2023-10-16

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

在Windows中,您可以使用CreatePipe()创建一个管道,并使一端可由SetHandleInformation()继承。然后,对于stdout和stderr,可以将设置了hStdOutputhStdErrorSTARTUPINFO传递给CreateProcess(),以将另一端传递给子进程。在调用CreateProcess()之后,父进程的句柄最接近子进程的管道末端。在MSDN上创建具有重定向输入和输出的子进程中详细解释了这一点。然而,我还没有找到一种方法来传递HANDLE,除了通过标准错误,标准输出或标准输入,给孩子。

我试过把HANDLE转换成一个字符串,像这样:

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

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

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

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

Update1: MSDN文章中的示例代码似乎表明,至少对于套接字句柄,您可以将它们作为字符串传递给子进程。

Update2:原来我犯了一个错误。

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

要使此工作,您需要确保您严格遵循创建具有重定向输入和输出的子进程。在调用CreateProcess()之后关闭子进程的管道末端并正确设置所有继承设置是很重要的。

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

为什么不使用这里所示的方法呢?

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

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

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

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