2008-08-11 9 views
5

Estoy envolviendo el código C++ existente de un proyecto BSD en nuestro envoltorio personalizado y quiero integrarlo a nuestro código con el menor número de cambios posible. Este código usa fprintf para imprimir a stderr con el fin de registrar/informar errores.Windows C++: ¿Cómo puedo redireccionar stderr para llamadas a fprintf?

Quiero redireccionar esto a un lugar alternativo dentro del mismo proceso. En Unix he hecho esto con un socketpair y un hilo: un extremo del socket es donde envío stderr (a través de una llamada al dup2) y el otro extremo se monitorea en un hilo, donde puedo procesar la salida.

Esto no funciona en Windows porque un socket no es lo mismo que un manejador de archivo.

Todos los documentos que he encontrado en la web muestran cómo redirigir el resultado de un proceso secundario, que no es lo que quiero. ¿Cómo puedo redireccionar stderr dentro del mismo proceso para obtener una devolución de llamada de algún tipo cuando se escribe la salida? (y antes de decirlo, lo intenté SetStdHandle pero no encontré ninguna manera de hacer esto) ...

Respuesta

6

Puede usar una técnica similar en Windows, solo necesita usar palabras diferentes para los mismos conceptos. :) Este artículo: http://msdn.microsoft.com/en-us/library/ms682499.aspx usa un tubo win32 para manejar E/S de otro proceso, solo tiene que hacer lo mismo con los hilos dentro del mismo proceso. Por supuesto, en su caso, toda la salida a stderr desde cualquier lugar del proceso se redireccionará a su consumidor.

En realidad, otras piezas del rompecabezas que pueda necesitar son _fdopen y _open_osfhandle. De hecho, aquí hay un ejemplo relacionado de alguna code publiqué hace años:

DWORD CALLBACK DoDebugThread(void *) 
{ 
    AllocConsole(); 
    SetConsoleTitle("Copilot Debugger"); 
    // The following is a really disgusting hack to make stdin and stdout attach 
    // to the newly created console using the MSVC++ libraries. I hope other 
    // operating systems don't need this kind of kludge.. :) 
    stdout->_file = _open_osfhandle((long)GetStdHandle(STD_OUTPUT_HANDLE), _O_TEXT); 
    stdin->_file = _open_osfhandle((long)GetStdHandle(STD_INPUT_HANDLE), _O_TEXT); 
    debug(); 
    stdout->_file = -1; 
    stdin->_file = -1; 
    FreeConsole(); 
    CPU_run(); 
    return 0; 
} 

En este caso, el proceso principal era un proceso de interfaz gráfica de usuario que no se inicia con stdio maneja en absoluto. Abre una consola, luego coloca las manijas derechas en stdout y stdin para que la función debug(), que fue diseñada como una función interactiva stdio, pueda interactuar con la consola recién creada. Debería poder abrir algunas tuberías y hacer el mismo tipo de cosas para redirigir a stderr.

3

Debe recordar que lo que MSVCRT llama "controladores de sistema operativo" no son identificadores de Win32, sino que se agrega otra capa de identificadores para confundirlo. MSVCRT intenta emular los números de manejador de Unix donde stdin = 0, stdout = 1, stderr = 2 y así sucesivamente. Los identificadores Win32 están numerados de forma diferente y sus valores siempre son múltiplos de 4. Abrir el conducto y configurar todos los controladores configurados correctamente requerirá que las manos se ensucien. Usar el código fuente de MSVCRT y un depurador es probablemente un requisito.

1

Mencione que no desea utilizar una tubería con nombre para uso interno; es probable que valga la pena señalar que la documentación para CreatePipe() indica "Las tuberías anónimas se implementan utilizando una tubería con nombre único. Por lo tanto, a menudo se puede pasar un identificador a una tubería anónima a una función que requiere un identificador para una tubería con nombre " Por lo tanto, sugiero que solo escriba una función que cree un conducto similar con la configuración correcta para la lectura asíncrona. Tiendo a usar un GUID como una cadena (generada usando CoCreateGUID() y StringFromIID()) para darme un nombre único y luego crear los extremos del servidor y el cliente de la tubería con nombre con la configuración correcta para E/S superpuestas (más detalles sobre esto, y código, aquí: http://www.lenholgate.com/blog/2008/02/process-management-using-jobs-on-windows.html).

Una vez que tengo que puedo conectar a un código que tengo que leer un archivo usando E/s superpuesta con una E/S puerto de finalización y, bueno, entonces me acaba de obtener notificaciones asíncronas de los datos a medida que llega .. Sin embargo, tengo una buena cantidad de código de la biblioteca bien probado que hace que todo suceda ...

Probablemente sea posible configurar el tubo con nombre y luego hacer una lectura solapada con un evento en su OVERLAPPED estructura y verifica el evento para ver si los datos estaban disponibles ... No tengo ningún código disponible que haga eso.

Cuestiones relacionadas