Reindirizza l'output della console nella casella di testo in un programma separato
Domanda
Sto sviluppando un'applicazione Windows Form che mi richiede di chiamare un programma separato per eseguire un'attività. Il programma è un'applicazione console e devo reindirizzare l'output standard dalla console a una TextBox nel mio programma.
Non ho problemi a eseguire il programma dalla mia applicazione, ma non so come reindirizzare l'output alla mia applicazione. Ho bisogno di catturare l'output mentre il programma è in esecuzione utilizzando eventi.
Il programma della console non è destinato a interrompere l'esecuzione finché l'applicazione non si interrompe e il testo cambia costantemente a intervalli casuali. Quello che sto tentando di fare è semplicemente agganciare l'output dalla console per attivare un gestore eventi che può quindi essere utilizzato per aggiornare TextBox.
Sto usando C # per codificare il programma e sto usando .NET Framework per lo sviluppo. L'applicazione originale non è un programma .NET.
EDIT: Ecco un esempio di codice di ciò che sto cercando di fare. Nella mia app finale, sostituirò Console.WriteLine con il codice per aggiornare TextBox. Ho provato a impostare un punto di interruzione nel gestore dell'evento e non è nemmeno stato raggiunto.
void Method()
{
var p = new Process();
var path = @"C:\ConsoleApp.exe";
p.StartInfo.FileName = path;
p.StartInfo.UseShellExecute = false;
p.OutputDataReceived += p_OutputDataReceived;
p.Start();
}
static void p_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
Console.WriteLine(">>> {0}", e.Data);
}
Soluzione
Questo funziona per me:
void RunWithRedirect(string cmdPath)
{
var proc = new Process();
proc.StartInfo.FileName = cmdPath;
// set up output redirection
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.RedirectStandardError = true;
proc.EnableRaisingEvents = true;
proc.StartInfo.CreateNoWindow = true;
// see below for output handler
proc.ErrorDataReceived += proc_DataReceived;
proc.OutputDataReceived += proc_DataReceived;
proc.Start();
proc.BeginErrorReadLine();
proc.BeginOutputReadLine();
proc.WaitForExit();
}
void proc_DataReceived(object sender, DataReceivedEventArgs e)
{
// output will be in string e.Data
}
Altri suggerimenti
Puoi usare il seguente codice
MemoryStream mem = new MemoryStream(1000);
StreamWriter writer = new StreamWriter(mem);
Console.SetOut(writer);
Assembly assembly = Assembly.LoadFrom(@"C:\ConsoleApp.exe");
assembly.EntryPoint.Invoke(null, null);
writer.Close();
string s = Encoding.Default.GetString(mem.ToArray());
mem.Close();
Ho aggiunto un certo numero di metodi di supporto alla Piattaforma O2 (progetto Open Source) che ti consentono di creare facilmente un script interazione con un altro processo tramite l'output e l'input della console (vedere http://code.google.com/p/o2platform/source/browse/trunk/O2_Scripts/APIs/Windows/CmdExe/CmdExeAPI.cs )
Utile anche per te potrebbe essere l'API che consente la visualizzazione dell'output della console del processo corrente (in una finestra di controllo o popup esistente). Vedi questo post del blog per maggiori dettagli: http://o2platform.wordpress.com/2011/11/26/api_consoleout-cs-inprocess-capture-of-the-console-output/ (questo blog contiene anche dettagli su come consumare la console output di nuovi processi)
Grazie a Marc Maxham per la sua risposta che mi fa risparmiare tempo!
Come lo nota Jon of All Trades, UseShellExecute
deve essere impostato su false per reindirizzare i flussi IO, altrimenti la chiamata Start ()
genera un InvalidOperationException
.
Ecco la mia modifica del codice in cui txtOut
è una casella di testo di sola lettura WPF
void RunWithRedirect(string cmdargs)
{
var proc = new Process()
{
StartInfo = new ProcessStartInfo("cmd.exe", "/k " + cmdargs)
{
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true
},
EnableRaisingEvents = true
};
// see below for output handler
proc.ErrorDataReceived += proc_DataReceived;
proc.OutputDataReceived += proc_DataReceived;
proc.Start();
proc.BeginErrorReadLine();
proc.BeginOutputReadLine();
proc.WaitForExit();
}
void proc_DataReceived(object sender, DataReceivedEventArgs e)
{
if (e.Data != null)
Dispatcher.BeginInvoke(new Action( () => txtOut.Text += (Environment.NewLine + e.Data) ));
}