using System; using System.Runtime.InteropServices; using System.Security.Permissions; namespace BepInEx.ConsoleUtil { internal class Kon { #region pinvoke [DllImport("kernel32.dll", SetLastError = true)] private static extern bool GetConsoleScreenBufferInfo(IntPtr hConsoleOutput, out CONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo); [DllImport("kernel32.dll", SetLastError = true)] private static extern bool SetConsoleTextAttribute(IntPtr hConsoleOutput, short attributes); [DllImport("kernel32.dll", SetLastError = true)] private static extern IntPtr GetStdHandle(int nStdHandle); #endregion #region Types private struct CONSOLE_SCREEN_BUFFER_INFO { internal COORD dwSize; internal COORD dwCursorPosition; internal short wAttributes; internal SMALL_RECT srWindow; internal COORD dwMaximumWindowSize; } private struct COORD { internal short X; internal short Y; } private struct SMALL_RECT { internal short Left; internal short Top; internal short Right; internal short Bottom; } private static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1); #endregion #region Private private static short ConsoleColorToColorAttribute(short color, bool isBackground) { if ((color & -16) != 0) throw new ArgumentException("Arg_InvalidConsoleColor"); if (isBackground) color <<= 4; return color; } private static CONSOLE_SCREEN_BUFFER_INFO GetBufferInfo(bool throwOnNoConsole, out bool succeeded) { succeeded = false; if (!(conOut == INVALID_HANDLE_VALUE)) { try { // FIXME: Windows console shouldn't be used in other OSs in the first place CONSOLE_SCREEN_BUFFER_INFO console_SCREEN_BUFFER_INFO; if (!GetConsoleScreenBufferInfo(conOut, out console_SCREEN_BUFFER_INFO)) { bool consoleScreenBufferInfo = GetConsoleScreenBufferInfo(GetStdHandle(-12), out console_SCREEN_BUFFER_INFO); if (!consoleScreenBufferInfo) consoleScreenBufferInfo = GetConsoleScreenBufferInfo(GetStdHandle(-10), out console_SCREEN_BUFFER_INFO); if (!consoleScreenBufferInfo) if (Marshal.GetLastWin32Error() == 6 && !throwOnNoConsole) return default(CONSOLE_SCREEN_BUFFER_INFO); succeeded = true; return console_SCREEN_BUFFER_INFO; } } catch (EntryPointNotFoundException) { // Fails under unsupported OSes } } if (!throwOnNoConsole) return default(CONSOLE_SCREEN_BUFFER_INFO); throw new Exception("IO.IO_NoConsole"); } private static void SetConsoleColor(bool isBackground, ConsoleColor c) { new UIPermission(UIPermissionWindow.SafeTopLevelWindows).Demand(); var color = ConsoleColorToColorAttribute((short)c, isBackground); bool flag; var bufferInfo = GetBufferInfo(false, out flag); if (!flag) return; var num = bufferInfo.wAttributes; num &= (short)(isBackground ? -241 : -16); num = (short)((ushort)num | (ushort)color); SetConsoleTextAttribute(conOut, num); } private static ConsoleColor GetConsoleColor(bool isBackground) { bool flag; var bufferInfo = GetBufferInfo(false, out flag); if (!flag) return isBackground ? ConsoleColor.Black : ConsoleColor.Gray; return ColorAttributeToConsoleColor((short)(bufferInfo.wAttributes & 240)); } private static ConsoleColor ColorAttributeToConsoleColor(short c) { if ((short)(c & 255) != 0) c >>= 4; return (ConsoleColor)c; } internal static IntPtr conOut = IntPtr.Zero; #endregion #region Public public static void ResetConsoleColor() { SetConsoleColor(true, ConsoleColor.Black); SetConsoleColor(false, ConsoleColor.Gray); } public static ConsoleColor ForegroundColor { get { return GetConsoleColor(false); } set { SetConsoleColor(false, value); } } public static ConsoleColor BackgroundColor { get { return GetConsoleColor(true); } set { SetConsoleColor(true, value); } } #endregion } }