2009-07-17 7 views
25

Tengo una aplicación que llama a otro proceso en una ventana de comandos y ese proceso tiene estadísticas de actualización que salen a la ventana de la consola. Pensé que esta era una operación bastante simple, pero parece que no puedo hacer que funcione. ¿Me estoy perdiendo de algo?ProcessInfo y RedirectStandardOutput

string assemblyLocation = Assembly.GetExecutingAssembly().Location; 

Process process = new Process 
{ 
    ProcessStart = 
    { 
     RedirectStandardOutput = true, 
     UseShellExecute = false, 
     WindowStyle = ProcessWindowStyle.Hidden, 
     Arguments = arg, 
     FileName = assemblyLocation.Substring(0, assemblyLocation.LastIndexOf("\\")) + "\\ffmpeg.exe", 
     CreateNoWindow = true 
    } 
}; 

process.Start(); 

Console.WriteLine(process.StandardOutput.ReadToEnd()); 

process.WaitForExit(); 

Lo ideal sería que lo que me gustaría es que la salida cambia dentro de ese proceso que golpean o los datos entra en el lector que se añaden eventos fuera de él.

Cualquier ayuda sería genial, siento que esta es una pregunta para principiantes pero parece que falta algo.

Respuesta

46

Lo he experimentado antes. A veces, la forma en que el proceso que está llamando genera la consola no es compatible con este tipo de redirección de salida. Tuve la suerte en este caso de poder modificar el proceso externo para evitar esto.

Puede intentar ejecutar su código en otro proceso que se envía a la consola y ver si funciona correctamente. A mí me parece correcto en este momento.

EDIT:

que fue y sacó un bloque de código que he usado para hacer esto. Esto se encuentra en una aplicación WPF que redirige la salida del proceso a la ventana. Observe el enlace del evento. Como esto es WPF, tengo que invocar mi llamada para escribir los datos. Puesto que no está preocupado por el bloqueo, en otras palabras debe ser capaz de reemplazar simplemente que con:

Console.WriteLine(e.Data); 

Es de esperar que ayude!

private static void LaunchProcess() 
    { 
     Process build = new Process(); 
     build.StartInfo.WorkingDirectory = @"dir"; 
     build.StartInfo.Arguments = ""; 
     build.StartInfo.FileName = "my.exe"; 

     build.StartInfo.UseShellExecute = false; 
     build.StartInfo.RedirectStandardOutput = true; 
     build.StartInfo.RedirectStandardError = true; 
     build.StartInfo.CreateNoWindow = true; 
     build.ErrorDataReceived += build_ErrorDataReceived; 
     build.OutputDataReceived += build_ErrorDataReceived; 
     build.EnableRaisingEvents = true; 
     build.Start(); 
     build.BeginOutputReadLine(); 
     build.BeginErrorReadLine(); 
     build.WaitForExit(); 
    } 

    // write out info to the display window 
    static void build_ErrorDataReceived(object sender, DataReceivedEventArgs e) 
    { 
     string strMessage = e.Data; 
     if (richTextBox != null && !String.Empty(strMessage)) 
     { 
      App.Instance.Dispatcher.BeginInvoke(DispatcherPriority.Send, (ThreadStart)delegate() 
      { 
       Paragraph para = new Paragraph(new Run(strMessage)); 
       para.Margin = new Thickness(0); 
       para.Background = brushErrorBrush; 
       box.Document.Blocks.Add(para); 
      }); 
     } 
    } 
+0

quiere decir que otro hilo u otro proceso? Puedo ejecutar el proceso desde la línea de cmd y la salida se ve bien. –

+0

Quise decir un proceso diferente al que estás intentando. En la instancia que encontré, cuando redirigí el stdout, el proceso no despejaba el búfer de salida cuando se iniciaba de esta manera, y por lo tanto, el flujo simplemente llegaba al final. Esto puede o no ser su problema. Vea el ejemplo de mi código sobre cómo he manejado esto en mis propias aplicaciones. – patjbs

+0

Puedo hacer que esto funcione con la mayoría de las aplicaciones de consola pero no con PowerShell. ¿Alguna idea? –

21

no estoy seguro exactamente cuál es el problema que se está ejecutando en, pero si usted está mirando para actuar en la salida tan pronto como se genera, intente enganchar en el evento del proceso OutputDataReceived. Puede especificar manejadores para recibir salida de forma asincrónica del proceso. He utilizado este enfoque con éxito.

