0

how can I use more colors in console while using WriteConsoleOutput and WriteConsoleOutputAttribute?
I found you can write ANSI colors using Console.Write, but how can I do this using those two methods?

Thomas Dickey
  • 51,086
  • 7
  • 70
  • 105
Aerd6154
  • 93
  • 8
  • Why are you using Win32 functions from a C# program? – Sean May 13 '20 at 16:37
  • I like to use `Console.ForegroundColor = ConsoleColor.Red` for example red. Then reset with `Console. ResetColor()' ... if that is what you were looking to do. – Barns May 13 '20 at 16:38
  • Does this answer your question? [Custom text color in C# console application?](https://stackoverflow.com/questions/7937256/custom-text-color-in-c-sharp-console-application) – Barns May 13 '20 at 16:47
  • Or perhaps [Converting Color to ConsoleColor?](https://stackoverflow.com/questions/1988833/converting-color-to-consolecolor) – Barns May 13 '20 at 16:48
  • @Barns even though you can set custom colors to ConsoleColor, it's still only limited to 16 colors. I want to use more colors (preferably 256 colors), but I can't find a way to use ANSI colors(256 colors support on some new Windows 10 update) with WriteConsoleOutput. – Aerd6154 May 13 '20 at 17:25
  • Looks you cannot https://learn.microsoft.com/en-us/windows/console/writeconsole – jira May 13 '20 at 18:05

3 Answers3

1

In C# is works like in C. I use it in C# some minutes ago and it works fine. Here is the Color table: https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit

C# Example:

    Console.Write("\x1B[38;5;{0}m", runtime.Register[2]);

C Example:

    printf ( "\x1B[38;5;%dm", color );
0

You have to opt-in on Windows to use ANSI color codes. It's not enabled by default.

using System.Runtime.InteropServices;

public static class ConsoleColor {
  private const int STD_OUTPUT_HANDLE = -11;
  private const uint ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004;

  [DllImport("kernel32.dll", SetLastError = true)]
  private static extern IntPtr GetStdHandle(int nStdHandle);

  [DllImport("kernel32.dll", SetLastError = true)]
  private static extern bool GetConsoleMode(IntPtr hConsoleHandle, out uint lpMode);

  [DllImport("kernel32.dll", SetLastError = true)]
  private static extern bool SetConsoleMode(IntPtr hConsoleHandle, uint dwMode);

  public static void Initialize() {
    if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) {
      EnableAnsiEscapeSequencesOnWindows();
    }
  }

  private static void EnableAnsiEscapeSequencesOnWindows() {
    IntPtr handle = GetStdHandle(STD_OUTPUT_HANDLE);
    if (handle == IntPtr.Zero) {
      throw new Exception("Cannot get standard output handle");
    }

    if (!GetConsoleMode(handle, out uint mode)) {
      throw new Exception("Cannot get console mode");
    }

    mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
    if (!SetConsoleMode(handle, mode)) {
      throw new Exception("Cannot set console mode");
    }
  }
}

It doesn't matter that we just initialize stdout. It colors work on stderr to once virtual terminal processing is enabled.

static int Main(string[] args) {
  ConsoleColor.Initialize();
  const string AnsiError = "\x1b[38;5;161m";
  const string AnsiReset = "\x1b[0m";
  Console.Error.WriteLine(AnsiError + "One or more tests failed!" + AnsiReset);
}
John Leidegren
  • 59,920
  • 20
  • 131
  • 152
0

You can used Ansi escape codes to color console text as it was possible with python I tried and have created a small extension on string to format & color the console text.

But unlike other answers it is a color mixed that works with RGB(255,255,255) and Css Hex Colors so it's not limited to the standard set of colors

Extension: Holi.cs

//Holi.cs
public static class Holi
{
    const int STD_OUTPUT_HANDLE = -11;
    const uint ENABLE_VIRTUAL_TERMINAL_PROCESSING = 4;

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern IntPtr GetStdHandle(int nStdHandle);

    [DllImport("kernel32.dll")]
    static extern bool GetConsoleMode(IntPtr hConsoleHandle, out uint lpMode);

    [DllImport("kernel32.dll")]
    static extern bool SetConsoleMode(IntPtr hConsoleHandle, uint dwMode);

    public const string RESET = "\x1B[0m";
    public const string UNDERLINE = "\x1B[4m";
    public const string BOLD = "\x1B[1m";
    public const string ITALIC = "\x1B[3m";
    public const string BLINK = "\x1B[5m";
    public const string BLINKRAPID = "\x1B[6m";
    public const string DEFAULTFORE = "\x1B[39m";
    public const string DEFAULTBACK = "\x1B[49m";

    static Holi()
    {
        var handle = GetStdHandle(STD_OUTPUT_HANDLE);
        uint mode;
        GetConsoleMode(handle, out mode);
        mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
        SetConsoleMode(handle, mode);
    }

    public static byte[] HexToRgb(string hexcolor)
    {
        hexcolor = hexcolor.Remove(0, 1);

        if (hexcolor.Length != 6)
            throw new Exception("Not a valid hex color");

        string[] rgb = hexcolor.Select((obj, index) => new { obj, index })
            .GroupBy(o => o.index / 2)
            .Select(g => new string(g.Select(a => a.obj)
            .ToArray())).ToArray<string>();

        return new byte[] { Convert.ToByte(rgb[0], 16), Convert.ToByte(rgb[1], 16), Convert.ToByte(rgb[2], 16) };
    }
    public static string ForeColor(this string text,byte red, byte green, byte blue)
    {
        return $"\x1B[38;2;{red};{green};{blue}m{text}";
    }

    public static string ForeColor(this string text, string hexrgb)
    {
        byte[] rgb = HexToRgb(hexrgb);

        return ForeColor(text, rgb[0], rgb[1], rgb[2]);
    }

    public static string BackColor(this string text, byte red, byte green, byte blue)
    {
        return $"\x1B[48;2;{red};{green};{blue}m{text}";
    }

    public static string BackColor(this string text, string hexrgb)
    {
        byte[] rgb = HexToRgb(hexrgb);

        return BackColor(text, rgb[0], rgb[1], rgb[2]);
    }

    public static string ResetColor(this string text)
    {
        return $"{RESET}{text}";
    }

    public static string Bold(this string text)
    {
        return $"{BOLD}{text}";
    }

    public static string Italic(this string text)
    {
        return $"{ITALIC}{text}";
    }

    public static string Underline(this string text)
    {
        return $"{UNDERLINE}{text}";
    }

    public static string Add(this string text,string addText)
    {
        return $"{text}{RESET}{addText}";
    }

    public static void Print(this string text,string prefix=null)
    {
        Console.WriteLine($"{prefix}{text}{RESET}");
    }

    public static void Printf(this string text, byte red=0, byte green=0, byte blue = 0)
    {
        Console.Write($"{ForeColor(red,green,blue)}{text}{RESET}");
    }

    public static void Printf(this string text, string hexColor)
    {
        byte[] rgb = HexToRgb(hexColor);

        Console.Write($"{ForeColor(rgb[0], rgb[1], rgb[2])}{text}{RESET}");
    }



    public static string ForeColor(params byte[] rgb)
    {
        if (rgb == null || rgb.Length == 0)
            return "\x1B[0m";

        if (rgb.Length == 3)
            return $"\x1B[38;2;{rgb[0]};{rgb[1]};{rgb[2]}m";

        if (rgb.Length == 2)
            return $"\x1B[38;2;{rgb[0]};{rgb[1]};0m";
        if (rgb.Length == 2)
            return $"\x1B[38;2;{rgb[0]};0;0m";

        return "\x1B[0m";

    }

    public static string BackColor(params byte[] rgb)
    {
        if (rgb == null || rgb.Length == 0)
            return "\x1B[0m";

        if (rgb.Length == 3)
            return $"\x1B[48;2;{rgb[0]};{rgb[1]};{rgb[2]}m";

        if (rgb.Length == 2)
            return $"\x1B[48;2;{rgb[0]};{rgb[1]};0m";
        if (rgb.Length == 2)
            return $"\x1B[48;2;{rgb[0]};0;0m";

        return "\x1B[0m";
    }

}

Example

Which can be used as:

//printf
"Printf Example\n".Printf(200, 255, 0);

//print
"#FFAAEE\n".ForeColor("#C8FF00").Print();

//format + print 
"\n RGB colored text".ForeColor(255,200,0).Print();
"\n HEX colored text".ForeColor("#FFC800").Print();
"\n RGB back colored text".BackColor(50, 0, 0).ResetColor().Add(" no background color ").Print();
"\n HEX back colored text".BackColor("#320000").Print();
"\n Bold Text".Bold().Print();
"\n Underline text".Underline().Add(" no underline ").Print();

//writline
var c = ForeColor(200, 255, 0);
Console.WriteLine($"Same {c}" + UNDERLINE + "underlined green" + RESET + " text");

Output

To get the following output in Microsoft Windows [Version 10.0.19044.2728]

enter image description here

Vinod Srivastav
  • 3,644
  • 1
  • 27
  • 40