ProcessInfo и RedirectStandardOutput

У меня есть приложение, которое вызывает другой процесс в командном окне, и этот процесс обновляет статистику, которая выводится в окно консоли. Я думал, что это довольно простая операция, но я не могу заставить ее работать. Я что-то пропустил?

string assemblyLocation = Assembly.GetExecutingAssembly().Location;

Process process = new Process
{
    ProcessStart =
    {
        RedirectStandardOutput = true,
        UseShellExecute = false,
        WindowStyle = ProcessWindowStyle.Hidden,
        Arguments = arg,
        FileName = assemblyLocation.Substring(0, assemblyLocation.LastIndexOf("\\")) + "\\ffmpeg.exe",
        CreateNoWindow = true
    }
};

process.Start();

Console.WriteLine(process.StandardOutput.ReadToEnd());

process.WaitForExit();

В идеале мне бы хотелось, чтобы выходной сигнал изменялся в процессе, который я нажимал, или данные поступали в считыватель, и я получал от него события.

Любая помощь была бы отличной, я чувствую, что это вопрос новичка, но, похоже, что-то упустил.

6 ответов

Решение

Я испытал это раньше. Иногда способ, которым вызываемый вами процесс выводит данные на консоль, несовместим с таким перенаправлением вывода. Мне повезло, что я смог изменить внешний процесс, чтобы обойти это.

Вы можете попробовать запустить свой код в другом процессе, который выводит на консоль, и посмотреть, работает ли он правильно. Это читает прямо сейчас для меня.

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

Я пошел и вытащил блок кода, который я использовал для этого. Это в приложении WPF, которое перенаправляет вывод процесса в окно. Обратите внимание на привязку события. Поскольку это WPF, я должен вызвать мой вызов для записи данных. Поскольку вы не беспокоитесь о блокировке, вы можете просто заменить это на:

Console.WriteLine(e.Data);

Надеюсь, это поможет!

    private static void LaunchProcess()
    {
        Process build = new Process();
        build.StartInfo.WorkingDirectory =  @"dir";
        build.StartInfo.Arguments = "";
        build.StartInfo.FileName = "my.exe";

        build.StartInfo.UseShellExecute = false;
        build.StartInfo.RedirectStandardOutput = true;
        build.StartInfo.RedirectStandardError = true;
        build.StartInfo.CreateNoWindow = true;
        build.ErrorDataReceived += build_ErrorDataReceived;
        build.OutputDataReceived += build_ErrorDataReceived;
        build.EnableRaisingEvents = true;
        build.Start();
        build.BeginOutputReadLine();
        build.BeginErrorReadLine();
        build.WaitForExit();
    }

    // write out info to the display window
    static void build_ErrorDataReceived(object sender, DataReceivedEventArgs e)
    {
        string strMessage = e.Data;
        if (richTextBox != null && !String.Empty(strMessage))
        {
            App.Instance.Dispatcher.BeginInvoke(DispatcherPriority.Send, (ThreadStart)delegate()
            {
                Paragraph para = new Paragraph(new Run(strMessage));
                para.Margin = new Thickness(0);
                para.Background = brushErrorBrush;
                box.Document.Blocks.Add(para);
            });
       }
    } 

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

ProcessStartInfo info = new ProcessStartInfo(...)
info.UseShellExecute = false;
info.RedirectStandardOutput = true;
info.RedirectStandardError = true;

Process p = Process.Start(info);
p.OutputDataReceived += p_OutputDataReceived;
p.ErrorDataReceived += p_ErrorDataReceived;

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

..

void p_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
  Console.WriteLine("Received from standard out: " + e.Data);
}

void p_ErrorDataReceived(object sender, DataReceivedEventArgs e)
{
  Console.WriteLine("Received from standard error: " + e.Data);
}

См. Событие OutputDataReceived off Process для получения дополнительной информации.

Использование лямбда-выражений и т.д.:

var info = new ProcessStartInfo(path)
{
    RedirectStandardError = true,
    RedirectStandardOutput = true,
    UseShellExecute = false,
    Verb = "runas",
};

var process = new Process
{
    EnableRaisingEvents = true,
    StartInfo = info
};

Action<object, DataReceivedEventArgs> actionWrite = (sender, e) =>
{
    Console.WriteLine(e.Data);
};

process.ErrorDataReceived += (sender, e) => actionWrite(sender, e);
process.OutputDataReceived += (sender, e) => actionWrite(sender, e);

process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
process.WaitForExit();

Интересно, что вы не можете читать из стандартного вывода и стандартной ошибки одновременно:

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

[C#]

строка output = p.StandardOutput.ReadToEnd ();

string error = p.StandardError.ReadToEnd ();

p.WaitForExit ();

В этом случае, если дочерний процесс записывает какой-либо текст в стандартную ошибку, он блокирует процесс, потому что родительский процесс не может прочитать стандартную ошибку, пока не завершит чтение из стандартного вывода. Однако родительский процесс не будет читать из стандартного вывода, пока процесс не завершится. Рекомендуемое решение этой ситуации - создать два потока, чтобы ваше приложение могло читать выходные данные каждого потока в отдельном потоке.

http://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo.redirectstandardoutput(v=vs.71).aspx

Текущий код работал в VS2010

void OnOutputDataReceived(object sender, DataReceivedEventArgs e)
    {
        if (String.IsNullOrEmpty(e.Data) == false)
        {
            new Thread(() =>
            {
                this.Dispatcher.Invoke(new Action(() =>
                {
                    // Add you code here
                }));
            }).Start();
        }
    }

Убедитесь, что ожидаемый вывод не отправляется на выход StandardError вместо вывода StandardOutput

Другие вопросы по тегам