Перенаправить вывод (stdout, stderr) дочернего процесса в окно вывода в Visual Studio - PullRequest
14 голосов
/ 04 сентября 2010

В данный момент я запускаю командный файл из моей программы на C #:

System.Diagnostics.Process.Start(@"DoSomeStuff.bat");

Я бы хотел иметь возможность перенаправить вывод (stdout и stderr) этого дочернего процесса в окно вывода в Visual Studio (в частности, в Visual C # Express 2008).

Есть ли способ сделать это?

(Дополнительно: так, что не все буферизируются, а затем выплевываются в окно вывода после завершения дочернего процесса.)


(Кстати: на данный момент я могу получить стандартный вывод (но не stderr) процесса parent в окне «Вывод»), сделав мою программу «Приложение Windows» вместо «Консольное приложение Msgstr "Это ломается, если программа запускается вне Visual Studio, но это нормально в моем конкретном случае.)

Ответы [ 4 ]

22 голосов
/ 04 сентября 2010
process.StartInfo.CreateNoWindow = true;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.OutputDataReceived += (sender, args) => Console.WriteLine(args.Data);
process.Start();
process.BeginOutputReadLine();

process.WaitForExit();

Та же идея для Error, просто замените Output в именах этих методов / свойств.

8 голосов
/ 01 сентября 2011

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

Методика основана на некотором коде MSDN. Что я не смог понять, так это как заставить окно вывода обновляться «на лету». Он не обновляется до тех пор, пока не вернется эта задача.

// Set this to your output window Pane
private EnvDTE.OutputWindowPane _OutputPane = null;

// Methods to receive standard output and standard error

private static void StandardOutputReceiver(object sendingProcess, DataReceivedEventArgs outLine)
{
   // Receives the child process' standard output
   if (! string.IsNullOrEmpty(outLine.Data)) {
       if (_OutputPane != null)
           _OutputPane.Write(outLine.Data + Environment.NewLine);
   }
}

private static void StandardErrorReceiver(object sendingProcess, DataReceivedEventArgs errLine)
{
   // Receives the child process' standard error
   if (! string.IsNullOrEmpty(errLine.Data)) {
       if (_OutputPane != null)
           _OutputPane.Write("Error> " + errLine.Data + Environment.NewLine);
   }
}

// main code fragment
{
    // Start the new process
    ProcessStartInfo startInfo = new ProcessStartInfo(PROGRAM.EXE);
    startInfo.Arguments = COMMANDLINE;
    startInfo.WorkingDirectory = srcDir;
    startInfo.UseShellExecute = false;
    startInfo.RedirectStandardOutput = true;
    startInfo.RedirectStandardError = true;
    startInfo.CreateNoWindow = true;
    Process p = Process.Start(startInfo);
    p.OutputDataReceived += new DataReceivedEventHandler(StandardOutputReceiver);
    p.BeginOutputReadLine();
    p.ErrorDataReceived += new DataReceivedEventHandler(StandardErrorReceiver);
    p.BeginErrorReadLine();
    bool completed = p.WaitForExit(20000);
    if (!completed)
    {
        // do something here if it didn't finish in 20 seconds
    }
    p.Close();
}
2 голосов
/ 04 сентября 2010

Здесь происходит то, что Visual Studio отображает выходные данные отладки программы в окне вывода. То есть: если вы используете Trace.WriteLine, он появится в окне вывода из-за прослушивателя трассировки по умолчанию.

Каким-то образом ваше приложение Windows Form (когда оно использует Console.WriteLine; я предполагаю, что вы используете Console.WriteLine) также записывает выходные данные отладки, и Visual Studio принимает это.

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

0 голосов
/ 04 сентября 2010

Рассматривали ли вы использование DefaultTraceListener ?

    //Create and add a new default trace listener.
    DefaultTraceListener defaultListener;
    defaultListener = new DefaultTraceListener();
    Trace.Listeners.Add(defaultListener);
...