Skip to content

Game.Debug.ConsoleWindow

Assembly: Assembly-CSharp (game code / mod runtime)
Namespace: Game.Debug

Type: public class

Base: System.Object

Summary: Utility for creating/attaching a Windows console and redirecting the application's standard input/output/error streams to it. Provides helpers to enable Windows Virtual Terminal (ANSI) processing, set console title and text color attributes, open CONIN$/CONOUT$ streams, and restore previous Console writers on Dispose. Windows-only (uses kernel32/user32 P/Invoke); intended for debugging and logging in development or modding scenarios for Cities: Skylines 2.


Fields

  • private const uint ATTACH_PARENT_PROCESS = uint.MaxValue
    Used as the special process id passed to AttachConsole to attach to the parent process console.

  • private const uint ERROR_ACCESS_DENIED = 5u
    Win32 error code for "access denied"; used to detect AttachConsole failure reason.

  • private const uint GENERIC_WRITE = 1073741824u
    Win32 desired access flag for CreateFile.

  • private const uint GENERIC_READ = 2147483648u
    Win32 desired access flag for CreateFile.

  • private const uint FILE_SHARE_READ = 1u
    Win32 share mode flag for CreateFile.

  • private const uint FILE_SHARE_WRITE = 2u
    Win32 share mode flag for CreateFile.

  • private const uint OPEN_EXISTING = 3u
    Win32 creation disposition for CreateFile.

  • private const uint FILE_ATTRIBUTE_NORMAL = 128u
    Win32 file attribute constant.

  • private const int SC_CLOSE = 61536
    System menu constant used to identify the Close command; used to remove the close button.

  • private const int MF_BYCOMMAND = 0
    Flag for DeleteMenu when removing menu items by command.

  • private TextWriter m_OldOutput
    Stores the previous Console.Out before redirecting so it can be restored on Dispose.

  • private TextWriter m_OldError
    Stores the previous Console.Error before redirecting so it can be restored on Dispose.

  • private StreamWriter m_Writer
    The StreamWriter wrapping the CONOUT$ handle that becomes Console.Out/Console.Error. Disposed on Dispose().

  • private const uint STD_OUTPUT_HANDLE = 4294967285u
    Value passed to GetStdHandle to obtain the stdout handle.

  • private const uint ENABLE_VIRTUAL_TERMINAL_PROCESSING = 4u
    Console mode flag to enable ANSI/VT sequence processing.

  • public const ushort FOREGROUND_BLUE = 1
    Foreground color attribute for console text.

  • public const ushort FOREGROUND_GREEN = 2
    Foreground color attribute for console text.

  • public const ushort FOREGROUND_RED = 4
    Foreground color attribute for console text.

  • public const ushort FOREGROUND_INTENSITY = 8
    Foreground intensity attribute (bright).

  • public const ushort BACKGROUND_BLUE = 16
    Background color attribute.

  • public const ushort BACKGROUND_GREEN = 32
    Background color attribute.

  • public const ushort BACKGROUND_RED = 64
    Background color attribute.

  • public const ushort BACKGROUND_INTENSITY = 128
    Background intensity attribute (bright).


Properties

  • This type exposes no public properties.

Constructors

  • public ConsoleWindow(string title, bool attachConsole = false)
    Creates a ConsoleWindow instance. If attachConsole is true, attempts to AttachConsole(ATTACH_PARENT_PROCESS); if that fails with an error other than ERROR_ACCESS_DENIED, it will AllocConsole() to create a new console. When a console is available it sets the console title and attempts to remove the Close button from the console window. After a console is ensured, it stores the current Console.Out and Console.Error writers, initializes and redirects output to CONOUT$, and enables virtual terminal processing on the output handle. If attachConsole is false but a console was created/attached internally, the class still redirects output. Use Dispose() to restore previous streams and free the console.

Notes: - attachConsole = true tries to attach to the parent process console first (useful when a parent process already has a console). - This constructor will set internal state only if a console was actually attached or allocated.


