Приветствую всех, сегодня в группе увидел сообщение от пользователя, который просил ему помочь. Смысл сводился к тому что у него программа, которую он написал, вы водит информацию в консоль. Но его не устраивали стандартные цвета консоли. Я лично еще из msdn знаю что там может отображаться только 16 цветов. Однако так как все варианты цветов можно посмотреть в самой студии:
public enum ConsoleColor { // // Сводка: // Черный цвет. Black = 0, // // Сводка: // Темно-синий цвет. DarkBlue = 1, // // Сводка: // Темно-зеленый цвет. DarkGreen = 2, // // Сводка: // Темно-голубой цвет (темный сине-зеленый). DarkCyan = 3, // // Сводка: // Темно-красный цвет. DarkRed = 4, // // Сводка: // Темно-пурпурный цвет (темный фиолетово-красный). DarkMagenta = 5, // // Сводка: // Темно-желтый цвет (коричнево-желтый). DarkYellow = 6, // // Сводка: // Серый цвет. Gray = 7, // // Сводка: // Темно-серый цвет. DarkGray = 8, // // Сводка: // Синий цвет. Blue = 9, // // Сводка: // Зеленый цвет. Green = 10, // // Сводка: // Голубой цвет (сине-зеленый). Cyan = 11, // // Сводка: // Красный цвет. Red = 12, // // Сводка: // Пурпурный цвет (фиолетово-красный). Magenta = 13, // // Сводка: // Желтый цвет. Yellow = 14, // // Сводка: // Белый цвет. White = 15 }
У меня было свободное время и интерес понять почему именно 16 цветов и можно ли как то помочь человеку. Все мои попытки понять такое ограничение сводились к тому что консоль не поддерживает отображение других цветов еще с DOS. Однако потратив некоторое время я наткнулся на один пример, который меня потряс решением этой проблемы. В нем действительно рассматривалась возможность изменения цветовой палитры из класса Color для консоли. По факту там можно было выбрать или задать любой цвет. Код не мой, но посидев разобрав его, пришел к выводу что применяется изменения цвета фона и шрифта, тем самым вывод в консоль шрифта в RGB цветах. Так делали еще при работе C++ и видимо код переделали и под C#. Не будем терять время и перейдем к рассмотрению самого кода программы по изменению цвета шрифта в консоли.
using System; using System.Collections.Generic; using System.Diagnostics; using System.Drawing; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; namespace SetScreenColorsApp { class Program { class SetScreenColorsApp { [StructLayout(LayoutKind.Sequential)] internal struct COORD { internal short X; internal short Y; } [StructLayout(LayoutKind.Sequential)] internal struct SMALL_RECT { internal short Left; internal short Top; internal short Right; internal short Bottom; } [StructLayout(LayoutKind.Sequential)] internal struct COLORREF { internal uint ColorDWORD; internal COLORREF(Color color) { ColorDWORD = (uint)color.R + (((uint)color.G) << 8) + (((uint)color.B) << 16); } internal COLORREF(uint r, uint g, uint b) { ColorDWORD = r + (g << 8) + (b << 16); } internal Color GetColor() { return Color.FromArgb((int)(0x000000FFU & ColorDWORD), (int)(0x0000FF00U & ColorDWORD) >> 8, (int)(0x00FF0000U & ColorDWORD) >> 16); } internal void SetColor(Color color) { ColorDWORD = (uint)color.R + (((uint)color.G) << 8) + (((uint)color.B) << 16); } } [StructLayout(LayoutKind.Sequential)] internal struct CONSOLE_SCREEN_BUFFER_INFO_EX { internal int cbSize; internal COORD dwSize; internal COORD dwCursorPosition; internal ushort wAttributes; internal SMALL_RECT srWindow; internal COORD dwMaximumWindowSize; internal ushort wPopupAttributes; internal bool bFullscreenSupported; internal COLORREF black; internal COLORREF darkBlue; internal COLORREF darkGreen; internal COLORREF darkCyan; internal COLORREF darkRed; internal COLORREF darkMagenta; internal COLORREF darkYellow; internal COLORREF gray; internal COLORREF darkGray; internal COLORREF blue; internal COLORREF green; internal COLORREF cyan; internal COLORREF red; internal COLORREF magenta; internal COLORREF yellow; internal COLORREF white; } const int STD_OUTPUT_HANDLE = -11; // per WinBase.h internal static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1); // per WinBase.h [DllImport("kernel32.dll", SetLastError = true)] private static extern IntPtr GetStdHandle(int nStdHandle); // тип консольного потока [DllImport("kernel32.dll", SetLastError = true)] private static extern bool GetConsoleScreenBufferInfoEx(IntPtr hConsoleOutput, ref CONSOLE_SCREEN_BUFFER_INFO_EX csbe); [DllImport("kernel32.dll", SetLastError = true)] private static extern bool SetConsoleScreenBufferInfoEx(IntPtr hConsoleOutput, ref CONSOLE_SCREEN_BUFFER_INFO_EX csbe); // Set a specific console color to an RGB color // The default console colors used are gray (foreground) and black (background) public static int SetColor(ConsoleColor consoleColor, Color targetColor) { return SetColor(consoleColor, targetColor.R, targetColor.G, targetColor.B); } public static int SetColor(ConsoleColor color, uint r, uint g, uint b) { CONSOLE_SCREEN_BUFFER_INFO_EX csbe = new CONSOLE_SCREEN_BUFFER_INFO_EX(); csbe.cbSize = (int)Marshal.SizeOf(csbe); // 96 = 0x60 IntPtr hConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE); // 7 if (hConsoleOutput == INVALID_HANDLE_VALUE) { return Marshal.GetLastWin32Error(); } bool brc = GetConsoleScreenBufferInfoEx(hConsoleOutput, ref csbe); if (!brc) { return Marshal.GetLastWin32Error(); } // Цвета (флаги) switch (color) { case ConsoleColor.Black: csbe.black = new COLORREF(r, g, b); break; case ConsoleColor.DarkBlue: csbe.darkBlue = new COLORREF(r, g, b); break; case ConsoleColor.DarkGreen: csbe.darkGreen = new COLORREF(r, g, b); break; case ConsoleColor.DarkCyan: csbe.darkCyan = new COLORREF(r, g, b); break; case ConsoleColor.DarkRed: csbe.darkRed = new COLORREF(r, g, b); break; case ConsoleColor.DarkMagenta: csbe.darkMagenta = new COLORREF(r, g, b); break; case ConsoleColor.DarkYellow: csbe.darkYellow = new COLORREF(r, g, b); break; case ConsoleColor.Gray: csbe.gray = new COLORREF(r, g, b); break; case ConsoleColor.DarkGray: csbe.darkGray = new COLORREF(r, g, b); break; case ConsoleColor.Blue: csbe.blue = new COLORREF(r, g, b); break; case ConsoleColor.Green: csbe.green = new COLORREF(r, g, b); break; case ConsoleColor.Cyan: csbe.cyan = new COLORREF(r, g, b); break; case ConsoleColor.Red: csbe.red = new COLORREF(r, g, b); break; case ConsoleColor.Magenta: csbe.magenta = new COLORREF(r, g, b); break; case ConsoleColor.Yellow: csbe.yellow = new COLORREF(r, g, b); break; case ConsoleColor.White: csbe.white = new COLORREF(r, g, b); break; } ++csbe.srWindow.Bottom; ++csbe.srWindow.Right; brc = SetConsoleScreenBufferInfoEx(hConsoleOutput, ref csbe); if (!brc) { return Marshal.GetLastWin32Error(); } return 0; } public static int SetScreenColors(Color foregroundColor, Color backgroundColor) { int irc; irc = SetColor(ConsoleColor.Gray, foregroundColor); if (irc != 0) return irc; irc = SetColor(ConsoleColor.Black, backgroundColor); if (irc != 0) return irc; return 0; } } static void Main(string[] args) { Color screenTextColor = Color.Orchid; Color screenBackgroundColor = Color.Black; int irc = SetScreenColorsApp.SetScreenColors(screenTextColor, screenBackgroundColor); Console.WriteLine("Nookery.ru"); Console.ReadKey(); } } }