0

Background

I have a code that runs an executable asynchronously. The executable would normally be run on the command line. My code is inspired by this post:


namespace Feather
{
    internal class Helper
    {
        private static StringBuilder output;
        private static Process cmd;

        public static void RunLogic(string args)
        {
            output = new StringBuilder();
            cmd = new Process();

            try
            {
                cmd.StartInfo.FileName = "Cotton.exe";
                cmd.StartInfo.Arguments = args;
                cmd.StartInfo.UseShellExecute = false;
                cmd.StartInfo.CreateNoWindow = true;
                cmd.StartInfo.RedirectStandardOutput = true;
                cmd.StartInfo.RedirectStandardInput = true;

                cmd.EnableRaisingEvents = true;
                cmd.OutputDataReceived +=
                   new DataReceivedEventHandler(cmd_OutputDataReceived);
                cmd.Exited += new EventHandler(cmd_Exited);

                cmd.Start();
            }

            catch (Exception ex)
            {
                RhinoApp.WriteLine("Error on process start: {0}", ex.Message);
            }
        }

        private static void cmd_Exited(object sender, EventArgs e)
        {
            try
            {
                if (!string.IsNullOrEmpty(output.ToString()))
                {
                    RhinoApp.WriteLine("Process output: {0}", output.ToString());
                }

                RhinoApp.WriteLine("Process finished.");
                cmd.Dispose();
            }

            catch (Exception ex)
            {
                RhinoApp.WriteLine("Error on process exit: {0}", ex.Message);
            }
        }

        private static void cmd_OutputDataReceived(object sender, DataReceivedEventArgs e)
        {
            try
            {
                RhinoApp.WriteLine("cmd_OutputDataReceived is called.");

                if (!String.IsNullOrEmpty(e.Data))
                {
                    output.Append(e.Data + Environment.NewLine);
                }
            }
            catch (Exception ex)
            {
                RhinoApp.WriteLine("Error on process data-receive: {0}", ex.Message);
            }
        }
    }
}

Question

The private static StringBuilder output; is always empty. Nothing is appended to it by output.Append(e.Data + Environment.NewLine); statement. I cannot figure out why.

How can I get all the executable command line logs? Is there a straightforward way to do so?

Megidd
  • 7,089
  • 6
  • 65
  • 142
  • 1
    Is your event handler `cmd_OutputDataReceived` getting invoked, are you getting data in the `e.Data` - check by writing to a temp file. – Anand Sowmithiran Aug 21 '23 at 13:16
  • 1
    This answer seems better, it adds output data to a concurrent queue and finally prints it, https://stackoverflow.com/a/67809857/14973743. After `Start`ing the process, you need to call the `BeginOutputReadLine` method as well ! – Anand Sowmithiran Aug 21 '23 at 13:23
  • @AnandSowmithiran You are right. Logs indicate that `cmd_OutputDataReceived` is never called whatsoever. – Megidd Aug 21 '23 at 13:25
  • @AnandSowmithiran You were right. The problem was the missing `cmd.BeginOutputReadLine();` statement. – Megidd Aug 21 '23 at 13:34
  • @AnandSowmithiran Can you post your comments as an answer? So that this post can be closed as answered. – Megidd Aug 21 '23 at 13:46

1 Answers1

0

The main problem was the missing cmd.BeginOutputReadLine(); statement. The final modified code is this:


namespace Feather
{
    internal class Helper
    {
        private static StringBuilder cmdLog;
        private static Process cmd;

        public static void RunLogic(string args)
        {
            cmdLog = new StringBuilder();
            cmd = new Process();

            try
            {
                cmd.StartInfo.FileName = "Cotton.exe";
                cmd.StartInfo.Arguments = args;
                cmd.StartInfo.UseShellExecute = false;
                cmd.StartInfo.CreateNoWindow = true;
                cmd.StartInfo.RedirectStandardOutput = true;
                cmd.StartInfo.RedirectStandardError = true;
                cmd.StartInfo.RedirectStandardInput = true;

                cmd.EnableRaisingEvents = true;
                cmd.OutputDataReceived += new DataReceivedEventHandler(cmd_LogReceived);
                cmd.ErrorDataReceived += new DataReceivedEventHandler(cmd_LogReceived);
                cmd.Exited += new EventHandler(cmd_Exited);

                cmd.Start();

                // Begin asynchronous reading.
                cmd.BeginOutputReadLine();
                cmd.BeginErrorReadLine();
            }

            catch (Exception ex)
            {
                RhinoApp.WriteLine("Error on process start: {0}", ex.Message);
            }
        }

        private static void cmd_Exited(object sender, EventArgs e)
        {
            try
            {
                if (!string.IsNullOrEmpty(cmdLog.ToString()))
                {
                    RhinoApp.WriteLine("Process logs:\n\n{0}", cmdLog.ToString());
                }

                RhinoApp.WriteLine("Process finished.");
                cmd.Dispose();
            }

            catch (Exception ex)
            {
                RhinoApp.WriteLine("Error on process exit: {0}", ex.Message);
            }
        }

        private static void cmd_LogReceived(object sender, DataReceivedEventArgs e)
        {
            try
            {
                if (!String.IsNullOrEmpty(e.Data))
                {
                    cmdLog.Append(e.Data + Environment.NewLine);
                }
            }
            catch (Exception ex)
            {
                RhinoApp.WriteLine("Error on process log: {0}", ex.Message);
            }
        }
    }
}
Megidd
  • 7,089
  • 6
  • 65
  • 142