简体   繁体   English

如何在 Windows 中访问除 stdout、stderr 和 stdin 之外的继承匿名管道 HANDLE?

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

I am trying to receive data from a child process over an anonymous pipe in Windows.我正在尝试通过 Windows 中的匿名管道从子进程接收数据。 I know how to do this using standard I/O streams but these are being used for other purposes.我知道如何使用标准 I/O 流来做到这一点,但这些被用于其他目的。 I also know how to do this in Linux or OSX using fork() , pipe() and execv() .我也知道如何在 Linux 或 OSX 中使用fork()pipe()execv()来做到这一点。

In Windows, you can create a pipe with CreatePipe() and make one end not inheritable with SetHandleInformation() .在Windows中,你可以创建一个带有管CreatePipe()使可继承一端SetHandleInformation() Then for stdout and stderr you can pass STARTUPINFO , with hStdOutput or hStdError set, to CreateProcess() to pass the other end to the child.然后对于 stdout 和 stderr,您可以将STARTUPINFO设置为hStdOutputhStdError传递给CreateProcess()以将另一端传递给孩子。 After the call to CreateProcess() the parent most close it's handle to the child's end of the pipe.在调用CreateProcess() ,父CreateProcess()最接近它的句柄到子进程的管道末端。 This is all explained in detail in Creating a Child Process with Redirected Input and Output on MSDN.在 MSDN 上创建具有重定向输入和输出的子进程中详细解释了这一切。 However, I have not found a way to pass a HANDLE , other than via stderr, stdout or stdin, to the child.但是,除了通过 stderr、stdout 或 stdin 之外,我还没有找到将HANDLE传递给孩子的方法。

I've tried converting the HANDLE to a string with something like this:我试过将HANDLE转换为这样的字符串:

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

And then passing it as a command line argument and converting it back to a HANDLE , which is just a void * in the child process.然后将其作为命令行参数传递并将其转换回HANDLE ,这只是子进程中的void * Although the child process apparently inherits the pipe HANDLE the actual value of the HANDLE must be different than in the parent because passing it this way fails to work.虽然子进程显然继承了管HANDLE的实际价值HANDLE ,因为它传递这样没有工作必须比父不同。

I know I can use a named pipe to do this but it seems it should be possible to do this with anonymous pipes.我知道我可以使用命名管道来做到这一点,但似乎应该可以使用匿名管道来做到这一点。

So how can I pass a pipe HANDLE to a child process in Windows?那么如何将管道HANDLE传递给 Windows 中的子进程?

Update1: Sample code in this MSDN article seems to indicate that, at least with socket handles, you can pass them as a string to the child.更新 1:此 MSDN 文章中的示例代码似乎表明,至少使用套接字句柄,您可以将它们作为字符串传递给子级。

Update2: Turns out I made a mistake.更新2:原来我犯了一个错误。 See my answer below.看我下面的回答。

Turns out you can pass a HANDLE to a child process as a command line argument by converting it to string and then, in the child process, back to a HANDLE (which is just a void * ).事实证明,您可以HANDLE作为命令行参数传递给子进程,方法是将其转换为字符串,然后在子进程中返回到HANDLE (它只是一个void * )。 Sample code using a HANDLE to a socket can be found here .可以在此处找到HANDLE用于套接字的示例代码。

To make this work you need to make sure you follow Creating a Child Process with Redirected Input and Output closely.要完成这项工作,您需要确保密切遵循创建具有重定向输入和输出的子进程 It's important that you close the child process's end of the pipe after calling CreateProcess() and get all the inheritance settings right.在调用CreateProcess()并正确设置所有继承设置后,关闭管道的子进程端非常重要。

Note, I tried passing the HANDLE as a string on the command line before but I was doing it wrong.请注意,我之前尝试在命令行上将HANDLE作为字符串传递,但我做错了。 My mistake was in passing the HANDLE as an int to boost::iostreams::file_descriptor() which made it treat it as a file descriptor instead of a Windows HANDLE .我的错误是将HANDLE作为int传递给boost::iostreams::file_descriptor() ,这使其将其视为文件描述符而不是 Windows HANDLE

Why not use the method shown here ?为什么不使用这里显示的方法?

Call the GetStdHandle function to get the current standard output handle;调用GetStdHandle函数获取当前标准输出句柄; save this handle so you can restore the original standard output handle after the child process has been created.保存此句柄,以便在创建子进程后恢复原始标准输出句柄。

Call the SetStdHandle function to set the standard output handle to the write handle to the pipe.调用 SetStdHandle 函数将标准输出句柄设置为管道的写句柄。 Now the parent process can create the child process.现在父进程可以创建子进程。

Call the CloseHandle function to close the write handle to the pipe.调用 CloseHandle 函数关闭管道的写句柄。 After the child process inherits the write handle, the parent process no longer needs its copy.子进程继承了写句柄后,父进程就不再需要它的副本了。

Call SetStdHandle to restore the original standard output handle.调用 SetStdHandle 恢复原始标准输出句柄。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM