views:

355

answers:

2

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 HANDLEs 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.

+1  A: 

Give libexecstream a whirl. It's cross platform, and allows you to trap the input, output and error streams of a process asynchronously as C++ style streams.

I've used it on Linux, Darwin and Windows and it seems to work. It's also pretty lightweight so integrates into projects with little pain, and has a pretty open BSD licence. I don't think there's any way around using a library (other than writing your own variations for each platform).

Adam Bowen
+1  A: 

for converting windows HANDLEs 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

smerlin