Quello che mi piacerebbe fare è simile a ciò che Visual Studio fa nella sua finestra di output o altri editor nelle finestre degli strumenti: Avvia un altro processo B dal mio processo A e cattura il suo output stdout/stderr.Come catturare lo stdout da un altro processo in Win32 senza latenza?
Finora, ho funzionato con CreatePipe()
, ma per qualche motivo, l'output di B non arriva a B quando viene scritto. Si comporta più come un buffer di qualche tipo che viene riempito e quando è pieno, tutti i contenuti dei buffer arrivano ad A contemporaneamente. Ho scritto il mio programma di test che emette qualcosa e fa subito un fflush(stdout)
. Quindi l'output arriva direttamente su A. Ma non posso cambiare il codice di tutti i processi B che mi piacerebbe usare in quel modo. Anche il tentativo di svuotare il tubo da A non funziona.
Come si suppone che funzioni?
Il mio codice di inizializzazione, così come codice di consumare:
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 ...
}
}
Edit: Ho appena trovato questa domanda: Continuously read from STDOUT of external process in Ruby. È lo stesso problema, ma nel contesto di Ruby. Purtroppo la soluzione era usare una libreria Ruby che lo facesse funzionare. Come fa quella libreria a farlo? Qual è l'equivalente in Win32/C++?
Il thread collegato è una soluzione * nix. Niente di simile in Win32. –
Come fai a sapere che è collegato solo a unix? Notate anche che esistono programmi su Windows che possono farcela bene - quelli a sorgente chiusa:/ – marc40000