C# 将子进程的输出(stdout、stderr)重定向到Visual Studio中的输出窗口

C# 将子进程的输出(stdout、stderr)重定向到Visual Studio中的输出窗口,c#,visual-studio,visual-studio-2008,stdout,output-window,C#,Visual Studio,Visual Studio 2008,Stdout,Output Window,目前,我正在从我的C#程序启动批处理文件,其中包括: System.Diagnostics.Process.Start(@"DoSomeStuff.bat"); 我希望能够将该子进程的输出(stdout和stderr)重定向到VisualStudio(特别是Visual C#Express 2008)中的输出窗口 有办法吗 (另外:当子进程完成时,它不会全部被缓冲,然后向外输出到输出窗口。) (顺便说一句:目前我可以让父进程的stdout(而不是stderr)显示在输出窗口中,方法是将我的程

目前,我正在从我的C#程序启动批处理文件,其中包括:

System.Diagnostics.Process.Start(@"DoSomeStuff.bat");
我希望能够将该子进程的输出(stdout和stderr)重定向到VisualStudio(特别是Visual C#Express 2008)中的输出窗口

有办法吗

(另外:当子进程完成时,它不会全部被缓冲,然后向外输出到输出窗口。)



(顺便说一句:目前我可以让父进程的stdout(而不是stderr)显示在输出窗口中,方法是将我的程序设置为“Windows应用程序”而不是“控制台应用程序”。如果程序在Visual Studio之外运行,这会中断,但在我的特定情况下这是可以的。)

您考虑过使用一个新的应用程序吗


这里发生的事情是VisualStudio正在输出窗口中显示程序的调试输出。也就是说:如果使用Trace.WriteLine,它将出现在输出窗口中,因为默认的跟踪侦听器

不知何故,您的Windows窗体应用程序(当它使用Console.WriteLine时;我假设您使用的是Console.WriteLine)也在编写调试输出,而Visual Studio正在处理这个问题

它不会对子进程执行相同的操作,除非显式捕获输出并将其与输出一起重定向

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

这个方法的一个变体对我很有用——现在发布这个,因为我希望我能早点找到它。 请注意,这只是从实际代码中提取的一个片段,因此可能存在一些小错误

该技术基于一些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();
}

这根本不能回答我的问题。在链接的MSDN页面中:“此类的一个实例将自动添加到Debug.Listeners和Trace.Listeners集合中。显式添加第二个DefaultTraceListener会导致调试器输出窗口中出现重复消息,并导致断言的消息框重复。”,让你的答案变得比完全无用更糟糕。这基本上就是我想问的——最后一点你是怎么做的?(而且,我意识到我的问题中遗漏了这一点:“当它发生时”如何做?)所有的部分都在这里。重定向进程的输出,使用Trace在输出窗口中获取它。您知道如何重定向子进程的输出了吗?下面给出的答案可以重定向父进程的输出,但不能重定向子进程的输出。这个答案基本上是正确的。它少了一些东西。特别是:
Start
Begin…ReadLine
WaitForExit
之后调用。另外,将
RedirectStandardInput
设置为true,修复了批处理文件中的一个程序(特别是plink)需要有效标准输入的问题,即使它没有使用它。
WaitForExit()
可能会导致无限等待。始终使用超时调用该方法:
process.WaitForExit(10000)
=>等待10秒。@paulm你说它不能获得正确的顺序是什么意思?这段代码在重定向stderr时对我不起作用(stdout正在工作)。知道为什么吗?请使用我问题的答案-这不会使stderr和stdout按正确顺序排列,即如果应用程序不正确,那么您可能会退出,退出,退出,等等
// 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();
}