In a separate process, the console opens to which the command is transferred. I want to get the result of the command, which, instead of outputting to the console, should be saved in a variable of type string and returned to the calling method. Here is the code that does not work:

internal class ConsoleBuilder { private static int lineCount = 0; private static StringBuilder output = new StringBuilder(); internal static void Execute(string command, ref Process proc, out string outputText, out string outputError) { outputText = string.Empty; outputError = string.Empty; proc = new Process(); proc.StartInfo = new ProcessStartInfo("C:\\Windows\\System32\\cmd.exe", command); proc.StartInfo.CreateNoWindow = true; proc.StartInfo.UseShellExecute = false; proc.StartInfo.RedirectStandardError = true; proc.StartInfo.RedirectStandardOutput = true; proc.EnableRaisingEvents = true; proc.OutputDataReceived += new DataReceivedEventHandler((sender, e) => { if(!String.IsNullOrEmpty(e.Data)) { lineCount++; output.Append("\n[" + lineCount + "]: " + e.Data); } }); proc.Start(); proc.BeginOutputReadLine(); proc.BeginErrorReadLine(); outputText = output.ToString(); } } internal class Program { private static void Main(string[] args) { string command = "echo I'm here!"; string pathToCmd = "C:\\Windows\\System32\\cmd.exe"; Process proc = null; string outputText = string.Empty; string outputError = string.Empty; ConsoleBuilder.Execute(command, ref proc, out outputText, out outputError); Console.WriteLine(outputText); } } 

The outputText string is returned empty. Tell me what's wrong?

    4 answers 4

    Recently solved the same problem, found the answer to the English version of the site. It is strange that you did not find it). Most likely, the problem is that you are not waiting for the end of the process. Here is the code that works for me.

     public static string ExecuteExternal(string fileName, string args, int timeout) { StringBuilder log = new StringBuilder(); using (Process process = new Process()) { process.StartInfo.FileName = fileName; process.StartInfo.Arguments = args; process.StartInfo.UseShellExecute = false; process.StartInfo.RedirectStandardOutput = true; process.StartInfo.RedirectStandardError = true; using (AutoResetEvent outputWaitHandle = new AutoResetEvent(false)) using (AutoResetEvent errorWaitHandle = new AutoResetEvent(false)) { process.OutputDataReceived += (sender, e) => { if (e.Data == null) { outputWaitHandle.Set(); } else { log.AppendLine(e.Data); } }; process.ErrorDataReceived += (sender, e) => { if (e.Data == null) { errorWaitHandle.Set(); } else { log.AppendLine(e.Data); } }; process.Start(); process.BeginOutputReadLine(); process.BeginErrorReadLine(); if (timeout > 0) { if (process.WaitForExit(timeout) && outputWaitHandle.WaitOne(timeout) && errorWaitHandle.WaitOne(timeout)) { } } else { process.WaitForExit(); outputWaitHandle.WaitOne(); errorWaitHandle.WaitOne(); } } } return log.ToString(); } 
    • and if the process is endless and I can not wait for it to end? - neo
    • one
      @neo; There is a timeout for this) The timeout parameter is passed to my method. If its value is> 0, then the timeout is set, otherwise we are waiting for the end of the process. Here is a link to the source - Rustam Fatkullin
    • Well, only timeouts and not enough, and when the handler is called, when necessary. - Qwertiy

    The outputText string is returned empty. Tell me what's wrong?

    Well, I still looked closely at the code ...

    The problem is that you return the string immediately, and the callback is called asynchronously, that is, after the string is returned.

      Asynchronously read failed. But the solution of synchronous reading, proposed here: Synchronous example .

       internal class ConsoleBuilder { private static int lineCount = 0; internal static StringBuilder output = new StringBuilder(); internal static string myStr = string.Empty; internal static void Execute(string command, ref Process process, out string outputText, out string outputError) { outputText = string.Empty; outputError = string.Empty; process = new Process(); process.StartInfo.FileName = "cmd.exe"; process.StartInfo.Arguments = "/c " + command; // Note the /c command (*) process.StartInfo.UseShellExecute = false; process.StartInfo.RedirectStandardOutput = true; process.StartInfo.RedirectStandardError = true; process.StartInfo.CreateNoWindow = true; process.Start(); //* Read the output (or the error) outputText = process.StandardOutput.ReadToEnd(); Console.WriteLine(output); outputError = process.StandardError.ReadToEnd(); Console.WriteLine(outputError); process.WaitForExit(); } } 
         ChDir("D:\Некий Путь\bin") Dim Info As New ProcessStartInfo With { .FileName = "cmd.exe", .Arguments = "/k ""D:\Некий Путь\bin\startup.bat""", .RedirectStandardOutput = True, .RedirectStandardError = True, .UseShellExecute = False, .CreateNoWindow = True} Dim Prc As Process = Process.Start(Info) Do Dim Line As String = Await Prc.StandardOutput.ReadLineAsync() If Line Is Nothing Then Exit Do RtbStart1.Text += Line + vbCrLf Loop 
        • But is there a C # code after all? - neo
        • @neo, but what is this incomprehensible? - Qwertiy
        • and the fact that you need to know the specific functions of the C # language in order to implement synchronous redirection of console output. Why are there functions of another language? - neo
        • and since you say that you need to read synchronously, why then Prc.StandardOutput.ReadLineAsync () ? - neo