1

is there a way to indicate if a process like standard calculator got an output or not,
i need it because i have this line :

sr = p1.StandardOutput;  

and i need to do this :

s = sr.ReadLine();  

only if there's an output from p1 in calculator for example there's no output so the program stuck after the ReadLine.
thanks all.

the code :

while (i < asProcesses.Length - 1)
            {
                if ((i + 1) == asProcesses.Length - 1 && sOutRedirect != "")
                    break;
                p1.StartInfo.RedirectStandardOutput = true;
                p1.StartInfo.FileName = asProcesses[i];
                p1.StartInfo.UseShellExecute = false;
                if(i==0)
                    p1.Start();
                sr = p1.StandardOutput;
                Process p2 = new Process();
                p2.StartInfo.RedirectStandardInput = true;
                p2.StartInfo.FileName = asProcesses[i + 1];
                p2.StartInfo.UseShellExecute = false;
                p2.Start();
                sw = p2.StandardInput;
                while (!sr.EndOfStream && s != null)
                {
                    s = sr.ReadLine();
                    if (s != null)
                    {
                        sw.WriteLine(s);
                    }
                }
                if (sw != null)
                    sw.Close();
                if (sr != null)
                    sr.Close();
                i++;
            }
Roy Gavrielov
  • 607
  • 4
  • 10
  • 22
  • I posted a few comments on a similar question that may be relevant: [Execute Process Chain](http://stackoverflow.com/questions/5170273/execute-process-chain) – Tamschi Mar 03 '11 at 01:46

2 Answers2

1
void foo()
{
    System.Diagnostics.Process p = new System.Diagnostics.Process();
    p.StartInfo.FileName = "c:\\windows\\system32\\ping.exe";
    p.StartInfo.RedirectStandardOutput = true;
    p.StartInfo.UseShellExecute = false;
    p.EnableRaisingEvents = true;
    p.OutputDataReceived += new System.Diagnostics.DataReceivedEventHandler(p_OutputDataReceived);
    p.Start();
    p.BeginOutputReadLine();
}           

void p_OutputDataReceived(object sender, System.Diagnostics.DataReceivedEventArgs e)
{
    string s = e.Data;        
    // process s
}
Jack B Nimble
  • 5,039
  • 4
  • 40
  • 62
0

If all processes exit after executing, use this instead of the inner while:

p1.WaitForExit();
sw.Write(sr.ReadToEnd());

If you want the processes to time out:

int i = 0;
while (!p1.HasExited && i < maxWaits)
{
    Thread.Sleep(delay);
    i++;
}
sw.Write(sr.ReadToEnd());

//Kill process if running:
if (!p1.HasExited)
{
    try { p1.Kill(); }
    catch { }
}

Edit:

It seems you're trying to chain the output from each process to the next one. If that's the case, you're missing a p1 = p2 at the end of the loop.
Also, consider to move the first starting process out of the loop: It will make your code much more readable. Setting p1's StartInfo should be moved into the if (i == 0) block if you leave it this way. Moving the output read last process out wouldn't be a bad idea either, in my opinion...

Edit:

This is my solution (with timing out):

        int maxWaits = 10; // Wait 1 second at most.
        int delay = 100;

        var p = new Process();
        p.StartInfo.RedirectStandardOutput = true;
        p.StartInfo.FileName = asProcesses[0];
        p.StartInfo.UseShellExecute = false;
        p.Start();

        foreach (var path in asProcesses.Skip(1))
        {
            var p2 = new Process();
            p2.StartInfo.FileName = path;
            p2.StartInfo.RedirectStandardInput = true;
            p2.StartInfo.RedirectStandardOutput = true;
            p2.StartInfo.UseShellExecute = false;

            {
                int i = 0;
                while (!p.HasExited && i < maxWaits)
                {
                    p2.StandardInput.Write(p.StandardOutput.ReadToEnd()); //Redirect IO. This line means that the second process can start calculations if the first is long-running and writes its output progressively.
                    Thread.Sleep(delay);
                    i++;
                }
            }

            p2.StandardInput.Write(p.StandardOutput.ReadToEnd()); //Redirect last output from p.

            {
                //Kill process if still running:
                if (!p.HasExited)
                {
                    try { p.Kill(); }
                    catch { }
                }
            }
        }

        {
            int i = 0;
            while (!p.HasExited && i < maxWaits)
            {
                Thread.Sleep(delay);
                i++;
            }
        }

        string result = p.StandardOutput.ReadToEnd();
        {
            if (!p.HasExited)
            {
                try { p.Kill(); }
                catch { }
            }
        }

Edit:

Algorithm that waits for each process to exit:

        var p = new Process();
        p.StartInfo.RedirectStandardOutput = true;
        p.StartInfo.FileName = asProcesses[0];
        p.StartInfo.UseShellExecute = false;
        p.Start();

        foreach (var path in asProcesses.Skip(1))
        {
            var p2 = new Process();
            p2.StartInfo.FileName = path;
            p2.StartInfo.RedirectStandardInput = true;
            p2.StartInfo.RedirectStandardOutput = true;
            p2.StartInfo.UseShellExecute = false;

            p.WaitForExit();
            p2.StandardInput.Write(p.StandardOutput.ReadToEnd());
        }

        p.WaitForExit();
        string result = p.StandardOutput.ReadToEnd();

I moved the first process out of the loop to get rid of the conditional. The control flow is simpler this way and it's easier to add code affection the first process specifically.

Tamschi
  • 1,089
  • 7
  • 23
  • thanks for the answer, you're right i'm trying to implement piping, and i don't want to kill any process. for example, if the command is calc|calc|calc - the calculator should be opened 3 times – Roy Gavrielov Mar 02 '11 at 20:50