Cross-platform redirect of standard input and output of spawned process in native C/C++ (edit with solution)

c, c++, cross-platform, io-redirection, native

Solution

for converting windows `HANDLE`s to C file descriptors use `_open_osfhandle` http://msdn.microsoft.com/en-us/library/bdts1c9x%28VS.71%29.aspx

EDIT: this example once helped me aswell with a similar problem: http://www.halcyon.com/~ast/dload/guicon.htm

Problem

I have a string command I'd like to execute asynchronously while writing to its input and reading its output. Sounds easy, right, the devil is in the cross-platform. I'm targeting both MSVC/Win32 and gcc/Linux and obviously want to write the minimum amount of platform-specific code. My google-fu has failed me, I get too much noise for my queries, so I started with what I know. popen - nice and easy, returns FILE* that is easy to consume everywhere. But here's what MSDN have to say about _popen: If used in a Windows program, the _popen function returns an invalid file pointer that causes the program to stop responding indefinitely. _popen works properly in a console application. To create a Windows application that redirects input and output, see Creating a Child Process with Redirected Input and Output in the Platform SDK. and so popen is out of the question (edit: because I'd like my code to work in GUI application). The Windows way to do it is in my opinion rather ugly and verbose. I could live with platform specific spawn code but I'd want at least the I/O code to be the same. Here, however, I hit a wall between the WinAPI `HANDLE`s and C `FILE*`, and `int` file descriptor. Is there a way to "convert" a `HANDLE` to `FILE*` or `int` fd or vice-versa? (Google failed me once more on this one, all the keywords I tried are way overused) Is there better way to do the whole thing with little platform-specific code? External libraries are not out of the question, however dependency maintenance is a pain, especially so on multiple platforms so I'd like to reduce dependencies. I didn't find such library in boost also. Just for the record, what worked for me in the end. On Windows/MSVC, `CreatePipe()` + `CreateProcess()` as outlined here, using `_open_osfhandle()` followed by `_fdopen()` to get `FILE*` to the process input and output. On Linux/GCC, nothing new here, creating `pipe()`s; `fork()` then `dup2()` the pipes; `exec()`; `fdopen()` on the relevant file descriptors. That way, only the process spawning code is platform dependent (which is ok, as on Windows I'd like to control additional `STARTUPINFO` parameters), writing input and reading output is done through standard `FILE*` and related functions.

Original source