Чтение вывода из другого запущенного приложения

Я работаю над пользовательской IDE на C# для языка сценариев, и у меня возникла проблема.

Я пытаюсь запустить процесс компиляции (pawncc.exe) и передать ему аргументы. Я сделал это, и теперь у меня есть проблема. Когда я хочу отобразить вывод приложения-компилятора, он отображает только некоторые его части. Он должен вывести это (получил из командной строки):

Pawn compiler 3.2.3664                  Copyright (c) 1997-2006, ITB CompuPhase

newGM.pwn(0) : fatal error 100: cannot read from file: "includes/main_include.inc"

Compilation aborted.
1 Error.

Но это не так. Он выводит это (в приложении, используя ту же команду/аргументы):

Pawn compiler 3.2.3664          Copyright (c) 1997-2006, ITB CompuPhase


1 Error.

Я просто не понимаю! Это действительно странно. Это может быть что-то простое, но я смотрю на это и исследую уже несколько часов! Вот мой код:

        public Form3(string path)
        {
            InitializeComponent();

            this._path = path;

            Process myProcess = new Process();
            ProcessStartInfo startInfo = new ProcessStartInfo("pawncc.exe");
            startInfo.CreateNoWindow = true;
            startInfo.UseShellExecute = false;
            startInfo.RedirectStandardOutput = true;
            startInfo.Arguments = path + " -r -d2";
            myProcess.StartInfo = startInfo;
            myProcess.Start();

            while (true)
            {
                string myString;
                byte[] buffer = new byte[512];
                var ar = myProcess.StandardOutput.BaseStream.BeginRead(buffer, 0, 512, null, null);
                ar.AsyncWaitHandle.WaitOne();
                var bytesRead = myProcess.StandardOutput.BaseStream.EndRead(ar);
                if (bytesRead > 0)
                {
                    myString = Encoding.ASCII.GetString(buffer, 0, bytesRead);
                }
                else
                {
                    myProcess.WaitForExit();
                    break;
                }
                richTextBox1.Text = myString;

            }

        }

!! РЕДАКТИРОВАТЬ:

Он делает то же самое с этим кодом:

        public Form3(string path)
        {
            InitializeComponent();

            this._path = path;

            Process myProcess = new Process();
            ProcessStartInfo startInfo = new ProcessStartInfo("pawncc.exe");
            startInfo.CreateNoWindow = true;
            startInfo.UseShellExecute = false;
            startInfo.RedirectStandardOutput = true;
            startInfo.RedirectStandardError = true;
            startInfo.Arguments = path + " -r -d2";
            myProcess.StartInfo = startInfo;
            myProcess.Start();

            using (StreamReader reader = myProcess.StandardOutput)
            {
                string result = reader.ReadToEnd();
                richTextBox1.Text = result;
            }
        }

person Quin Schurman    schedule 02.01.2013    source источник
comment
Я только что задал похожий вопрос пару дней назад. Краткая версия ответа заключается в том, что обработка событий данных (myProcess.OutputDataReceived и myProcess.ErrorDataReceived ) намного надежнее, чем использование методов синхронного чтения.   -  person psubsee2003    schedule 02.01.2013


Ответы (3)


Вам также необходимо перенаправить стандартный поток ошибок:

startInfo.RedirectStandardError = true;

Изменить: я только что просмотрел код и обнаружил, что вы только для чтения потока StandardOutput.

