2010-01-09 11 views
8

Tengo un comando de cadena que me gustaría ejecutar de forma asíncrona mientras escribo en su entrada y leyendo su salida. Suena fácil, correcto, el diablo está en la plataforma cruzada. Me estoy enfocando tanto en MSVC/Win32 como en gcc/Linux y obviamente quiero escribir la cantidad mínima de código específico de la plataforma. Mi google-fu me ha fallado, recibo demasiado ruido por mis consultas, así que comencé con lo que sé.Redirección multiplataforma de entrada y salida estándar del proceso generado en C/C++ nativo (editar con solución)

popen - agradable y fácil, devuelve ARCHIVO * que es fácil de consumir en todas partes. Pero aquí es lo que MSDN have to say about _popen:

si se utiliza en un programa de Windows, la función _popen devuelve un puntero a un archivo no válida que hace que el programa deje de responder indefinidamente. _popen funciona correctamente en una aplicación de consola. Para crear una aplicación Windows que redirecciona la entrada y la salida , consulte Crear un proceso secundario con entrada y salida redirigidas en Platform SDK.

y así popen está fuera de la cuestión (edit: porque me gustaría que mi código funcione en la aplicación GUI). La manera de hacerlo de Windows es, en mi opinión, bastante fea y prolija. Podría vivir con el código de generación específico de la plataforma, pero me gustaría que al menos el código de E/S sea el mismo. Aquí, sin embargo, choqué con una pared entre el WinAPI HANDLE sy C FILE*, y el descriptor de archivo int. ¿Hay alguna manera de "convertir" un HANDLE en FILE* o int fd o viceversa? (Google me falló una vez más en este caso, todas las palabras clave que probé se usaron demasiado)

¿Hay alguna forma mejor de hacerlo con poco código de plataforma específica?

Las bibliotecas externas no están fuera de discusión, sin embargo, el mantenimiento de la dependencia es problemático, especialmente en plataformas múltiples, por lo que me gustaría reducir las dependencias. No encontré esa biblioteca en el impulso también.


Solo para el registro, lo que funcionó para mí al final. En Windows/MSVC, CreatePipe() + CreateProcess() como se indica here, usando _open_osfhandle() seguido de _fdopen() para obtener FILE* en la entrada y salida del proceso. En Linux/GCC, nada nuevo aquí, creando pipe() s; fork() luego dup2() las tuberías; exec(); fdopen() en los descriptores de archivos relevantes. De esta forma, solo el código de generación del proceso depende de la plataforma (lo cual está bien, ya que en Windows me gustaría controlar los parámetros adicionales STARTUPINFO), escribiendo la entrada y leyendo la salida a través del estándar FILE* y funciones relacionadas.

+0

usted no dice si está escribiendo una interfaz gráfica de usuario o una aplicación de consola. Si este último, popen() funciona en Windows. –

Respuesta

6

Give libexecstream a whirl. Es multiplataforma y le permite atrapar los flujos de entrada, salida y error de un proceso de forma asíncrona como flujos de estilo C++.

Lo he usado en Linux, Darwin y Windows y parece funcionar. También es bastante liviano, por lo que se integra en proyectos con poco dolor y tiene una licencia BSD bastante abierta. No creo que haya forma de evitar el uso de una biblioteca (que no sea escribir sus propias variaciones para cada plataforma).

Cuestiones relacionadas