2010-09-04 24 views
11

Al momento sto iniziando un file batch dal mio programma C# con:Reindirizzare l'output (stdout, stderr) di un processo figlio alla finestra Output in Visual Studio

System.Diagnostics.Process.Start(@"DoSomeStuff.bat"); 

Quello che mi piacerebbe essere è in grado di reindirizzare l'output (stdout e stderr) di quel processo figlio alla finestra Output in Visual Studio (in particolare Visual C# Express 2008).

C'è un modo per farlo?

(Inoltre:. Tale che non è tutto tamponato e poi sputò fuori alla finestra Output quando il processo figlio termina)


(BTW: Al momento posso ottenere stdout (ma non stderr) del processo genitore per apparire nella finestra Output, rendendo il mio programma una "Applicazione Windows" invece di una "Applicazione console". Questo si interrompe se il programma viene eseguito all'esterno di Visual Studio, ma nel mio caso questo è ok .)

+0

Tutti i pezzi sono qui. Reindirizzare l'output per il processo, utilizzare Trace per ottenerlo nella finestra Output. –

+0

Hai capito come reindirizzare l'output di un processo figlio? Le risposte fornite di seguito potrebbero reindirizzare l'output di un processo padre ma non quello di un figlio. – Fiona

risposta

20
process.StartInfo.CreateNoWindow = true; 
process.StartInfo.UseShellExecute = false; 
process.StartInfo.RedirectStandardOutput = true; 
process.OutputDataReceived += (sender, args) => Console.WriteLine(args.Data); 
process.Start(); 
process.BeginOutputReadLine(); 

process.WaitForExit(); 

Stessa idea per Error, basta sostituire Output in quei nomi metodo/proprietà.

+6

Questa risposta ha quasi ragione. Manca qualcosa. In particolare: chiamata 'Start' prima di' Begin ... ReadLine' e 'WaitForExit' in seguito. Anche l'impostazione di 'RedirectStandardInput' su true ha risolto un problema causato da uno dei programmi (in particolare plink) nel file batch che voleva uno stdin valido, anche se non lo utilizzava. –

+0

'WaitForExit()' può causare un'attesa infinita. Chiamare sempre il metodo con un timeout: 'process.WaitForExit (10000)' => attende 10 secondi. –

-3

Avete considerato l'utilizzo di un DefaultTraceListener?

//Create and add a new default trace listener. 
    DefaultTraceListener defaultListener; 
    defaultListener = new DefaultTraceListener(); 
    Trace.Listeners.Add(defaultListener); 
+2

Questo * nemmeno * remotamente * risponde alla mia domanda. E dalla pagina MSDN collegata: "Un'istanza di questa classe viene automaticamente aggiunta alle raccolte Debug.Listeners e Trace.Listeners. L'aggiunta esplicita di un secondo DefaultTraceListener causa messaggi duplicati nella finestra di output del debugger e caselle di messaggio duplicate per gli asser.", Rendendo la tua risposta è peggio di totalmente inutile. –

+4

Revenge downvote, eh? Rimani elegante, GenEric35. –

+0

+1 per la spiegazione della pagina MSDN di Anderw – prabhakaran

2

Che cosa sta succedendo qui è che Visual Studio sta visualizzando l'output di debug dal programma nella finestra di output. Cioè: se usi Trace.WriteLine, apparirà nella finestra Output, a causa del listener di trace predefinito.

In qualche modo, l'applicazione Windows Form (quando utilizza Console.WriteLine; presumo che si stia utilizzando Console.WriteLine) sta anche scrivendo l'output di debug e Visual Studio lo sta rilevando.

Non farà lo stesso per i processi figli, a meno che non si acquisisca esplicitamente l'output e lo si reindirizzi insieme all'output.

+0

Questo è praticamente ciò che sto cercando di chiedere - come si fa a fare l'ultimo passo? (E ho capito che mi mancava questo dalla mia domanda: come si fa "come succede"?) –

8

Una variazione di questo funziona per me, ora lo faccio perché vorrei averlo trovato prima. Si noti che questo è solo un frammento estratto dal codice reale, quindi potrebbero esserci errori banali.

La tecnica è basata su un codice MSDN. Quello che non sono stato in grado di capire è come ottenere la finestra di output da aggiornare "al volo". Non si aggiorna fino al termine di questa attività.

// Set this to your output window Pane 
private EnvDTE.OutputWindowPane _OutputPane = null; 

// Methods to receive standard output and standard error 

private static void StandardOutputReceiver(object sendingProcess, DataReceivedEventArgs outLine) 
{ 
    // Receives the child process' standard output 
    if (! string.IsNullOrEmpty(outLine.Data)) { 
     if (_OutputPane != null) 
      _OutputPane.Write(outLine.Data + Environment.NewLine); 
    } 
} 

private static void StandardErrorReceiver(object sendingProcess, DataReceivedEventArgs errLine) 
{ 
    // Receives the child process' standard error 
    if (! string.IsNullOrEmpty(errLine.Data)) { 
     if (_OutputPane != null) 
      _OutputPane.Write("Error> " + errLine.Data + Environment.NewLine); 
    } 
} 

// main code fragment 
{ 
    // Start the new process 
    ProcessStartInfo startInfo = new ProcessStartInfo(PROGRAM.EXE); 
    startInfo.Arguments = COMMANDLINE; 
    startInfo.WorkingDirectory = srcDir; 
    startInfo.UseShellExecute = false; 
    startInfo.RedirectStandardOutput = true; 
    startInfo.RedirectStandardError = true; 
    startInfo.CreateNoWindow = true; 
    Process p = Process.Start(startInfo); 
    p.OutputDataReceived += new DataReceivedEventHandler(StandardOutputReceiver); 
    p.BeginOutputReadLine(); 
    p.ErrorDataReceived += new DataReceivedEventHandler(StandardErrorReceiver); 
    p.BeginErrorReadLine(); 
    bool completed = p.WaitForExit(20000); 
    if (!completed) 
    { 
     // do something here if it didn't finish in 20 seconds 
    } 
    p.Close(); 
} 
+0

Questo non porterà stdout e stderror nell'ordine corretto .. – paulm

+0

@paulm cosa intendi con esso non otterrà l'ordine giusto? Questo codice non funziona per me nel reindirizzamento dello stderr (stdout sta funzionando). Qualche idea del perché? – rboy

+0

Usa la risposta della mia domanda - questo non otterrà stderr e stdout nell'ordine corretto, cioè se l'app viene eliminata, errata, errata, potresti uscire, uscire, errare, errare, ecc. – paulm

Problemi correlati