user1522008
user1522008

Reputation: 171

I am trying to read the output of a process in c# but I get this message "Cannot mix synchronous and asynchronous operation on process stream."

I am writing a backup program using xcopy and because there are a lot of large files it takes a while so I want to show the progress. When I try to use StreamReader to get the standard output, it has this error message when I debug. "Cannot mix synchronous and asynchronous operation on process stream."

  public void backup_worker_DoWork(object sender, DoWorkEventArgs e)
    {
        int loop = 1;

        backup_worker.WorkerReportsProgress = true;

        Process xcopy = new Process();
        ProcessStartInfo startinfo = new ProcessStartInfo();
        startinfo.CreateNoWindow = true;
        startinfo.UseShellExecute = false;
        startinfo.RedirectStandardError = true;
        startinfo.RedirectStandardOutput = true;
        startinfo.FileName = Environment.CurrentDirectory + "\\xcopy.exe";
        startinfo.Arguments = '"' + source + '"' + " " + '"' + target + '"' + " " + "/s /e /y";
        xcopy.StartInfo.RedirectStandardOutput = true;
        xcopy.StartInfo = startinfo;

        xcopy.Start();
        xcopy.BeginErrorReadLine();
        xcopy.BeginOutputReadLine();

        StreamReader sr = xcopy.StandardOutput;

        while (loop > 0)
        {
            progress = sr.ReadLine();
            output_list.Items.Add(progress);
        }

        xcopy.OutputDataReceived += new DataReceivedEventHandler(backup_worker_OutputDataRecieved);
        xcopy.ErrorDataReceived += new DataReceivedEventHandler(backup_worker_ErrorDataReceived);
        xcopy.WaitForExit();
        backup_worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backup_worker_RunWorkerCompleted);
    }

    void backup_worker_ErrorDataReceived(object sender, DataReceivedEventArgs e)
    {

    }

    void backup_worker_OutputDataRecieved(object sender, DataReceivedEventArgs e)
    {
    }

    void backup_worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        MessageBox.Show("Completed");
    }

Please help. Thanks in advance

Upvotes: 17

Views: 21042

Answers (3)

IDK
IDK

Reputation: 188

The below note from MSDN should make it very clear, what the problem is

You cannot mix asynchronous and synchronous read operations on a redirected stream. Once the redirected stream of a Process is opened in either asynchronous or synchronous mode, all further read operations on that stream must be in the same mode. For example, do not follow BeginErrorReadLine with a call to ReadLine on the StandardError stream, or vice versa. However, you can read two different streams in different modes. For example, you can call BeginErrorReadLine and then call ReadLine for the StandardOutput stream.

Your code should be more on the lines as below



    public void backup_worker_DoWork(object sender, DoWorkEventArgs e) {
        int loop = 1;

        // This should ideally not be in the DoWork, but where you setup or create the worker
        backup_worker.WorkerReportsProgress = true;
        backup_worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backup_worker_RunWorkerCompleted);
        backup_worker.WorkerSupportsCancellation = true;

        // setup your scopy process
        ProcessStartInfo startinfo = new ProcessStartInfo();
        startinfo.CreateNoWindow = true;
        startinfo.UseShellExecute = false;
        startinfo.RedirectStandardError = true;
        startinfo.RedirectStandardOutput = true;
        startinfo.FileName = Environment.CurrentDirectory + "\\xcopy.exe";
        startinfo.Arguments = "/s /e /y " + '"' + source + '"' + " " + '"' + target + '"' + " ";
        Process xcopy = new Process();
        xcopy.StartInfo = startinfo;
        xcopy.ErrorDataReceived += new DataReceivedEventHandler(backup_worker_ErrorDataReceived);

        // start the xcopy and read the output
        xcopy.Start();
        xcopy.BeginErrorReadLine();

        string copiedFileName;
        while ((copiedFileName = xcopy.StandardOutput.ReadLine()) != null) {
            output_list.Items.Add(copiedFileName);
        }

        // we should be done when here, but doesen't hurt to wait
        xcopy.WaitForExit();
    }

    void backup_worker_ErrorDataReceived(object sender, DataReceivedEventArgs e) {
        MessageBox.Show("We have a problem. Figure what needs to be done here!");
    }

    void backup_worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        if (e.Cancelled == true) {
            MessageBox.Show("Canceled!");
        } else if (e.Error != null) {
            MessageBox.Show("Error: " + e.Error.Message);
        } else {
            MessageBox.Show("Completed!");
        }
    }

Upvotes: 8

If you want to do the synchronous way,

instead of

xcopy.BeginOutputReadLine()

use

string s = xcopy.StandardOutput.ReadToEnd()

be warned, that if you do that for both the output and the error, and one of them is too long, you can hit a deadlock.

Upvotes: 3

Reed Copsey
Reed Copsey

Reputation: 564413

The problem is that you're using both synchronous and asynchronous output:

// Using async version here...
xcopy.BeginOutputReadLine();


StreamReader sr = xcopy.StandardOutput;

while (loop > 0)
{
    // Trying to use synchronous reading here
    progress = sr.ReadLine();

You need to design your algorithm to use one option or the other, but not both.

Upvotes: 19

Related Questions