Methods

  • private static void EnableVirtualTerminal()
    Enables the ENABLE_VIRTUAL_TERMINAL_PROCESSING console mode on the process STD_OUTPUT_HANDLE (calls GetStdHandle and modifies the console mode to include the VT flag). This enables ANSI escape/VT sequences on Windows 10+ consoles.

  • private static void EnableVirtualTerminal(IntPtr handle)
    Same as above but operates on a provided console handle. Validates handle != IntPtr.Zero and that GetConsoleMode succeeds before setting the mode.

  • public static void SetColor(ushort color)
    Set console text attributes (foreground/background/intensity) by calling SetConsoleTextAttribute on the STD_OUTPUT_HANDLE. Accepts combined attribute flags (see FOREGROUND_/BACKGROUND_ constants).

  • private IntPtr InitializeOutStream()
    Opens CONOUT$ via CreateFileW wrapped by CreateFileStream, constructs a StreamWriter around it with AutoFlush = true, sets Console.Out and Console.Error to that writer, and returns the native handle (SafeFileHandle.DangerousGetHandle()). Returns IntPtr.Zero if opening the stream failed.

Important: Uses SafeFileHandle.DangerousGetHandle() to obtain the native handle for passing to SetConsoleMode. The returned IntPtr should only be used immediately; DangerousGetHandle has risks if the safe handle gets released concurrently.

  • private void InitializeInStream()
    Opens CONIN$ via CreateFileStream and sets Console.In to a StreamReader for the returned FileStream. This is not automatically invoked by the constructor (only provided if input redirection is needed).

  • private static FileStream CreateFileStream(string name, uint win32DesiredAccess, uint win32ShareMode, FileAccess dotNetFileAccess)
    Helper that calls CreateFileW(name, ...) and wraps the returned handle in a SafeFileHandle and FileStream. Returns null if CreateFileW returned an invalid handle.

  • public void Dispose()
    Restores the previous Console.Out and Console.Error writers, disposes the internal StreamWriter (m_Writer), and calls FreeConsole(). After Dispose, the console stream redirection is undone. Ensure Dispose is called to release resources (either via using or try/finally).

  • public void SetTitle(string strName)
    Wraps SetConsoleTitle to change the console window title.

P/Invoke declarations (internal/private extern methods): - GetConsoleMode(IntPtr hConsoleHandle, out uint lpMode)
- SetConsoleMode(IntPtr hConsoleHandle, uint dwMode)
- GetConsoleWindow()
- GetSystemMenu(IntPtr hWnd, bool bRevert)
- DeleteMenu(IntPtr hMenu, uint uPosition, uint uFlags)
- AllocConsole()
- AttachConsole(uint dwProcessId)
- FreeConsole()
- GetStdHandle(uint nStdHandle)
- SetStdHandle(uint nStdHandle, IntPtr handle)
- SetConsoleTitle(string lpConsoleTitle)
- SetConsoleTextAttribute(IntPtr hConsoleOutput, ushort attributes)
- CreateFileW(string lpFileName, uint dwDesiredAccess, uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition, uint dwFlagsAndAttributes, IntPtr hTemplateFile)

Notes on P/Invoke: - All native dependencies are Windows kernel32/user32 APIs. This class will not work on non-Windows platforms. - Several externs are declared with SetLastError = true; calling Marshal.GetLastWin32Error() after failures can provide failure reasons (the constructor uses this to check for ERROR_ACCESS_DENIED).


Usage Example

// Create and attach/allocate a console for debugging output.
// Preferably call Dispose when done (or use a using block).
var console = new Game.Debug.ConsoleWindow("My Mod Console", attachConsole: true);

try
{
    // Set text color (e.g., bright green)
    Game.Debug.ConsoleWindow.SetColor(Game.Debug.ConsoleWindow.FOREGROUND_GREEN | Game.Debug.ConsoleWindow.FOREGROUND_INTENSITY);

    Console.WriteLine("Console initialized for debugging.");

    // You can also enable VT explicitly on a handle if needed (internal helper).
}
finally
{
    console.Dispose(); // restores Console.Out/Error and frees the console
}

Additional tips: - If you only want ANSI escape sequences (colors via escape codes) you still need to enable virtual terminal processing on the console handle, which this class does when it successfully redirects output. - Because InitializeOutStream uses SafeFileHandle.DangerousGetHandle(), avoid manipulating the SafeFileHandle elsewhere to prevent handle lifetime races. - Consider checking for platform (Environment.OSVersion or RuntimeInformation.IsOSPlatform) before using this class to avoid attempts to P/Invoke on non-Windows platforms.