Metoda WaitForExit() w klasie Proscess blokuje działaanie programu

0

Próbuję przechwycić wyjście standardowe aplikacji konsolowej. Wywołanie metody WaitForExit() blokuje działanie programu i nic się nie wyświetla w "richTextBox1". Jak usunę wywołanie tej metody to wtedy wszystko działa. Jednak zależy mi na użyciu WaitForExit();

private void button1_Click(object sender, EventArgs e)
{
    process1.StartInfo.FileName = "cmd.exe";
    process1.StartInfo.Arguments = "/?";

    process1.Start();
    process1.BeginOutputReadLine();
    process1.BeginErrorReadLine();

    process1.WaitForExit();
}

private void process1_OutputDataReceived(object sender, System.Diagnostics.DataReceivedEventArgs e)
{
    richTextBox1.Text += e.Data + "\n";
}

private void process1_ErrorDataReceived(object sender, System.Diagnostics.DataReceivedEventArgs e)
{
    richTextBox1.Text += e.Data + "\n";
}
0

W dokumentacji dla metody Process.WaitForExit jest napisane, że wątek będzie czekał na zakończenie tego procesu. Wywołując cmd.exe /? na końcu pojawia się "Press any key to continue...". Proces nie zakończy działania do czasu naciśnięcia dowolnego przycisku.

Fragment z dokumentacji:
"WaitForExit() makes the current thread wait until the associated process terminates."

0

Napisałem program testowy

namespace test
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("OK");
        }
    }
}

Gdy wywołuję test.exe też się blokuje

0

Taki kod działa i WaitForExit() nie blokuje programu. Ten komunikat na końcu "Press any key to continue..." jednak nie blokuje.

       public static void Main(string[] args)
       {
            var p = new Process
            {
                StartInfo =
                {
                    RedirectStandardError = true,
                    RedirectStandardOutput = true,
                    UseShellExecute = false,
                    FileName = "cmd.exe",
                    Arguments = "/?"
                }
            };

            p.OutputDataReceived += OutputDataReceived;
            p.ErrorDataReceived += ErrorDataReceived;

            p.Start();

            p.BeginOutputReadLine();
            p.BeginErrorReadLine();

            p.WaitForExit();
        }

        private static void OutputDataReceived(object sender, DataReceivedEventArgs e)
        {
            if (string.IsNullOrEmpty(e.Data)) return;

            Console.WriteLine(e.Data);
        }

        private static void ErrorDataReceived(object sender, DataReceivedEventArgs e)
        {
            if (string.IsNullOrEmpty(e.Data)) return;

            Console.WriteLine(e.Data);
        }           
0

Poniższy kod działa:

using System;
using System.Windows.Forms;

namespace DISMassistant
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            process1.StartInfo.RedirectStandardError = true;
            process1.StartInfo.RedirectStandardOutput = true;
            process1.StartInfo.UseShellExecute = false;
            process1.StartInfo.FileName = "cmd.exe";
            process1.StartInfo.Arguments = "/?";

            process1.Start();

            process1.BeginOutputReadLine();
            process1.BeginErrorReadLine();

            process1.WaitForExit();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            MessageBox.Show("OK");
        }

        private void process1_OutputDataReceived(object sender, System.Diagnostics.DataReceivedEventArgs e)
        {
            if (string.IsNullOrEmpty(e.Data)) return;
            richTextBox1.Text += e.Data + "\n";
        }

        private void process1_ErrorDataReceived(object sender, System.Diagnostics.DataReceivedEventArgs e)
        {
            if (string.IsNullOrEmpty(e.Data)) return;
            richTextBox1.Text += e.Data + "\n";
        }
    }
}

Ale jak przeniosę poniższy fragment do metody "button1_Click" to program się zawiesza

process1.Start();

process1.BeginOutputReadLine();
process1.BeginErrorReadLine();

process1.WaitForExit();
0

W twoim kodzie brakuje:
process1.OutputDataReceived += process1_OutputDataReceived;
process1.ErrorDataReceived += process1_ErrorDataReceived;
oraz
private Process process1 = new Process();

Po dodaniu tych linijek i uruchomieniu nie udało mi się powtórzyć problemu.
Jedynie w trybie debug próbuje modyfikować RichTextBoxa z innego wątku. Tutaj jest opis jak to poprawić w takim przypadku:
https://docs.microsoft.com/en[...]-controls?redirectedfrom=MSDN

0

Ja korzystam z Visual Studio Express 2017. Aplikacja jest typu Windows Forms. Wyszczególnione przez ciebie linijki są w kodzie, tylko w innym pliku. Zostały one dodane automatycznie poprzez przeciągnięcie kontrolki do formularza. Poza tym przechwycenie wyjścia standardowego działa jak jego obsługa jest umieszczona bezpośrednio w konstruktorze klasy "Form1". A nie działa w wywołaniu metody "button1_Click"

0

Wczoraj stworzyłem też aplikacje Windows Forms i na tej aplikacji sprawdzałem to.

Mógłbyś podesłać cały projekt to sprawdzę na nim?

0

Taki kod działa (w załączniku). Tylko je chcę, aby to się odbyło po przyciśnięciu "Button1"

0

Zatrzymuje się przez to (jest to w Form1.Designer.cs): this.process1.SynchronizingObject = this;
Usunięcie tego albo process1.WaitForExit() nie powoduje blokowania programu.

Po usunięciu this.process1.SynchronizingObject z innego wątku będzie próbował modyfikować RichTextBoxa. W poprzednim komentarzu wrzuciłem link do dokumentacji, musisz użyć metody Invoke.
Po usunięciu process1.WaitForExit() działa dobrze (widać jedynie odświeżenie tekstu jak dodaje nowe linie z tekstem do RichTextBoxa).

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0