Lo que me gustaría hacer es similar a lo que Visual Studio hace en su ventana de salida u otros editores en sus ventanas de herramientas: Comience otro proceso B desde mi proceso A y capture su salida stdout/stderr.Cómo capturar stdout de otro proceso en Win32 sin latencia?
Hasta ahora, lo tengo trabajando con CreatePipe()
, pero por alguna razón, la salida de B no llega a B justo cuando se escribe. Se comporta más como un buffer de algún tipo se llena y cuando está lleno, todo el contenido de los buffers llega a A de una vez. Escribí mi propio programa de prueba que produce algo y hace un fflush(stdout)
directamente después. Entonces la salida llega directamente a A. Pero no puedo cambiar el código de todos los procesos B que me gustaría usar de esa manera. Tratar de lavar la tubería desde A tampoco funciona.
¿Cómo se supone que funciona?
Mi código de inicialización, así como el consumo de código:
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.bInheritHandle = TRUE;
sa.lpSecurityDescriptor = NULL;
err = CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &sa, stdouthistory);
if (err == 0)
return 1;
err = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
GetCurrentProcess(), &hChildStdoutRdDup , 0,
FALSE,
DUPLICATE_SAME_ACCESS);
if (err == 0)
return 3;
CloseHandle(hChildStdoutRd);
DWORD a, b, c;
a = PIPE_READMODE_BYTE | PIPE_NOWAIT;
b = 0;
c = 0;
SetNamedPipeHandleState(hChildStdoutRdDup, &a, &b, &c);
err = CreatePipe(&hChildStdinRd, &hChildStdinWr, &sa, stdinhistory);
if (err == 0)
return 1;
err = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
GetCurrentProcess(), &hChildStdinWrDup , 0,
FALSE,
DUPLICATE_SAME_ACCESS);
if (err == 0)
return 4;
CloseHandle(hChildStdinWr);
a = PIPE_READMODE_BYTE | PIPE_NOWAIT;
b = 0;
c = 0;
ZeroMemory(&si,sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.dwFlags = STARTF_USESTDHANDLES;
si.wShowWindow = SW_SHOW;
si.hStdOutput = hChildStdoutWr;
si.hStdError = hChildStdoutWr;
si.hStdInput = hChildStdinRd;
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
err = CreateProcess(0, this->cmdline, 0, 0, true, CREATE_NO_WINDOW, 0, 0, &si, &pi);
if (err == 0)
return 4;
Consumo:
DWORD avail;
unsigned int ofs = 0;
if (PeekNamedPipe(hChildStdoutRdDup, NULL, 0, NULL, &avail, NULL))
{
if (avail != 0)
{
int err = ReadFile(hChildStdoutRdDup, s + ofs, slen, &threadbuffern, 0);
// Consume ...
}
}
Editar: Acabo de encontrar esta pregunta: Continuously read from STDOUT of external process in Ruby. Es el mismo problema, pero en el contexto de Ruby. Lamentablemente, la solución fue utilizar alguna biblioteca de Ruby que simplemente lo haga funcionar. ¿Cómo lo hace esa biblioteca? ¿Cuál es el equivalente en Win32/C++?
El hilo enlazado es una solución * nix. Nada similar en Win32. –
¿Cómo sabes que solo está relacionado con Unix? También tenga en cuenta que existen programas en Windows que pueden hacerlo bien - de código cerrado:/ – marc40000