Hello,
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.