ProcessStartInfo info = new ProcessStartInfo(...) 
info.UseShellExecute = false; 
info.RedirectStandardOutput = true; 
info.RedirectStandardError = true; 

Process p = Process.Start(info); 
p.OutputDataReceived += p_OutputDataReceived; 
p.ErrorDataReceived += p_ErrorDataReceived; 

p.BeginOutputReadLine(); 
p.BeginErrorReadLine(); 
p.WaitForExit(); 

..

void p_OutputDataReceived(object sender, DataReceivedEventArgs e) 
{ 
    Console.WriteLine("Received from standard out: " + e.Data); 
} 

void p_ErrorDataReceived(object sender, DataReceivedEventArgs e) 
{ 
    Console.WriteLine("Received from standard error: " + e.Data); 
} 

ver el proceso OutputDataReceived evento fuera para más información.

+0

Necesita 'Start()' un proceso antes de 'WaitForExit()' – abatishchev

+0

@abatishchev: Sí, y lo estoy haciendo. ¿Cual es tu punto? –

+0

¡Lo siento! Mi falta de atención Acurrucado con 'Process p = Process.Start (info);' – abatishchev

10

El uso de las expresiones lambda, etc:

var info = new ProcessStartInfo(path) 
{ 
    RedirectStandardError = true, 
    RedirectStandardOutput = true, 
    UseShellExecute = false, 
    Verb = "runas", 
}; 

var process = new Process 
{ 
    EnableRaisingEvents = true, 
    StartInfo = info 
}; 

Action<object, DataReceivedEventArgs> actionWrite = (sender, e) => 
{ 
    Console.WriteLine(e.Data); 
}; 

process.ErrorDataReceived += (sender, e) => actionWrite(sender, e); 
process.OutputDataReceived += (sender, e) => actionWrite(sender, e); 

process.Start(); 
process.BeginOutputReadLine(); 
process.BeginErrorReadLine(); 
process.WaitForExit(); 
+0

Solo una nota al respecto: el verbo "runas" solo funciona si UseShellExecute = true, Verb = "runas". Si UseShellExecute = true no puede redirigir el resultado. Ver más en http://kiquenet.wordpress.com/2014/08/22/uac-run-as-administrator-elevated-process/ – Kiquenet

4

Curiosamente no se puede leer desde la salida estándar y el error estándar al mismo tiempo:

si redirige tanto la salida estándar y el error estándar y luego intente leer ambos, para el ejemplo usando el siguiente código C#.

[C#] salida

cadena = p.StandardOutput.ReadToEnd();

string error = p.StandardError.ReadToEnd();

p.WaitForExit();

En este caso, si el proceso secundario escribe cualquier texto en el error estándar, bloqueará el proceso , porque el proceso principal no puede leer desde el error estándar hasta que haya terminado leyendo desde salida estándar. Sin embargo, el proceso principal no leerá la salida estándar hasta que el proceso finalice. Una solución recomendada para esta situación es crear dos subprocesos para que su aplicación pueda leer la salida de cada flujo en una secuencia separada.

http://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo.redirectstandardoutput(v=vs.71).aspx

+0

No es cierto, consulte la respuesta aceptada. –

+2

No es cierto que ** no haya forma ** de leer ambas transmisiones, solo que no es seguro usar solo métodos síncronos en ambas transmisiones al mismo tiempo. Solo quiero aclarar que @ jeremy-mcgee diciendo "no es verdad" no hace que la información ** citada ** en la respuesta sea incorrecta. – Aardvark

0

Compruebe que la salida que está esperando no está siendo enviada a la salida StandardError lugar de la salida StandardOutput

1

fluye código trabajó en VS2010

void OnOutputDataReceived(object sender, DataReceivedEventArgs e) 
    { 
     if (String.IsNullOrEmpty(e.Data) == false) 
     { 
      new Thread(() => 
      { 
       this.Dispatcher.Invoke(new Action(() => 
       { 
        // Add you code here 
       })); 
      }).Start(); 
     } 
    } 
+0

¿Qué es Dispatcher? Que es esto**? ¿Qué es el evento OnOutputDataReceived? ¿Qué es el tipo DataReceivedEventArgs? ¿Cuál es el contexto completo de tu código fuente? – Kiquenet

Cuestiones relacionadas