WaitforExit doesn't work correctly

user1158745 picture user1158745 · Feb 9, 2012 · Viewed 16.6k times · Source

So I have been battling this issue for awhile now and tried many different ways to fix it but cannot.

Bascally waht my app does is calls a java file to load an application on a device. While it's loading it's printing it to a richtext box, then I would like to move on to the next file. The problem I am having is that while the first file is being loaded, the 2nd tries to load which cases issues. I have tried the wait for exit but if I do that, then the output data doesn't get written to the rich text box. Any ideas?

private void btnLoad_Click(object sender, EventArgs e)
    {
        rchsdtOut.Clear();
        //count the items in queue.
        var count = lstBarToLoad.Items.Count;

        if (count <= 0)
        {
            MessageBox.Show("Nothing added to the load queue");
       }
        else
       {

            String toLoad;
            for (int i=0; i < count;i++)
              {//START OF FOREACH
                 toLoad = lstBarToLoad.Items[i].Text;
                //call load method.
                  loaddPB(toLoad);      
              }//end of for.
        }//end of else.
    }//end of private

I tried putting the wait for exit in many different places, but it doesn't seem to work.

     //Method to load files on device.
    private void loaddPB(string toLoad)
    {

        process1 = new System.Diagnostics.Process();
        process1.StartInfo.UseShellExecute = false;
        process1.StartInfo.RedirectStandardOutput = true;
        process1.StartInfo.RedirectStandardError = true;
        process1.StartInfo.CreateNoWindow = true;
        process1.StartInfo.FileName = "java.exe ";

        process1.StartInfo.Arguments = "-Xmx512M -jar";
        process1.StartInfo.Arguments += toLoad;
        try
        {

                 process1.Start();
                 process1.OutputDataReceived += (s, a) => myMethod(a);
                 process1.BeginOutputReadLine();
                 process1.ErrorDataReceived += (s, a) => myErrorMethod(a);
                 process1.BeginErrorReadLine();

                 process1.WaitForExit();
        }
        catch
        {
            Console.WriteLine("error");
        }

    }

Two methods below write the stdout or error to the richtext field.

        //Method to do the logging.
    private void myMethod(DataReceivedEventArgs e)
    {

            if (e.Data != null)
            {
                Action action = () => rchsdtOut.Text += "\r\n" + e.Data.ToString();
                rchsdtOut.BeginInvoke(action, null);
                Console.WriteLine(e.Data.ToString());
            }

    }//end of private

    //Method to load the error if any thrown.
    private void myErrorMethod(DataReceivedEventArgs e)
    {
        if (e.Data != null)
        {
            Action action = () => rchsdtOut.Text += "\r\n" + e.Data.ToString();
            rchsdtOut.BeginInvoke(action, null);
            Console.WriteLine(e.Data.ToString());

        }
    }//end of private

Any ideas would be great. Bascally I need the process to exit, so then I can continue thought the forloop to load the next file.

Answer

Jason Williams picture Jason Williams · Feb 9, 2012

If you WaitForExit, your application blocks (waits) until the process exits. This means it is unable to process any Windows messages in its UI thread, so it doesn't update the UI.

You need to start the process "in the background" so your UI continues to refresh. This can be done with:

  • Start and monitor the process from a separate thread, and pass progress information back to the UI thread for display
  • Add an event handler to the process exited event, or periodically poll the process.HasExited flag, and use this to know when the first process has finished. Your event handler would start this process off and then exit back to your main application loop so that it runs as normal while waiting for the external process to finish.
  • Sit in a busy wait loop until it completes, and process application events. (Beware of this, as any events that cause reentrant calls to this code could do very bad things. Generally if you use this approach you nee dto make sure that the rest of your application is "locked down" in a state where it knows it is busy waiting for a process to complete). THis is effectively what WaitForExit does, but it also processes application events, allowing the UI to remain vaguely responsive:

    while (!process.HasExited)  
    {  
        Application.DoEvents();  
        Thread.Sleep(100);  
    }