From b1797d1ecf476478de40b867e475bb1cf457a161 Mon Sep 17 00:00:00 2001 From: "gu.martinm@gmail.com" Date: Mon, 9 Jun 2014 20:29:44 +0200 Subject: [PATCH] Process launcher: comments and some improvements --- .../ProcessLauncher/LinuxWindowsProcess.cs | 76 ++++++++++++---------- 1 file changed, 41 insertions(+), 35 deletions(-) diff --git a/Allgemeines/ProcessLauncher/ProcessLauncher/LinuxWindowsProcess.cs b/Allgemeines/ProcessLauncher/ProcessLauncher/LinuxWindowsProcess.cs index 3f83771..703a25c 100644 --- a/Allgemeines/ProcessLauncher/ProcessLauncher/LinuxWindowsProcess.cs +++ b/Allgemeines/ProcessLauncher/ProcessLauncher/LinuxWindowsProcess.cs @@ -18,21 +18,34 @@ namespace ProcessLauncher // To use StandardOutput, you must set ProcessStartInfo.UseShellExecute to false, and you must set // ProcessStartInfo.RedirectStandardOutput to true. Otherwise, reading from the StandardOutput stream throws an exception. // What is going to do Mono with stdout, stdin and stderr depending on this value? + // Answer: true or false is the same (from the stdout/stderr/stdin point of view) BUT IF THIS PROPERTY + // HAS TRUE VALUE YOU MAY NOT REDIRECT stdout/stderr/stdin STREAMS. SO, THIS PROPERTY + // ENABLES US TO REDIRECT STREAMS (by means of pipes). WHEN UseShellExecute HAS TRUE VALUE TRYING + // TO SET TRUE VALUE IN RedirectStandardOutput/RedirectStandardInput/RedirectStandardError + // WILL THROW EXCEPTION. startInfo.UseShellExecute = false; - // Redirect the standard output of the subprocess command. - // What is going to do Mono with stdout? Some pipe, I guess. + // Redirect the standard output of the child process command. + // What is going to do Mono with stdout? Answer: piped stdout from child to this C# parent process. + // TRUE VALUE REQUIRES UseShellExecute=false startInfo.RedirectStandardOutput = true; - // What is going to do Mono with stdin? + // What is going to do Mono with stdin? Answer: stdin the same as child's parent process (this C# process) + // TRUE VALUE REQUIRES UseShellExecute=false startInfo.RedirectStandardInput = false; - // What is going to do Mono with stderr? + // What is going to do Mono with stderr? Answer: stderr the same as child's parent process (this C# process) + // TRUE VALUE REQUIRES UseShellExecute=false startInfo.RedirectStandardError = false; // What is going to do Mono with this value? What if I am running a GTK (GUI application) startInfo.WindowStyle = ProcessWindowStyle.Minimized; + // Encoding + startInfo.StandardOutputEncoding = Encoding.UTF8; + // It is only supported when stream is redirected. + // startInfo.StandardErrorEncoding = Encoding.UTF8; + startInfo.Arguments = arguments; startInfo.FileName = command; @@ -46,58 +59,51 @@ namespace ProcessLauncher process.StartInfo = startInfo; - // When is Mono going to call my event implementation? Every time the subprocess writes to stdout? + // What is going to do Mono depending on this value? :/ + // true if the Exited event should be raised when the associated child process is terminated + // (through either an exit or a call to Kill); otherwise, false. The default is false. + // The EnableRaisingEvents property indicates whether the component should be notified + // when the operating system has shut down a child process. The EnableRaisingEvents property + // is used in asynchronous processing to notify your application that a child process has exited. + // To force your application to synchronously wait for an exit event (which interrupts + // processing of the application until the exit event has occurred), use the WaitForExit method. + process.EnableRaisingEvents = false; + + // When is Mono going to call my event implementation? Every time the child process writes to stdout? // From here: http://msdn.microsoft.com/en-us/library/vstudio/system.diagnostics.process.outputdatareceived%28v=vs.110%29.aspx - // Thereafter, the OutputDataReceived event signals each time the process writes a line to the - // redirected StandardOutput stream, until the process exits or calls CancelOutputRead. + // Thereafter, the OutputDataReceived event signals each time the child process writes a line to the + // redirected StandardOutput stream, until the child process exits or calls CancelOutputRead. // That behaviour is weird (IMHO) Check out the Mono implementation!!! // Set our event handler to asynchronously read the standard output. process.OutputDataReceived += new DataReceivedEventHandler( delegate(object sendingProcess, DataReceivedEventArgs outLine) { // Collect the command output. - // To asynchronously collect the redirected StandardOutput or StandardError stream output of a process, you must create - // a method that handles the redirected stream output events. The event-handler method is called when the process writes + // To asynchronously collect the redirected StandardOutput or StandardError stream output of a child process, you must create + // a method that handles the redirected stream output events. The event-handler method is called when the child process writes // to the redirected stream. The event delegate calls your event handler with an instance of DataReceivedEventArgs. - // The Data property contains the text line that the process wrote to the redirected stream. + // The Data property contains the text line that the child process wrote to the redirected stream. if (!String.IsNullOrEmpty(outLine.Data)) { // Add the text to the collected output. processOutput.Append(Environment.NewLine + outLine.Data); } }); - // Taken from http://stackoverflow.com/questions/285760/how-to-spawn-a-process-and-capture-its-stdout-in-net - // I do not think this is the right way to read the output stream!!!! - // My event handler will be called (see documentation) every time the process writes a line to the output stream but - // with this code I will be reading the output stream until it is closed by the process. So, I guess, we could end - // up having multiple event handlers reading from the same stream (output stream) Each handler was called each time - // the process wrote a line to the output stream. :/ - // process.OutputDataReceived += new DataReceivedEventHandler( - // delegate(object sender, DataReceivedEventArgs e) - // { - // using (StreamReader output = process.StandardOutput) - // { - // string data = output.ReadToEnd(); - // processOutput.Append(data); - // } - // }); - // Don't mix using statements and lambda expressions :( - // http://blogs.msdn.com/b/jaredpar/archive/2008/07/16/don-t-mix-using-statements-and-lambda-expressions.aspx - // process.OutputDataReceived += (sender, e) => - // { - // using (StreamReader output = process.StandardOutput) - // { - // string data = output.ReadToEnd(); - // processOutput.Append(data); - // } - // }; // Start the process. process.Start(); // Start the asynchronous read of the output stream. + // What is going to do Mono with this method? I guess, it will begin to read from the piped stream + // line by line and it will call to my DataReceivedEventHandler delegate implementation for every line + // (by means of some new thread in an asynchronous way) process.BeginOutputReadLine(); + // BE CAREFUL WITH DEADLOCKS (if child process fills pipes and nobody reads them, this C# parent process + // could wait forever because the child process would be waiting until someone reads from the pipes) + // In this case, the process, which should read from the stdout pipe, is this C# parent process. + // see: http://msdn.microsoft.com/en-us/library/vstudio/system.diagnostics.process.standardoutput + // Wait for the process. process.WaitForExit(); -- 2.1.4