【问题标题】:How to keeps colours from msbuild output?如何从 msbuild 输出中保留颜色?
【发布时间】:2013-07-03 19:35:15
【问题描述】:

当我在命令行运行 msbuild 时,它会在控制台中显示漂亮的颜色。

但是,当我使用 Process.Start 从 C# 运行它时,输出显示为黑白。我怎样才能保持颜色?

var info = new ProcessStartInfo("msbuild")
{
    UseShellExecute = false,
    CreateNoWindow = true,
    RedirectStandardError = true,
    RedirectStandardOutput = true,            
};

using (var p = Process.Start(info) )
{
    p.ErrorDataReceived += (s, e) => Console.Error.WriteLine(e.Data);
    p.OutputDataReceived += (s, e) => Console.WriteLine(e.Data);
    p.BeginErrorReadLine();
    p.BeginOutputReadLine();
    p.WaitForExit();
}

另外,当我们在这里时,我在 BeginOutputReadLine 之前运行 Process.Start 重要吗?是否会丢失任何输出?


动机,对于那些感兴趣的人。我从事的一个项目使用自定义构建工具(重新发明轮子恕我直言)。它使用 msbuild,但在复杂的间接层后面(上面的简化模型)。 Msbuild 有用的颜色丢失了。我想拯救他们。

【问题讨论】:

  • 我看到你已经打开了一个赏金......想告诉我们这个问题的哪个方面 Hans Passant 的回答没有充分涵盖?还是你开始赏金给他了?
  • @CodyGray Hans 说这是不可能的。我希望它成为可能。
  • 不幸的是,他是对的。没有办法让OutputDataReceived 这样做。它输出的只是文本,而不是颜色。如果你想要颜色,你必须解析数据并手动应用它们,就像他说的那样。您可能对 VSColorOutput 扩展感兴趣,它会为您完成这项工作。
  • 我认为可以做到,但是您需要解析流并在流中收集 ANSI 转义码。实际上,您必须解释输出。 en.wikipedia.org/wiki/ANSI_escape_code 和 MSFT nodejstools 中的这个例子:github.com/Microsoft/nodejstools/blob/…
  • MSBuild 可能会这样做:stackoverflow.com/questions/8938679/…

标签: c# .net process system.diagnostics


【解决方案1】:
   p.OutputDataReceived += (s, e) => Console.WriteLine(e.Data);

Process.OutputDataReceived 读取文本,而不是颜色。此下方的输出重定向功能仅重定向标准输出文本,而不是控制台颜色属性。当您从命令行使用 > 重定向运算符运行 msbuild 以将其输出发送到文本文件时,您会得到完全相同的结果。当您在记事本中打开文本文件时,您当然会看到平淡无奇的文本。

解析重定向的输出以重新着色您自己的输出是非常不切实际的。你被乏味困住了。再说一次,程序员不会经常抱怨 IDE 中错误列表窗口的外观:)

【讨论】:

  • 认为可能是这种情况。 RedirectStandardOutput = false 会发生什么?
  • 显然,如果您不重定向输出,则 MSBuild 会再次写入控制台。而且你不会看到任何东西,因为你告诉它不要创建控制台。
  • “非常不切实际”这句话是我一直以来最喜欢的词之一。谢谢。
  • 现在这并非不切实际,因为他们重写了外壳,只花了 8 年时间。
【解决方案2】:

就是这样,没有其他方法可以做到这一点。 您的代码首先启动该过程,然后附加事件处理程序。所以可能会有一些数据丢失,但这取决于 cpu 处理代码的速度。 您最好先附加事件处理程序,然后再启动该过程。 (见下文)

using (var p = new Process())
{
    p.StartInfo = new ProcessStartInfo("msbuild")
    {
        UseShellExecute = false,
        CreateNoWindow = true,
        RedirectStandardError = true,
        RedirectStandardOutput = true,
    };
    p.ErrorDataReceived += (s, e) => ErrorLine(e.Data);
    p.OutputDataReceived += (s, e) => OutputLine(e.Data);
    p.BeginErrorReadLine();
    p.BeginOutputReadLine();
    p.Start();
    p.WaitForExit();
}
void ErrorLine(string text)
{
    Console.ForegroundColor = ConsoleColor.White;
    Console.BackgroundColor = ConsoleColor.DarkRed;
    Console.Error.WriteLine(text);
    Console.ResetColor();
}
void OutputLine(string text)
{
    Console.Error.WriteLine(text);
}

【讨论】:

  • 这是不正确的,有办法做到这一点,如果你阅读 powershell-core 源代码,你会发现你应该创建进程并暂停其主线程,然后设置 BeginXXXReadLine然后你才“解冻”进程,iow,恢复线程。对于 2021 年阅读此内容的任何人(因为我不喜欢误导性信息),如果您想正确使用流重定向,请查看此处。 github.com/PowerShell/PowerShell/blob/…
【解决方案3】:

我不知道如何专门针对 msbuild 执行此操作,所有警告/错误/其他颜色不同的事情,但您可以在写入之前使用 Console.ForegroundColor = ConsoleColor.Red; 更改控制台颜色,然后重置它与Console.ResetColor();

因此,您将更改 ErrorDataRecieved 订阅以在写入之前将颜色更改为红色,并在写入输出后重置颜色。

【讨论】:

    【解决方案4】:

    这个问题的潜在解决方案。现在可以解决这个问题,因为控制台基础结构几乎完全在 Windows 上进行了重新设计。 Introducing Windows Pseudo Console

    使用 ConPTY 创建 MsBuild 将给出完整的 VT 输出。

     public void Start(string command, int consoleWidth = 80, int consoleHeight = 30)
        {
            using (var inputPipe = new PseudoConsolePipe())
            using (var outputPipe = new PseudoConsolePipe())
            using (var pseudoConsole = PseudoConsole.Create(inputPipe.ReadSide, outputPipe.WriteSide, consoleWidth, consoleHeight))
            using (var process = ProcessFactory.Start(command, PseudoConsole.PseudoConsoleThreadAttribute, pseudoConsole.Handle))
            {
                // copy all pseudoconsole output to a FileStream and expose it to the rest of the app
                ConsoleOutStream = new FileStream(outputPipe.ReadSide, FileAccess.Read);
                OutputReady.Invoke(this, EventArgs.Empty);
    
                // Store input pipe handle, and a writer for later reuse
                _consoleInputPipeWriteHandle = inputPipe.WriteSide;
                _consoleInputWriter = new StreamWriter(new FileStream(_consoleInputPipeWriteHandle, FileAccess.Write))
                {
                    AutoFlush = true
                };
    
                // free resources in case the console is ungracefully closed (e.g. by the 'x' in the window titlebar)
                OnClose(() => DisposeResources(process, pseudoConsole, outputPipe, inputPipe, _consoleInputWriter));
    
                WaitForExit(process).WaitOne(Timeout.Infinite);
            }
        }
    

    来源: https://github.com/microsoft/terminal/blob/07d06f62aa5a883f70cbe8572bf8ea1f8577f53f/samples/ConPTY/GUIConsole/GUIConsole.ConPTY/Terminal.cs

    【讨论】:

      猜你喜欢
      • 2020-03-20
      • 2017-01-07
      • 2013-06-09
      • 1970-01-01
      • 2012-03-31
      • 2013-09-20
      • 1970-01-01
      • 2013-04-24
      • 1970-01-01
      相关资源
      最近更新 更多