Обычно я отслеживаю процесс как для стандартных потоков вывода, так и для потоков ошибок, используя события DataReceived в процессе и добавляя результаты в построитель строк, а затем сохраняя содержимое StringBuilder в элементе пользовательского интерфейса:

    private static System.Text.StringBuilder m_sbText;

    public Form3(string path)
    {
        InitializeComponent();

        this._path = path;

        Process myProcess = new Process();
        ProcessStartInfo startInfo = new ProcessStartInfo("pawncc.exe");
        startInfo.CreateNoWindow = true;
        startInfo.UseShellExecute = false;
        startInfo.RedirectStandardOutput = true;
        startInfo.RedirectStandardError = true;
        startInfo.Arguments = path + " -r -d2";
        myProcess.StartInfo = startInfo;

        m_sbText = new System.Text.StringBuilder(1000);

        myProcess.OutputDataReceived += ProcessDataHandler;
        myProcess.ErrorDataReceived += ProcessDataHandler;

        myProcess.Start();

        myProcess.BeginOutputReadLine();
        myProcess.BeginErrorReadLine();

        while (!myProcess.HasExited)
        {
            System.Threading.Thread.Sleep(500);
            System.Windows.Forms.Application.DoEvents();
        }
        RichTextBox1.Text = m_sbText.ToString();
    }

    private static void ProcessDataHandler(object sendingProcess, DataReceivedEventArgs outLine)
    {
        // Collect the net view command output. 
        if (!String.IsNullOrEmpty(outLine.Data))
        {
            // Add the text to the collected output.
            m_sbText.AppendLine(outLine.Data);
        }
    }

Очевидно, есть вариации на этот счет, но это должно помочь вам начать.

person competent_tech    schedule 02.01.2013
comment
@QuinSchurman: я только что понял, что вы отслеживаете только поток StandardOutput. Я обновил ответ, чтобы показать использование событий процесса для получения входящих данных, что, я думаю, намного проще в использовании. - person competent_tech; 02.01.2013
comment
Большое спасибо! Это сработало. Отмечено как ответ. Также спасибо за быстрый ответ. - person Quin Schurman; 02.01.2013
comment
Итак, я использовал этот код - он работает хорошо, но я хотел бы расширить его, разделив вывод и отсортировав их в список. Например, я мог поместить ошибки с номерами строк в список в пользовательском интерфейсе, чтобы упростить чтение вывода. Лучший пример: измените это newGM.pwn(0) : fatal error 100: cannot read from file: "includes/main_include.inc" на это (на вкладке newGM, прикрепленный список внизу.) Errors: %i. error id 100: (FATAL!) file "includes/main_include.inc" is missing or unreadable. - person Quin Schurman; 03.01.2013
comment
Есть два вызова Process.Start. - person Lii; 30.03.2015

У меня нет приложения pawnCC, поэтому я не могу попробовать, но, похоже, они ограничивают многословность отладочной информации внешними приложениями, кроме командной строки.

Можете попробовать запустить pawncc.exe через cmd:

"cmd.exe \c CommandParameterToLaunchPawnCCwithArguments"
person Jeremy Thompson    schedule 02.01.2013
comment
Неплохая идея, так как это даст вам необработанный вывод - person JerKimball; 02.01.2013

Я заметил некоторые спорадические проблемы при работе с необработанными потоками вывода/ошибок из порожденных процессов в прошлом, поэтому я обычно имею дело с захваченным выводом через обработку событий:

Process myProcess = new Process();
ProcessStartInfo startInfo = new ProcessStartInfo("pawncc.exe");
startInfo.CreateNoWindow = true;
startInfo.UseShellExecute = false;
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardError = true;
startInfo.Arguments = path + " -r -d2";
myProcess.EnableRaisingEvents = true;
myProcess.OutputDataReceived += OnOutputDataReceived;
myProcess.ErrorDataReceived += OnErrorDataReceived;
myProcess.StartInfo = startInfo;
myProcess.Start();
myProcess.BeginOutputReadLine();
myProcess.BeginErrorReadLine(); 
person JerKimball    schedule 02.01.2013
comment
Это не объясняет, почему некоторые выходные данные извлекаются, но не ошибка. - person Jeremy Thompson; 02.01.2013
comment
@JeremyThompson Верно, но я заметил некоторые спорадические проблемы при работе с необработанными потоками вывода / ошибок из порожденных процессов (processii?) в прошлом, отсюда и предложение (и включение элементов StandardError) - person JerKimball; 02.01.2013
comment
+1 честное слово, возможно, добавьте это в свой ответ I've noticed some sporadic issues when dealing with the raw output/error streams from spawned processes in the past, hence my suggestion to hook up the StandardError events. - person Jeremy Thompson; 02.01.2013