Console app async control

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Alistair George

    #1

    Console app async control

    Hi all.
    A win gui has to run a console (cmd) app, desirably the cmd window is
    hidden, which I will do by placing outside the view area.
    The GUI must be able to parse the output from cmd and do various things
    like show a progress meter etc. It should also be able to gracefully
    close the cmd window if it hangs or user needs the thread to abort.
    Would I be correct in assuming the cmd should be started in a thread
    with async coms?
    MethodInvoker with BeginInvoke?
    Appreciate any pointers to articles on this subject (google search
    reveals few).
    Thank you.
  • Marc Gravell

    #2
    Re: Console app async control

    If you look at ProcessStartInf o, you can suppress the visual console
    (IIRC) with CreateNoWindow = true, and capture the output by setting
    RedirectStandar dOutput = false, UseShellExecute = false, and reading
    from Process.Standar dOutput once you have started the command.

    When running a win-ui, the easiest option is to do the reading (from
    StandardOutput) on a workder thread (not the UI thread), and then
    (when you read something interesting) use yourForm.BeginI nvoke() to
    notify the UI. There is also an event-driven mechanism
    (Process.Output DataReceived), but this is trickier.

    I'll put an example together if you like...

    Marc

    Comment

    • Marc Gravell

      #3
      Re: Console app async control

      (exe)

      using System;
      using System.IO;

      class Program {
      static int Main(string[] args) {
      try {
      string root = args.Length == 1 ? args[0] :
      Environment.Cur rentDirectory;
      string[] dirs = Directory.GetDi rectories(args[0], "*.*",
      SearchOption.Al lDirectories);
      int count = dirs.Length, lastPercent = -1;
      for (int i = 0; i < count; i++) {
      int percent = (i * 100) / count;
      if (percent != lastPercent) {
      Console.WriteLi ne(percent.ToSt ring() + "%");
      }
      foreach (string file in Directory.GetFi les(dirs[i])) {
      Console.WriteLi ne(file);
      }
      }
      return 0;
      } catch (Exception ex) {
      Console.Error.W riteLine(ex.Mes sage);
      return -1;
      }
      }
      }

      (winform)

      using System;
      using System.Windows. Forms;
      using System.Componen tModel;
      using System.Diagnost ics;
      using System.IO;
      using System.Text.Reg ularExpressions ;

      class SomeForm : Form {
      static void Main() {
      Application.Ena bleVisualStyles ();
      using (Form f = new SomeForm()) {
      Application.Run (f);
      }
      }

      Button goStop;
      BackgroundWorke r worker;
      const string BUTTON_TEXT = "Go";
      protected override void OnLoad(EventArg s e) {
      base.OnLoad(e);
      goStop = new Button();
      goStop.Text = BUTTON_TEXT;
      goStop.Click += new EventHandler(go Stop_Click);
      Controls.Add(go Stop);
      worker = new BackgroundWorke r();
      worker.WorkerSu pportsCancellat ion = true;
      worker.WorkerRe portsProgress = true;
      worker.DoWork+= new DoWorkEventHand ler(worker_DoWo rk);
      worker.Progress Changed += new
      ProgressChanged EventHandler(wo rker_ProgressCh anged);
      worker.RunWorke rCompleted += new
      RunWorkerComple tedEventHandler (worker_RunWork erCompleted);
      }

      void worker_RunWorke rCompleted(obje ct sender,
      RunWorkerComple tedEventArgs e) {
      goStop.Text = BUTTON_TEXT;
      if (e.Cancelled) {
      this.Text = "cancelled" ;
      } else if ((int) e.Result == 0) {
      this.Text = "complete";
      } else {
      this.Text = "error " + e.Result.ToStri ng();
      }
      }

      void worker_Progress Changed(object sender,
      ProgressChanged EventArgs e) {
      goStop.Text = e.ProgressPerce ntage.ToString( ) + "%";
      }

      void goStop_Click(ob ject sender, EventArgs e) {
      if (worker.IsBusy) {
      worker.CancelAs ync();
      } else {
      worker.RunWorke rAsync();
      }
      }

      void worker_DoWork(o bject sender, DoWorkEventArgs e)
      {
      string exe = @"c:\walker.exe ", root = @"c:\develop\t" ;
      ProcessStartInf o psi = new ProcessStartInf o(exe, root);
      psi.UseShellExe cute = false;
      psi.RedirectSta ndardOutput = true;
      psi.CreateNoWin dow = true;
      using(Process proc = Process.Start(p si))
      using(StreamRea der reader = proc.StandardOu tput) {
      worker.ReportPr ogress(0);
      Regex re = new Regex(@"\d{1,3} %");
      int index = 0;
      while (!reader.EndOfS tream) {
      if (worker.Cancell ationPending) {
      proc.Kill();
      e.Cancel = true;
      break;
      }
      string line = reader.ReadLine ();
      if (re.IsMatch(lin e)) {

      worker.ReportPr ogress(int.Pars e(line.TrimEnd( '%')));
      } else {
      if (index++ % 20 == 0) {
      this.Invoke((Me thodInvoker)del egate {
      this.Text = line;
      });
      }
      }
      }
      if (!e.Cancel) {
      e.Result = proc.ExitCode;
      }

      }
      }
      }

      Comment

      • Alistair George

        #4
        Re: Console app async control

        Marc Gravell wrote:
        >
        I'll put an example together if you like...
        >
        Marc
        >
        Thank you so much Marc. You have made the task very easy for me to
        implement. On the few google results that I have read on the subject, it
        is indicated that getting the output from the CMD window is unreliable
        to say the least. This is a problem that the previous implimentation
        had. So it will be interesting to see how well it works if you like I
        will stay in touch.

        Am trying to improve a situation whereby the previous method used to
        occasionally hang when they used the cmd output. I am not sure whether
        they used sync or async comms in that case.
        Thanks again, Al.

        Comment

        • Marc Gravell

          #5
          Re: Console app async control

          I did some more playing with this, and it looks like (irritatingly) in
          the event of a hang, the Begin... approach is more stable... sorry to
          confuse things! I'll see if I can get that working...

          Marc

          Comment

          • Alistair George

            #6
            Re: Console app async control

            Marc Gravell wrote:
            I did some more playing with this, and it looks like (irritatingly) in
            the event of a hang, the Begin... approach is more stable... sorry to
            confuse things! I'll see if I can get that working...
            >
            Marc
            >
            OK, but are you saying that the method can hang due to comms problems?

            Comment

            • Chris Dunaway

              #7
              Re: Console app async control

              On Sep 10, 2:25 pm, Alistair George <non...@xtra.co .nzwrote:
              Marc Gravell wrote:
              I did some more playing with this, and it looks like (irritatingly) in
              the event of a hang, the Begin... approach is more stable... sorry to
              confuse things! I'll see if I can get that working...
              >
              Marc
              >
              OK, but are you saying that the method can hang due to comms problems?
              Be careful when redirecting both standard output and standard error as
              there can be a deadlock issue. Check the docs which give some more
              details about this issue.

              Chris

              Comment

              • Alistair George

                #8
                Re: Console app async control

                Chris Dunaway wrote:
                On Sep 10, 2:25 pm, Alistair George <non...@xtra.co .nzwrote:
                >Marc Gravell wrote:
                >>I did some more playing with this, and it looks like (irritatingly) in
                >>the event of a hang, the Begin... approach is more stable... sorry to
                >>confuse things! I'll see if I can get that working...
                >>Marc
                >OK, but are you saying that the method can hang due to comms problems?
                >
                Be careful when redirecting both standard output and standard error as
                there can be a deadlock issue. Check the docs which give some more
                details about this issue.
                >
                Chris
                >
                Thanks Chris.
                Mark did you want to go any further or shall I proceed with caution
                using the code that you promulgated?
                Cheers,
                Alistair.

                Comment

                Working...