Process.start: ¿cómo obtener la salida?

Me gustaría ejecutar un progtwig de línea de comando externo desde mi aplicación Mono / .NET. Por ejemplo, me gustaría ejecutar mencoder . Es posible:

  1. Para obtener el resultado del shell de línea de comando, y escribirlo en mi cuadro de texto?
  2. ¿Para obtener el valor numérico para mostrar una barra de progreso con el tiempo transcurrido?

Cuando crea su objeto de Process establezca StartInfo apropiadamente:

 var proc = new Process { StartInfo = new ProcessStartInfo { FileName = "program.exe", Arguments = "command line arguments to your executable", UseShellExecute = false, RedirectStandardOutput = true, CreateNoWindow = true } }; 

luego comienza el proceso y lee de él:

 proc.Start(); while (!proc.StandardOutput.EndOfStream) { string line = proc.StandardOutput.ReadLine(); // do something with line } 

Puede usar int.Parse() o int.TryParse() para convertir las cadenas en valores numéricos. Es posible que tenga que hacer alguna manipulación de cadenas primero si hay caracteres numéricos no válidos en las cadenas que lee.

Puede procesar su salida de forma síncrona o asíncrona .

1: ejemplo sincrónico

 static void runCommand() { Process process = new Process(); process.StartInfo.FileName = "cmd.exe"; process.StartInfo.Arguments = "/c DIR"; // Note the /c command (*) process.StartInfo.UseShellExecute = false; process.StartInfo.RedirectStandardOutput = true; process.StartInfo.RedirectStandardError = true; process.Start(); //* Read the output (or the error) string output = process.StandardOutput.ReadToEnd(); Console.WriteLine(output); string err = process.StandardError.ReadToEnd(); Console.WriteLine(err); process.WaitForExit(); } 

Tenga en cuenta que es mejor procesar tanto la salida como los errores : deben manejarse por separado.

(*) Para algunos comandos (aquí StartInfo.Arguments ) debe agregar la directiva /c ; de lo contrario, el proceso se congela en WaitForExit() .

2: ejemplo asíncrono

 static void runCommand() { //* Create your Process Process process = new Process(); process.StartInfo.FileName = "cmd.exe"; process.StartInfo.Arguments = "/c DIR"; process.StartInfo.UseShellExecute = false; process.StartInfo.RedirectStandardOutput = true; process.StartInfo.RedirectStandardError = true; //* Set your output and error (asynchronous) handlers process.OutputDataReceived += new DataReceivedEventHandler(OutputHandler); process.ErrorDataReceived += new DataReceivedEventHandler(OutputHandler); //* Start process and handlers process.Start(); process.BeginOutputReadLine(); process.BeginErrorReadLine(); process.WaitForExit(); } static void OutputHandler(object sendingProcess, DataReceivedEventArgs outLine) { //* Do your stuff with the output (write to console/log/StringBuilder) Console.WriteLine(outLine.Data); } 

Si no necesita complicar las operaciones con la salida, puede omitir el método OutputHandler, simplemente agregando los manejadores directamente en línea:

 //* Set your output and error (asynchronous) handlers process.OutputDataReceived += (s, e) => Console.WriteLine(e.Data); process.ErrorDataReceived += (s, e) => Console.WriteLine(e.Data); 

Muy bien, para cualquiera que quiera que se lean tanto los errores como los resultados, pero se bloquea con cualquiera de las soluciones, proporcionadas en otras respuestas (como yo), aquí hay una solución que construí después de leer la explicación de MSDN para la propiedad StandardOutput.

La respuesta se basa en el código de T30:

 static void runCommand() { //* Create your Process Process process = new Process(); process.StartInfo.FileName = "cmd.exe"; process.StartInfo.Arguments = "/c DIR"; process.StartInfo.UseShellExecute = false; process.StartInfo.RedirectStandardOutput = true; process.StartInfo.RedirectStandardError = true; //* Set ONLY ONE handler here. process.ErrorDataReceived += new DataReceivedEventHandler(OutputHandler); //* Start process process.Start(); //* Read one element asynchronously process.BeginErrorReadLine(); //* Read the other one synchronously string output = process.StandardOutput.ReadToEnd(); Console.WriteLine(output); process.WaitForExit(); } static void OutputHandler(object sendingProcess, DataReceivedEventArgs outLine) { //* Do your stuff with the output (write to console/log/StringBuilder) Console.WriteLine(outLine.Data); } 

La forma estándar de .NET de hacer esto es leer desde el flujo ‘ StandardOutput ‘ del Proceso. Hay un ejemplo en los documentos MSDN enlazados. Similarmente, puede leer desde StandardError y escribir en StandardInput .

puede usar la memoria compartida para comunicarse con los 2 procesos, eche un vistazo a MemoryMappedFile

creará principalmente un archivo mapeado en memoria mmf en el proceso principal usando la instrucción “using”, luego creará el segundo proceso hasta que finalice y dejará que escriba el resultado en mmf usando BinaryWriter , luego leerá el resultado del mmf usando el proceso principal , también puede pasar el nombre de mmf usando argumentos de línea de comando o codificarlo.

Asegúrese de que al usar el archivo asignado en el proceso principal que hace que el proceso secundario escriba el resultado en el archivo asignado antes de que el archivo asignado se libere en el proceso principal

Ejemplo: proceso principal

  private static void Main(string[] args) { using (MemoryMappedFile mmf = MemoryMappedFile.CreateNew("memfile", 128)) { using (MemoryMappedViewStream stream = mmf.CreateViewStream()) { BinaryWriter writer = new BinaryWriter(stream); writer.Write(512); } Console.WriteLine("Starting the child process"); // Command line args are separated by a space Process p = Process.Start("ChildProcess.exe", "memfile"); Console.WriteLine("Waiting child to die"); p.WaitForExit(); Console.WriteLine("Child died"); using (MemoryMappedViewStream stream = mmf.CreateViewStream()) { BinaryReader reader = new BinaryReader(stream); Console.WriteLine("Result:" + reader.ReadInt32()); } } Console.WriteLine("Press any key to continue..."); Console.ReadKey(); } 

Proceso de niño

  private static void Main(string[] args) { Console.WriteLine("Child process started"); string mmfName = args[0]; using (MemoryMappedFile mmf = MemoryMappedFile.OpenExisting(mmfName)) { int readValue; using (MemoryMappedViewStream stream = mmf.CreateViewStream()) { BinaryReader reader = new BinaryReader(stream); Console.WriteLine("child reading: " + (readValue = reader.ReadInt32())); } using (MemoryMappedViewStream input = mmf.CreateViewStream()) { BinaryWriter writer = new BinaryWriter(input); writer.Write(readValue * 2); } } Console.WriteLine("Press any key to continue..."); Console.ReadKey(); } 

Para usar esta muestra, deberá crear una solución con 2 proyectos en su interior, luego tomará el resultado de comstackción del proceso hijo de% childDir% / bin / debug y lo copiará a% parentDirectory% / bin / debug y luego ejecutará el proyecto principal

childDir y parentDirectory son los nombres de las carpetas de tus proyectos en el PC, buena suerte 🙂

  1. Es posible obtener la salida del shell de línea de comando de un proceso como se describe aquí: http://www.c-sharpcorner.com/UploadFile/edwinlima/SystemDiagnosticProcess12052005035444AM/SystemDiagnosticProcess.aspx

  2. Esto depende de mencoder. Si muestra este estado en la línea de comando, entonces sí 🙂

Cómo iniciar un proceso (como un archivo bat, script perl, progtwig de consola) y mostrar su salida estándar en un formulario de Windows:

 processCaller = new ProcessCaller(this); //processCaller.FileName = @"..\..\hello.bat"; processCaller.FileName = @"commandline.exe"; processCaller.Arguments = ""; processCaller.StdErrReceived += new DataReceivedHandler(writeStreamInfo); processCaller.StdOutReceived += new DataReceivedHandler(writeStreamInfo); processCaller.Completed += new EventHandler(processCompletedOrCanceled); processCaller.Cancelled += new EventHandler(processCompletedOrCanceled); // processCaller.Failed += no event handler for this one, yet. this.richTextBox1.Text = "Started function. Please stand by.." + Environment.NewLine; // the following function starts a process and returns immediately, // thus allowing the form to stay responsive. processCaller.Start(); 

Puede encontrar ProcessCaller en este enlace: Iniciar un proceso y mostrar su salida estándar