// ==++== // // Copyright (c) Microsoft Corporation. All rights reserved. // // ==--== /*============================================================================= ** ** Class: Console ** ** ** Purpose: This class provides access to the standard input, standard output ** and standard error streams. ** ** =============================================================================*/ namespace System { using System; using System.IO; using System.Text; using System.Globalization; using System.Security; using System.Security.Permissions; using Microsoft.Win32; using System.Runtime.CompilerServices; using System.Threading; using System.Runtime.InteropServices; using Microsoft.Win32.SafeHandles; using System.Runtime.ConstrainedExecution; using System.Runtime.Versioning; using System.Diagnostics.Contracts; using System.Diagnostics.CodeAnalysis; using System.Collections.Generic; // Provides static fields for console input & output. Use // Console.In for input from the standard input stream (stdin), // Console.Out for output to stdout, and Console.Error // for output to stderr. If any of those console streams are // redirected from the command line, these streams will be redirected. // A program can also redirect its own output or input with the // SetIn, SetOut, and SetError methods. // // The distinction between Console.Out & Console.Error is useful // for programs that redirect output to a file or a pipe. Note that // stdout & stderr can be output to different files at the same // time from the DOS command line: // // someProgram 1> out 2> err // //Contains only static data. Serializable attribute not required. public static class Console { private const int DefaultConsoleBufferSize = 256; private const short AltVKCode = 0x12; #if !FEATURE_PAL private const int NumberLockVKCode = 0x90; // virtual key code private const int CapsLockVKCode = 0x14; // Beep range - see MSDN. private const int MinBeepFrequency = 37; private const int MaxBeepFrequency = 32767; // MSDN says console titles can be up to 64 KB in length. // But I get an exception if I use buffer lengths longer than // ~24500 Unicode characters. Oh well. private const int MaxConsoleTitleLength = 24500; #endif // !FEATURE_PAL #if !FEATURE_CORECLR private static readonly UnicodeEncoding StdConUnicodeEncoding = new UnicodeEncoding(false, false); #endif // !FEATURE_CORECLR private static volatile TextReader _in; private static volatile TextWriter _out; private static volatile TextWriter _error; private static volatile ConsoleCancelEventHandler _cancelCallbacks; private static volatile ControlCHooker _hooker; #if !FEATURE_PAL // ReadLine & Read can't use this because they need to use ReadFile // to be able to handle redirected input. We have to accept that // we will lose repeated keystrokes when someone switches from // calling ReadKey to calling Read or ReadLine. Those methods should // ideally flush this cache as well. [System.Security.SecurityCritical] // auto-generated private static Win32Native.InputRecord _cachedInputRecord; // For ResetColor private static volatile bool _haveReadDefaultColors; private static volatile byte _defaultColors; #endif // !FEATURE_PAL #if FEATURE_CODEPAGES_FILE // if no codepages file then locked into default private static volatile bool _isOutTextWriterRedirected = false; private static volatile bool _isErrorTextWriterRedirected = false; #endif private static volatile Encoding _inputEncoding = null; private static volatile Encoding _outputEncoding = null; #if !FEATURE_CORECLR private static volatile bool _stdInRedirectQueried = false; private static volatile bool _stdOutRedirectQueried = false; private static volatile bool _stdErrRedirectQueried = false; private static bool _isStdInRedirected; private static bool _isStdOutRedirected; private static bool _isStdErrRedirected; #endif // !FEATURE_CORECLR // Private object for locking instead of locking on a public type for SQL reliability work. // Use this for internal synchronization during initialization, wiring up events, or for short, non-blocking OS calls. private static volatile Object s_InternalSyncObject; private static Object InternalSyncObject { get { Contract.Ensures(Contract.Result() != null); if (s_InternalSyncObject == null) { Object o = new Object(); #pragma warning disable 0420 Interlocked.CompareExchange(ref s_InternalSyncObject, o, null); #pragma warning restore 0420 } return s_InternalSyncObject; } } // Use this for blocking in Console.ReadKey, which needs to protect itself in case multiple threads call it simultaneously. // Use a ReadKey-specific lock though, to allow other fields to be initialized on this type. private static volatile Object s_ReadKeySyncObject; private static Object ReadKeySyncObject { get { Contract.Ensures(Contract.Result() != null); if (s_ReadKeySyncObject == null) { Object o = new Object(); #pragma warning disable 0420 Interlocked.CompareExchange(ref s_ReadKeySyncObject, o, null); #pragma warning restore 0420 } return s_ReadKeySyncObject; } } // About reliability: I'm not using SafeHandle here. We don't // need to close these handles, and we don't allow the user to close // them so we don't have many of the security problems inherent in // something like file handles. Additionally, in a host like SQL // Server, we won't have a console. private static volatile IntPtr _consoleInputHandle; private static volatile IntPtr _consoleOutputHandle; private static IntPtr ConsoleInputHandle { [System.Security.SecurityCritical] // auto-generated [ResourceExposure(ResourceScope.Process)] [ResourceConsumption(ResourceScope.Process)] get { if (_consoleInputHandle == IntPtr.Zero) { _consoleInputHandle = Win32Native.GetStdHandle(Win32Native.STD_INPUT_HANDLE); } return _consoleInputHandle; } } private static IntPtr ConsoleOutputHandle { [System.Security.SecurityCritical] // auto-generated [ResourceExposure(ResourceScope.Process)] [ResourceConsumption(ResourceScope.Process)] get { if (_consoleOutputHandle == IntPtr.Zero) { _consoleOutputHandle = Win32Native.GetStdHandle(Win32Native.STD_OUTPUT_HANDLE); } return _consoleOutputHandle; } } #if !FEATURE_CORECLR [System.Security.SecuritySafeCritical] [ResourceExposure(ResourceScope.Process)] [ResourceConsumption(ResourceScope.Process)] private static bool IsHandleRedirected(IntPtr ioHandle) { // Need this to use GetFileType: SafeFileHandle safeIOHandle = new SafeFileHandle(ioHandle, false); // If handle is not to a character device, we must be redirected: int fileType = Win32Native.GetFileType(safeIOHandle); if ((fileType & Win32Native.FILE_TYPE_CHAR) != Win32Native.FILE_TYPE_CHAR) return true; // We are on a char device. // If GetConsoleMode succeeds, we are NOT redirected. int mode; bool success = Win32Native.GetConsoleMode(ioHandle, out mode); return !success; } public static bool IsInputRedirected { [System.Security.SecuritySafeCritical] get { if (_stdInRedirectQueried) return _isStdInRedirected; lock (InternalSyncObject) { if (_stdInRedirectQueried) return _isStdInRedirected; _isStdInRedirected = IsHandleRedirected(ConsoleInputHandle); _stdInRedirectQueried = true; return _isStdInRedirected; } } } // public static bool IsInputRedirected public static bool IsOutputRedirected { [System.Security.SecuritySafeCritical] get { if (_stdOutRedirectQueried) return _isStdOutRedirected; lock (InternalSyncObject) { if (_stdOutRedirectQueried) return _isStdOutRedirected; _isStdOutRedirected = IsHandleRedirected(ConsoleOutputHandle); _stdOutRedirectQueried = true; return _isStdOutRedirected; } } } // public static bool IsOutputRedirected public static bool IsErrorRedirected { [System.Security.SecuritySafeCritical] [ResourceExposure(ResourceScope.Process)] [ResourceConsumption(ResourceScope.Process)] get { if (_stdErrRedirectQueried) return _isStdErrRedirected; lock (InternalSyncObject) { if (_stdErrRedirectQueried) return _isStdErrRedirected; IntPtr errHndle = Win32Native.GetStdHandle(Win32Native.STD_ERROR_HANDLE); _isStdErrRedirected = IsHandleRedirected(errHndle); _stdErrRedirectQueried = true; return _isStdErrRedirected; } } } // public static bool IsErrorRedirected #endif // !FEATURE_CORECLR public static TextReader In { [System.Security.SecuritySafeCritical] // auto-generated [HostProtection(UI=true)] [ResourceExposure(ResourceScope.None)] [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)] get { Contract.Ensures(Contract.Result() != null); // Because most applications don't use stdin, we can delay // initialize it slightly better startup performance. if (_in == null) { lock(InternalSyncObject) { if (_in == null) { // Set up Console.In Stream s = OpenStandardInput(DefaultConsoleBufferSize); TextReader tr; if (s == Stream.Null) tr = StreamReader.Null; else { // Hopefully Encoding.GetEncoding doesn't load as many classes now. #if FEATURE_CORECLR Encoding enc = Encoding.UTF8; #else // FEATURE_CORECLR Encoding enc = InputEncoding; #endif // FEATURE_CORECLR tr = TextReader.Synchronized(new StreamReader(s, enc, false, DefaultConsoleBufferSize, true)); } System.Threading.Thread.MemoryBarrier(); _in = tr; } } } return _in; } } public static TextWriter Out { [HostProtection(UI=true)] [ResourceExposure(ResourceScope.None)] [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)] get { Contract.Ensures(Contract.Result() != null); // Hopefully this is inlineable. if (_out == null) InitializeStdOutError(true); return _out; } } public static TextWriter Error { [HostProtection(UI=true)] get { Contract.Ensures(Contract.Result() != null); // Hopefully this is inlineable. if (_error == null) InitializeStdOutError(false); return _error; } } // For console apps, the console handles are set to values like 3, 7, // and 11 OR if you've been created via CreateProcess, possibly -1 // or 0. -1 is definitely invalid, while 0 is probably invalid. // Also note each handle can independently be invalid or good. // For Windows apps, the console handles are set to values like 3, 7, // and 11 but are invalid handles - you may not write to them. However, // you can still spawn a Windows app via CreateProcess and read stdout // and stderr. // So, we always need to check each handle independently for validity // by trying to write or read to it, unless it is -1. // We do not do a security check here, under the assumption that this // cannot create a security hole, but only waste a user's time or // cause a possible denial of service attack. [System.Security.SecuritySafeCritical] // auto-generated [ResourceExposure(ResourceScope.None)] [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)] private static void InitializeStdOutError(bool stdout) { // Set up Console.Out or Console.Error. lock(InternalSyncObject) { if (stdout && _out != null) return; else if (!stdout && _error != null) return; TextWriter writer = null; Stream s; if (stdout) s = OpenStandardOutput(DefaultConsoleBufferSize); else s = OpenStandardError(DefaultConsoleBufferSize); if (s == Stream.Null) { #if _DEBUG if (CheckOutputDebug()) writer = MakeDebugOutputTextWriter((stdout) ? "Console.Out: " : "Console.Error: "); else #endif // _DEBUG writer = TextWriter.Synchronized(StreamWriter.Null); } else { #if FEATURE_CORECLR Encoding encoding = Encoding.UTF8; #else // FEATURE_CORECLR Encoding encoding = OutputEncoding; #endif // FEATURE_CORECLR StreamWriter stdxxx = new StreamWriter(s, encoding, DefaultConsoleBufferSize, true); stdxxx.HaveWrittenPreamble = true; stdxxx.AutoFlush = true; writer = TextWriter.Synchronized(stdxxx); } if (stdout) _out = writer; else _error = writer; Contract.Assert((stdout && _out != null) || (!stdout && _error != null), "Didn't set Console::_out or _error appropriately!"); } } // This is ONLY used in debug builds. If you have a registry key set, // it will redirect Console.Out & Error on console-less applications to // your debugger's output window. #if _DEBUG [System.Security.SecuritySafeCritical] // auto-generated [ResourceExposure(ResourceScope.None)] [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] private static bool CheckOutputDebug() { #if FEATURE_WIN32_REGISTRY new System.Security.Permissions.RegistryPermission(RegistryPermissionAccess.Read | RegistryPermissionAccess.Write, "HKEY_LOCAL_MACHINE").Assert(); RegistryKey rk = Registry.LocalMachine; using (rk = rk.OpenSubKey("Software\\Microsoft\\.NETFramework", false)) { if (rk != null) { Object obj = rk.GetValue("ConsoleSpewToDebugger", 0); if (obj != null && ((int)obj) != 0) { return true; } } } return false; #else // FEATURE_WIN32_REGISTRY #if FEATURE_PAL && !FEATURE_CORECLR const int parameterValueLength = 255; StringBuilder parameterValue = new StringBuilder(parameterValueLength); bool rc = Win32Native.FetchConfigurationString(true, "ConsoleSpewToDebugger", parameterValue, parameterValueLength); if (rc) { if (0 != parameterValue.Length) { int value = Convert.ToInt32(parameterValue.ToString()); if (0 != value) return true; } } #endif // FEATURE_PAL && !FEATURE_CORECLR return false; #endif // FEATURE_WIN32_REGISTRY } #endif // _DEBUG #if _DEBUG private static TextWriter MakeDebugOutputTextWriter(String streamLabel) { TextWriter output = new __DebugOutputTextWriter(streamLabel); output.WriteLine("Output redirected to debugger from a bit bucket."); return TextWriter.Synchronized(output); } #endif // _DEBUG #if !FEATURE_CORECLR // We cannot simply compare the encoding to Encoding.Unicode bacasue it incorporates BOM // and we do not care about BOM. Instead, we compare by class, codepage and little-endianess only: private static bool IsStandardConsoleUnicodeEncoding(Encoding encoding) { UnicodeEncoding enc = encoding as UnicodeEncoding; if (null == enc) return false; return (StdConUnicodeEncoding.CodePage == enc.CodePage) && (StdConUnicodeEncoding.bigEndian == enc.bigEndian); } private static bool GetUseFileAPIs(int handleType) { switch(handleType) { case Win32Native.STD_INPUT_HANDLE: return !IsStandardConsoleUnicodeEncoding(InputEncoding) || IsInputRedirected; case Win32Native.STD_OUTPUT_HANDLE: return !IsStandardConsoleUnicodeEncoding(OutputEncoding) || IsOutputRedirected; case Win32Native.STD_ERROR_HANDLE: return !IsStandardConsoleUnicodeEncoding(OutputEncoding) || IsErrorRedirected; default: // This can never happen. Contract.Assert(false, "Unexpected handleType value (" + handleType + ")"); return true; } } #endif // !FEATURE_CORECLR // This method is only exposed via methods to get at the console. // We won't use any security checks here. #if FEATURE_CORECLR [System.Security.SecurityCritical] // auto-generated #else [System.Security.SecuritySafeCritical] #endif [ResourceExposure(ResourceScope.Process)] [ResourceConsumption(ResourceScope.Process)] private static Stream GetStandardFile(int stdHandleName, FileAccess access, int bufferSize) { // We shouldn't close the handle for stdout, etc, or we'll break // unmanaged code in the process that will print to console. // We should have a better way of marking this on SafeHandle. IntPtr handle = Win32Native.GetStdHandle(stdHandleName); SafeFileHandle sh = new SafeFileHandle(handle, false); // If someone launches a managed process via CreateProcess, stdout // stderr, & stdin could independently be set to INVALID_HANDLE_VALUE. // Additionally they might use 0 as an invalid handle. if (sh.IsInvalid) { // Minor perf optimization - get it out of the finalizer queue. sh.SetHandleAsInvalid(); return Stream.Null; } // Check whether we can read or write to this handle. if (stdHandleName != Win32Native.STD_INPUT_HANDLE && !ConsoleHandleIsWritable(sh)) { //BCLDebug.ConsoleError("Console::ConsoleHandleIsValid for std handle "+stdHandleName+" failed, setting it to a null stream"); return Stream.Null; } #if !FEATURE_CORECLR bool useFileAPIs = GetUseFileAPIs(stdHandleName); #else const bool useFileAPIs = true; #endif // !FEATURE_CORECLR //BCLDebug.ConsoleError("Console::GetStandardFile for std handle "+stdHandleName+" succeeded, returning handle number "+handle.ToString()); Stream console = new __ConsoleStream(sh, access, useFileAPIs); // Do not buffer console streams, or we can get into situations where // we end up blocking waiting for you to hit enter twice. It was // redundant. return console; } // Checks whether stdout or stderr are writable. Do NOT pass // stdin here. #if FEATURE_CORECLR [System.Security.SecurityCritical] // auto-generated #else [System.Security.SecuritySafeCritical] #endif [ResourceExposure(ResourceScope.Process)] [ResourceConsumption(ResourceScope.Process)] private static unsafe bool ConsoleHandleIsWritable(SafeFileHandle outErrHandle) { // Do NOT call this method on stdin! // Windows apps may have non-null valid looking handle values for // stdin, stdout and stderr, but they may not be readable or // writable. Verify this by calling WriteFile in the // appropriate modes. // This must handle console-less Windows apps. int bytesWritten; byte junkByte = 0x41; int r = Win32Native.WriteFile(outErrHandle, &junkByte, 0, out bytesWritten, IntPtr.Zero); // In Win32 apps w/ no console, bResult should be 0 for failure. return r != 0; } public static Encoding InputEncoding { [System.Security.SecuritySafeCritical] // auto-generated get { Contract.Ensures(Contract.Result() != null); if (null != _inputEncoding) return _inputEncoding; lock(InternalSyncObject) { if (null != _inputEncoding) return _inputEncoding; uint cp = Win32Native.GetConsoleCP(); _inputEncoding = Encoding.GetEncoding((int) cp); return _inputEncoding; } } #if FEATURE_CODEPAGES_FILE // if no codepages file then locked into default [System.Security.SecuritySafeCritical] // auto-generated [ResourceExposure(ResourceScope.Process)] [ResourceConsumption(ResourceScope.Process)] set { if (value == null) throw new ArgumentNullException("value"); Contract.EndContractBlock(); new UIPermission(UIPermissionWindow.SafeTopLevelWindows).Demand(); lock(InternalSyncObject) { if (!IsStandardConsoleUnicodeEncoding(value)) { uint cp = (uint) value.CodePage; bool r = Win32Native.SetConsoleCP(cp); if (!r) __Error.WinIOError(); } _inputEncoding = (Encoding) value.Clone(); // We need to reinitialize Console.In in the next call to _in // This will discard the current StreamReader, potentially // losing buffered data _in = null; } } // set #endif // FEATURE_CODEPAGES_FILE } // public static Encoding InputEncoding public static Encoding OutputEncoding { [System.Security.SecuritySafeCritical] // auto-generated get { Contract.Ensures(Contract.Result() != null); if (null != _outputEncoding) return _outputEncoding; lock(InternalSyncObject) { if (null != _outputEncoding) return _outputEncoding; uint cp = Win32Native.GetConsoleOutputCP(); _outputEncoding = Encoding.GetEncoding((int) cp); return _outputEncoding; } } #if FEATURE_CODEPAGES_FILE // if no codepages file then locked into default [System.Security.SecuritySafeCritical] // auto-generated [ResourceExposure(ResourceScope.Process)] [ResourceConsumption(ResourceScope.Process)] set { if (value == null) throw new ArgumentNullException("value"); Contract.EndContractBlock(); new UIPermission(UIPermissionWindow.SafeTopLevelWindows).Demand(); lock(InternalSyncObject) { // Before changing the code page we need to flush the data // if Out hasn't been redirected. Also, have the next call to // _out reinitialize the console code page. if (_out != null && !_isOutTextWriterRedirected) { _out.Flush(); _out = null; } if (_error != null && !_isErrorTextWriterRedirected) { _error.Flush(); _error = null; } if (!IsStandardConsoleUnicodeEncoding(value)) { uint cp = (uint) value.CodePage; bool r = Win32Native.SetConsoleOutputCP(cp); if (!r) __Error.WinIOError(); } _outputEncoding = (Encoding) value.Clone(); } } // set #endif // FEATURE_CODEPAGES_FILE } // public static Encoding OutputEncoding #if !FEATURE_PAL [HostProtection(UI=true)] public static void Beep() { Beep(800, 200); } [System.Security.SecuritySafeCritical] // auto-generated [HostProtection(UI=true)] public static void Beep(int frequency, int duration) { if (frequency < MinBeepFrequency || frequency > MaxBeepFrequency) throw new ArgumentOutOfRangeException("frequency", frequency, Environment.GetResourceString("ArgumentOutOfRange_BeepFrequency", MinBeepFrequency, MaxBeepFrequency)); if (duration <= 0) throw new ArgumentOutOfRangeException("duration", duration, Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum")); // Note that Beep over Remote Desktop connections does not currently Contract.EndContractBlock(); // work. Ignore any failures here. Win32Native.Beep(frequency, duration); } [System.Security.SecuritySafeCritical] // auto-generated [ResourceExposure(ResourceScope.Process)] [ResourceConsumption(ResourceScope.Process)] public static void Clear() { Win32Native.COORD coordScreen = new Win32Native.COORD(); Win32Native.CONSOLE_SCREEN_BUFFER_INFO csbi; bool success; int conSize; IntPtr hConsole = ConsoleOutputHandle; if (hConsole == Win32Native.INVALID_HANDLE_VALUE) throw new IOException(Environment.GetResourceString("IO.IO_NoConsole")); // get the number of character cells in the current buffer // Go through my helper method for fetching a screen buffer info // to correctly handle default console colors. csbi = GetBufferInfo(); conSize = csbi.dwSize.X * csbi.dwSize.Y; // fill the entire screen with blanks int numCellsWritten = 0; success = Win32Native.FillConsoleOutputCharacter(hConsole, ' ', conSize, coordScreen, out numCellsWritten); if (!success) __Error.WinIOError(); // now set the buffer's attributes accordingly numCellsWritten = 0; success = Win32Native.FillConsoleOutputAttribute(hConsole, csbi.wAttributes, conSize, coordScreen, out numCellsWritten); if (!success) __Error.WinIOError(); // put the cursor at (0, 0) success = Win32Native.SetConsoleCursorPosition(hConsole, coordScreen); if (!success) __Error.WinIOError(); } [System.Security.SecurityCritical] // auto-generated private static Win32Native.Color ConsoleColorToColorAttribute(ConsoleColor color, bool isBackground) { if ((((int)color) & ~0xf) != 0) throw new ArgumentException(Environment.GetResourceString("Arg_InvalidConsoleColor")); Contract.EndContractBlock(); Win32Native.Color c = (Win32Native.Color) color; // Make these background colors instead of foreground if (isBackground) c = (Win32Native.Color) ((int)c << 4); return c; } [System.Security.SecurityCritical] // auto-generated private static ConsoleColor ColorAttributeToConsoleColor(Win32Native.Color c) { // Turn background colors into foreground colors. if ((c & Win32Native.Color.BackgroundMask) != 0) c = (Win32Native.Color) (((int)c) >> 4); return (ConsoleColor) c; } public static ConsoleColor BackgroundColor { [System.Security.SecuritySafeCritical] // auto-generated [ResourceExposure(ResourceScope.None)] [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)] get { bool succeeded; Win32Native.CONSOLE_SCREEN_BUFFER_INFO csbi = GetBufferInfo(false, out succeeded); // For code that may be used from Windows app w/ no console if (!succeeded) return ConsoleColor.Black; Win32Native.Color c = (Win32Native.Color) csbi.wAttributes & Win32Native.Color.BackgroundMask; return ColorAttributeToConsoleColor(c); } [System.Security.SecuritySafeCritical] // auto-generated [ResourceExposure(ResourceScope.Process)] [ResourceConsumption(ResourceScope.Process)] set { new UIPermission(UIPermissionWindow.SafeTopLevelWindows).Demand(); Win32Native.Color c = ConsoleColorToColorAttribute(value, true); bool succeeded; Win32Native.CONSOLE_SCREEN_BUFFER_INFO csbi = GetBufferInfo(false, out succeeded); // For code that may be used from Windows app w/ no console if (!succeeded) return; Contract.Assert(_haveReadDefaultColors, "Setting the foreground color before we've read the default foreground color!"); short attrs = csbi.wAttributes; attrs &= ~((short)Win32Native.Color.BackgroundMask); // C#'s bitwise-or sign-extends to 32 bits. attrs = (short) (((uint) (ushort) attrs) | ((uint) (ushort) c)); // Ignore errors here - there are some scenarios for running code that wants // to print in colors to the console in a Windows application. Win32Native.SetConsoleTextAttribute(ConsoleOutputHandle, attrs); } } // public static ConsoleColor BackgroundColor public static ConsoleColor ForegroundColor { [System.Security.SecuritySafeCritical] // auto-generated [ResourceExposure(ResourceScope.None)] [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)] get { bool succeeded; Win32Native.CONSOLE_SCREEN_BUFFER_INFO csbi = GetBufferInfo(false, out succeeded); // For code that may be used from Windows app w/ no console if (!succeeded) return ConsoleColor.Gray; Win32Native.Color c = (Win32Native.Color) csbi.wAttributes & Win32Native.Color.ForegroundMask; return ColorAttributeToConsoleColor(c); } [System.Security.SecuritySafeCritical] // auto-generated [ResourceExposure(ResourceScope.Process)] [ResourceConsumption(ResourceScope.Process)] set { new UIPermission(UIPermissionWindow.SafeTopLevelWindows).Demand(); Win32Native.Color c = ConsoleColorToColorAttribute(value, false); bool succeeded; Win32Native.CONSOLE_SCREEN_BUFFER_INFO csbi = GetBufferInfo(false, out succeeded); // For code that may be used from Windows app w/ no console if (!succeeded) return; Contract.Assert(_haveReadDefaultColors, "Setting the foreground color before we've read the default foreground color!"); short attrs = csbi.wAttributes; attrs &= ~((short)Win32Native.Color.ForegroundMask); // C#'s bitwise-or sign-extends to 32 bits. attrs = (short) (((uint) (ushort) attrs) | ((uint) (ushort) c)); // Ignore errors here - there are some scenarios for running code that wants // to print in colors to the console in a Windows application. Win32Native.SetConsoleTextAttribute(ConsoleOutputHandle, attrs); } } // public static ConsoleColor ForegroundColor [System.Security.SecuritySafeCritical] // auto-generated [ResourceExposure(ResourceScope.Process)] [ResourceConsumption(ResourceScope.Process)] public static void ResetColor() { new UIPermission(UIPermissionWindow.SafeTopLevelWindows).Demand(); bool succeeded; Win32Native.CONSOLE_SCREEN_BUFFER_INFO csbi = GetBufferInfo(false, out succeeded); // For code that may be used from Windows app w/ no console if (!succeeded) return; Contract.Assert(_haveReadDefaultColors, "Setting the foreground color before we've read the default foreground color!"); short defaultAttrs = (short) (ushort) _defaultColors; // Ignore errors here - there are some scenarios for running code that wants // to print in colors to the console in a Windows application. Win32Native.SetConsoleTextAttribute(ConsoleOutputHandle, defaultAttrs); } [ResourceExposure(ResourceScope.Process)] [ResourceConsumption(ResourceScope.Process)] public static void MoveBufferArea(int sourceLeft, int sourceTop, int sourceWidth, int sourceHeight, int targetLeft, int targetTop) { MoveBufferArea(sourceLeft, sourceTop, sourceWidth, sourceHeight, targetLeft, targetTop, ' ', ConsoleColor.Black, BackgroundColor); } [System.Security.SecuritySafeCritical] // auto-generated [ResourceExposure(ResourceScope.Process)] [ResourceConsumption(ResourceScope.Process)] public unsafe static void MoveBufferArea(int sourceLeft, int sourceTop, int sourceWidth, int sourceHeight, int targetLeft, int targetTop, char sourceChar, ConsoleColor sourceForeColor, ConsoleColor sourceBackColor) { if (sourceForeColor < ConsoleColor.Black || sourceForeColor > ConsoleColor.White) throw new ArgumentException(Environment.GetResourceString("Arg_InvalidConsoleColor"), "sourceForeColor"); if (sourceBackColor < ConsoleColor.Black || sourceBackColor > ConsoleColor.White) throw new ArgumentException(Environment.GetResourceString("Arg_InvalidConsoleColor"), "sourceBackColor"); Contract.EndContractBlock(); Win32Native.CONSOLE_SCREEN_BUFFER_INFO csbi = GetBufferInfo(); Win32Native.COORD bufferSize = csbi.dwSize; if (sourceLeft < 0 || sourceLeft > bufferSize.X) throw new ArgumentOutOfRangeException("sourceLeft", sourceLeft, Environment.GetResourceString("ArgumentOutOfRange_ConsoleBufferBoundaries")); if (sourceTop < 0 || sourceTop > bufferSize.Y) throw new ArgumentOutOfRangeException("sourceTop", sourceTop, Environment.GetResourceString("ArgumentOutOfRange_ConsoleBufferBoundaries")); if (sourceWidth < 0 || sourceWidth > bufferSize.X - sourceLeft) throw new ArgumentOutOfRangeException("sourceWidth", sourceWidth, Environment.GetResourceString("ArgumentOutOfRange_ConsoleBufferBoundaries")); if (sourceHeight < 0 || sourceTop > bufferSize.Y - sourceHeight) throw new ArgumentOutOfRangeException("sourceHeight", sourceHeight, Environment.GetResourceString("ArgumentOutOfRange_ConsoleBufferBoundaries")); // Note: if the target range is partially in and partially out // of the buffer, then we let the OS clip it for us. if (targetLeft < 0 || targetLeft > bufferSize.X) throw new ArgumentOutOfRangeException("targetLeft", targetLeft, Environment.GetResourceString("ArgumentOutOfRange_ConsoleBufferBoundaries")); if (targetTop < 0 || targetTop > bufferSize.Y) throw new ArgumentOutOfRangeException("targetTop", targetTop, Environment.GetResourceString("ArgumentOutOfRange_ConsoleBufferBoundaries")); // If we're not doing any work, bail out now (Windows will return // an error otherwise) if (sourceWidth == 0 || sourceHeight == 0) return; new UIPermission(UIPermissionWindow.SafeTopLevelWindows).Demand(); // Read data from the original location, blank it out, then write // it to the new location. This will handle overlapping source and // destination regions correctly. // See the "Reading and Writing Blocks of Characters and Attributes" // sample for help // Read the old data Win32Native.CHAR_INFO[] data = new Win32Native.CHAR_INFO[sourceWidth * sourceHeight]; bufferSize.X = (short) sourceWidth; bufferSize.Y = (short) sourceHeight; Win32Native.COORD bufferCoord = new Win32Native.COORD(); Win32Native.SMALL_RECT readRegion = new Win32Native.SMALL_RECT(); readRegion.Left = (short) sourceLeft; readRegion.Right = (short) (sourceLeft + sourceWidth - 1); readRegion.Top = (short) sourceTop; readRegion.Bottom = (short) (sourceTop + sourceHeight - 1); bool r; fixed(Win32Native.CHAR_INFO* pCharInfo = data) r = Win32Native.ReadConsoleOutput(ConsoleOutputHandle, pCharInfo, bufferSize, bufferCoord, ref readRegion); if (!r) __Error.WinIOError(); // Overwrite old section // I don't have a good function to blank out a rectangle. Win32Native.COORD writeCoord = new Win32Native.COORD(); writeCoord.X = (short) sourceLeft; Win32Native.Color c = ConsoleColorToColorAttribute(sourceBackColor, true); c |= ConsoleColorToColorAttribute(sourceForeColor, false); short attr = (short) c; int numWritten; for(int i = sourceTop; i= Int16.MaxValue) throw new ArgumentOutOfRangeException("width", width, Environment.GetResourceString("ArgumentOutOfRange_ConsoleBufferLessThanWindowSize")); if (height < srWindow.Bottom + 1 || height >= Int16.MaxValue) throw new ArgumentOutOfRangeException("height", height, Environment.GetResourceString("ArgumentOutOfRange_ConsoleBufferLessThanWindowSize")); Win32Native.COORD size = new Win32Native.COORD(); size.X = (short) width; size.Y = (short) height; bool r = Win32Native.SetConsoleScreenBufferSize(ConsoleOutputHandle, size); if (!r) __Error.WinIOError(); } public static int WindowHeight { [System.Security.SecuritySafeCritical] // auto-generated [ResourceExposure(ResourceScope.None)] [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)] get { Win32Native.CONSOLE_SCREEN_BUFFER_INFO csbi = GetBufferInfo(); return csbi.srWindow.Bottom - csbi.srWindow.Top + 1; } [ResourceExposure(ResourceScope.Process)] [ResourceConsumption(ResourceScope.Process)] set { SetWindowSize(WindowWidth, value); } } public static int WindowWidth { [System.Security.SecuritySafeCritical] // auto-generated [ResourceExposure(ResourceScope.None)] [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)] get { Win32Native.CONSOLE_SCREEN_BUFFER_INFO csbi = GetBufferInfo(); return csbi.srWindow.Right - csbi.srWindow.Left + 1; } [ResourceExposure(ResourceScope.Process)] [ResourceConsumption(ResourceScope.Process)] set { SetWindowSize(value, WindowHeight); } } [System.Security.SecuritySafeCritical] // auto-generated [ResourceExposure(ResourceScope.Process)] [ResourceConsumption(ResourceScope.Process)] public static unsafe void SetWindowSize(int width, int height) { if (width <= 0) throw new ArgumentOutOfRangeException("width", width, Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum")); if (height <= 0) throw new ArgumentOutOfRangeException("height", height, Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum")); Contract.EndContractBlock(); new UIPermission(UIPermissionWindow.SafeTopLevelWindows).Demand(); // Get the position of the current console window Win32Native.CONSOLE_SCREEN_BUFFER_INFO csbi = GetBufferInfo(); bool r; // If the buffer is smaller than this new window size, resize the // buffer to be large enough. Include window position. bool resizeBuffer = false; Win32Native.COORD size = new Win32Native.COORD(); size.X = csbi.dwSize.X; size.Y = csbi.dwSize.Y; if (csbi.dwSize.X < csbi.srWindow.Left + width) { if (csbi.srWindow.Left >= Int16.MaxValue - width) throw new ArgumentOutOfRangeException("width", Environment.GetResourceString("ArgumentOutOfRange_ConsoleWindowBufferSize")); size.X = (short) (csbi.srWindow.Left + width); resizeBuffer = true; } if (csbi.dwSize.Y < csbi.srWindow.Top + height) { if (csbi.srWindow.Top >= Int16.MaxValue - height) throw new ArgumentOutOfRangeException("height", Environment.GetResourceString("ArgumentOutOfRange_ConsoleWindowBufferSize")); size.Y = (short) (csbi.srWindow.Top + height); resizeBuffer = true; } if (resizeBuffer) { r = Win32Native.SetConsoleScreenBufferSize(ConsoleOutputHandle, size); if (!r) __Error.WinIOError(); } Win32Native.SMALL_RECT srWindow = csbi.srWindow; // Preserve the position, but change the size. srWindow.Bottom = (short) (srWindow.Top + height - 1); srWindow.Right = (short) (srWindow.Left + width - 1); r = Win32Native.SetConsoleWindowInfo(ConsoleOutputHandle, true, &srWindow); if (!r) { int errorCode = Marshal.GetLastWin32Error(); // If we resized the buffer, un-resize it. if (resizeBuffer) { Win32Native.SetConsoleScreenBufferSize(ConsoleOutputHandle, csbi.dwSize); } // Try to give a better error message here Win32Native.COORD bounds = Win32Native.GetLargestConsoleWindowSize(ConsoleOutputHandle); if (width > bounds.X) throw new ArgumentOutOfRangeException("width", width, Environment.GetResourceString("ArgumentOutOfRange_ConsoleWindowSize_Size", bounds.X)); if (height > bounds.Y) throw new ArgumentOutOfRangeException("height", height, Environment.GetResourceString("ArgumentOutOfRange_ConsoleWindowSize_Size", bounds.Y)); __Error.WinIOError(errorCode, String.Empty); } } // public static unsafe void SetWindowSize(int width, int height) public static int LargestWindowWidth { [System.Security.SecuritySafeCritical] // auto-generated [ResourceExposure(ResourceScope.None)] [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)] get { // Note this varies based on current screen resolution and // current console font. Do not cache this value. Win32Native.COORD bounds = Win32Native.GetLargestConsoleWindowSize(ConsoleOutputHandle); return bounds.X; } } public static int LargestWindowHeight { [System.Security.SecuritySafeCritical] // auto-generated [ResourceExposure(ResourceScope.None)] [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)] get { // Note this varies based on current screen resolution and // current console font. Do not cache this value. Win32Native.COORD bounds = Win32Native.GetLargestConsoleWindowSize(ConsoleOutputHandle); return bounds.Y; } } public static int WindowLeft { [System.Security.SecuritySafeCritical] // auto-generated [ResourceExposure(ResourceScope.None)] [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)] get { Win32Native.CONSOLE_SCREEN_BUFFER_INFO csbi = GetBufferInfo(); return csbi.srWindow.Left; } [ResourceExposure(ResourceScope.Process)] [ResourceConsumption(ResourceScope.Process)] set { SetWindowPosition(value, WindowTop); } } public static int WindowTop { [System.Security.SecuritySafeCritical] // auto-generated [ResourceExposure(ResourceScope.None)] [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)] get { Win32Native.CONSOLE_SCREEN_BUFFER_INFO csbi = GetBufferInfo(); return csbi.srWindow.Top; } [ResourceExposure(ResourceScope.Process)] [ResourceConsumption(ResourceScope.Process)] set { SetWindowPosition(WindowLeft, value); } } [System.Security.SecuritySafeCritical] // auto-generated [ResourceExposure(ResourceScope.Process)] [ResourceConsumption(ResourceScope.Process)] public static unsafe void SetWindowPosition(int left, int top) { new UIPermission(UIPermissionWindow.SafeTopLevelWindows).Demand(); // Get the size of the current console window Win32Native.CONSOLE_SCREEN_BUFFER_INFO csbi = GetBufferInfo(); Win32Native.SMALL_RECT srWindow = csbi.srWindow; // Check for arithmetic underflows & overflows. int newRight = left + srWindow.Right - srWindow.Left + 1; if (left < 0 || newRight > csbi.dwSize.X || newRight < 0) throw new ArgumentOutOfRangeException("left", left, Environment.GetResourceString("ArgumentOutOfRange_ConsoleWindowPos")); int newBottom = top + srWindow.Bottom - srWindow.Top + 1; if (top < 0 || newBottom > csbi.dwSize.Y || newBottom < 0) throw new ArgumentOutOfRangeException("top", top, Environment.GetResourceString("ArgumentOutOfRange_ConsoleWindowPos")); // Preserve the size, but move the position. srWindow.Bottom -= (short) (srWindow.Top - top); srWindow.Right -= (short) (srWindow.Left - left); srWindow.Left = (short) left; srWindow.Top = (short) top; bool r = Win32Native.SetConsoleWindowInfo(ConsoleOutputHandle, true, &srWindow); if (!r) __Error.WinIOError(); } public static int CursorLeft { [System.Security.SecuritySafeCritical] // auto-generated [ResourceExposure(ResourceScope.None)] [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)] get { Win32Native.CONSOLE_SCREEN_BUFFER_INFO csbi = GetBufferInfo(); return csbi.dwCursorPosition.X; } [ResourceExposure(ResourceScope.Process)] [ResourceConsumption(ResourceScope.Process)] set { SetCursorPosition(value, CursorTop); } } public static int CursorTop { [System.Security.SecuritySafeCritical] // auto-generated [ResourceExposure(ResourceScope.None)] [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)] get { Win32Native.CONSOLE_SCREEN_BUFFER_INFO csbi = GetBufferInfo(); return csbi.dwCursorPosition.Y; } [ResourceExposure(ResourceScope.Process)] [ResourceConsumption(ResourceScope.Process)] set { SetCursorPosition(CursorLeft, value); } } [System.Security.SecuritySafeCritical] // auto-generated [ResourceExposure(ResourceScope.Process)] [ResourceConsumption(ResourceScope.Process)] public static void SetCursorPosition(int left, int top) { // Note on argument checking - the upper bounds are NOT correct // here! But it looks slightly expensive to compute them. Let // Windows calculate them, then we'll give a nice error message. if (left < 0 || left >= Int16.MaxValue) throw new ArgumentOutOfRangeException("left", left, Environment.GetResourceString("ArgumentOutOfRange_ConsoleBufferBoundaries")); if (top < 0 || top >= Int16.MaxValue) throw new ArgumentOutOfRangeException("top", top, Environment.GetResourceString("ArgumentOutOfRange_ConsoleBufferBoundaries")); Contract.EndContractBlock(); new UIPermission(UIPermissionWindow.SafeTopLevelWindows).Demand(); IntPtr hConsole = ConsoleOutputHandle; Win32Native.COORD coords = new Win32Native.COORD(); coords.X = (short) left; coords.Y = (short) top; bool r = Win32Native.SetConsoleCursorPosition(hConsole, coords); if (!r) { // Give a nice error message for out of range sizes int errorCode = Marshal.GetLastWin32Error(); Win32Native.CONSOLE_SCREEN_BUFFER_INFO csbi = GetBufferInfo(); if (left < 0 || left >= csbi.dwSize.X) throw new ArgumentOutOfRangeException("left", left, Environment.GetResourceString("ArgumentOutOfRange_ConsoleBufferBoundaries")); if (top < 0 || top >= csbi.dwSize.Y) throw new ArgumentOutOfRangeException("top", top, Environment.GetResourceString("ArgumentOutOfRange_ConsoleBufferBoundaries")); __Error.WinIOError(errorCode, String.Empty); } } public static int CursorSize { [System.Security.SecuritySafeCritical] // auto-generated [ResourceExposure(ResourceScope.None)] [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)] get { Win32Native.CONSOLE_CURSOR_INFO cci; IntPtr hConsole = ConsoleOutputHandle; bool r = Win32Native.GetConsoleCursorInfo(hConsole, out cci); if (!r) __Error.WinIOError(); return cci.dwSize; } [System.Security.SecuritySafeCritical] // auto-generated [ResourceExposure(ResourceScope.Process)] [ResourceConsumption(ResourceScope.Process)] set { // Value should be a percentage from [1, 100]. if (value < 1 || value > 100) throw new ArgumentOutOfRangeException("value", value, Environment.GetResourceString("ArgumentOutOfRange_CursorSize")); Contract.EndContractBlock(); new UIPermission(UIPermissionWindow.SafeTopLevelWindows).Demand(); Win32Native.CONSOLE_CURSOR_INFO cci; IntPtr hConsole = ConsoleOutputHandle; bool r = Win32Native.GetConsoleCursorInfo(hConsole, out cci); if (!r) __Error.WinIOError(); cci.dwSize = value; r = Win32Native.SetConsoleCursorInfo(hConsole, ref cci); if (!r) __Error.WinIOError(); } } public static bool CursorVisible { [System.Security.SecuritySafeCritical] // auto-generated [ResourceExposure(ResourceScope.None)] [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)] get { Win32Native.CONSOLE_CURSOR_INFO cci; IntPtr hConsole = ConsoleOutputHandle; bool r = Win32Native.GetConsoleCursorInfo(hConsole, out cci); if (!r) __Error.WinIOError(); return cci.bVisible; } [System.Security.SecuritySafeCritical] // auto-generated [ResourceExposure(ResourceScope.Process)] [ResourceConsumption(ResourceScope.Process)] set { new UIPermission(UIPermissionWindow.SafeTopLevelWindows).Demand(); Win32Native.CONSOLE_CURSOR_INFO cci; IntPtr hConsole = ConsoleOutputHandle; bool r = Win32Native.GetConsoleCursorInfo(hConsole, out cci); if (!r) __Error.WinIOError(); cci.bVisible = value; r = Win32Native.SetConsoleCursorInfo(hConsole, ref cci); if (!r) __Error.WinIOError(); } } #if !FEATURE_CORECLR [System.Security.SecurityCritical] [DllImport(JitHelpers.QCall, CharSet = CharSet.Ansi)] [ResourceExposure(ResourceScope.None)] [SuppressUnmanagedCodeSecurity] private static extern Int32 GetTitleNative(StringHandleOnStack outTitle, out Int32 outTitleLength); public static String Title { [System.Security.SecuritySafeCritical] // auto-generated [ResourceExposure(ResourceScope.None)] [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)] get { string title = null; int titleLength = -1; Int32 r = GetTitleNative(JitHelpers.GetStringHandleOnStack(ref title), out titleLength); if (0 != r) { __Error.WinIOError(r, String.Empty); } if (titleLength > MaxConsoleTitleLength) throw new InvalidOperationException(Environment.GetResourceString("ArgumentOutOfRange_ConsoleTitleTooLong")); Contract.Assert(title.Length == titleLength); return title; } [System.Security.SecuritySafeCritical] // auto-generated [ResourceExposure(ResourceScope.None)] [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)] set { if (value == null) throw new ArgumentNullException("value"); if (value.Length > MaxConsoleTitleLength) throw new ArgumentOutOfRangeException("value", Environment.GetResourceString("ArgumentOutOfRange_ConsoleTitleTooLong")); Contract.EndContractBlock(); new UIPermission(UIPermissionWindow.SafeTopLevelWindows).Demand(); if (!Win32Native.SetConsoleTitle(value)) __Error.WinIOError(); } } #endif // !FEATURE_CORECLR [Flags] internal enum ControlKeyState { RightAltPressed = 0x0001, LeftAltPressed = 0x0002, RightCtrlPressed = 0x0004, LeftCtrlPressed = 0x0008, ShiftPressed = 0x0010, NumLockOn = 0x0020, ScrollLockOn = 0x0040, CapsLockOn = 0x0080, EnhancedKey = 0x0100 } [HostProtection(UI=true)] [ResourceExposure(ResourceScope.Process)] [ResourceConsumption(ResourceScope.Process)] public static ConsoleKeyInfo ReadKey() { return ReadKey(false); } // For tracking Alt+NumPad unicode key sequence. When you press Alt key down // and press a numpad unicode decimal sequence and then release Alt key, the // desired effect is to translate the sequence into one Unicode KeyPress. // We need to keep track of the Alt+NumPad sequence and surface the final // unicode char alone when the Alt key is released. [System.Security.SecurityCritical] // auto-generated private static bool IsAltKeyDown(Win32Native.InputRecord ir) { return (((ControlKeyState) ir.keyEvent.controlKeyState) & (ControlKeyState.LeftAltPressed | ControlKeyState.RightAltPressed)) != 0; } // Skip non key events. Generally we want to surface only KeyDown event // and suppress KeyUp event from the same Key press but there are cases // where the assumption of KeyDown-KeyUp pairing for a given key press // is invalid. For example in IME Unicode keyboard input, we often see // only KeyUp until the key is released. [System.Security.SecurityCritical] // auto-generated private static bool IsKeyDownEvent(Win32Native.InputRecord ir) { return (ir.eventType == Win32Native.KEY_EVENT && ir.keyEvent.keyDown); } [System.Security.SecurityCritical] // auto-generated private static bool IsModKey(Win32Native.InputRecord ir) { // We should also skip over Shift, Control, and Alt, as well as caps lock. // Apparently we don't need to check for 0xA0 through 0xA5, which are keys like // Left Control & Right Control. See the ConsoleKey enum for these values. short keyCode = ir.keyEvent.virtualKeyCode; return ((keyCode >= 0x10 && keyCode <= 0x12) || keyCode == 0x14 || keyCode == 0x90 || keyCode == 0x91); } [System.Security.SecuritySafeCritical] // auto-generated [HostProtection(UI=true)] [ResourceExposure(ResourceScope.Process)] [ResourceConsumption(ResourceScope.Process)] public static ConsoleKeyInfo ReadKey(bool intercept) { Win32Native.InputRecord ir; int numEventsRead = -1; bool r; lock (ReadKeySyncObject) { if (_cachedInputRecord.eventType == Win32Native.KEY_EVENT) { // We had a previous keystroke with repeated characters. ir = _cachedInputRecord; if (_cachedInputRecord.keyEvent.repeatCount == 0) _cachedInputRecord.eventType = -1; else { _cachedInputRecord.keyEvent.repeatCount--; } // We will return one key from this method, so we decrement the // repeatCount here, leaving the cachedInputRecord in the "queue". } else { // We did NOT have a previous keystroke with repeated characters: while (true) { r = Win32Native.ReadConsoleInput(ConsoleInputHandle, out ir, 1, out numEventsRead); if (!r || numEventsRead == 0) { // This will fail when stdin is redirected from a file or pipe. // We could theoretically call Console.Read here, but I // think we might do some things incorrectly then. throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ConsoleReadKeyOnFile")); } short keyCode = ir.keyEvent.virtualKeyCode; // First check for non-keyboard events & discard them. Generally we tap into only KeyDown events and ignore the KeyUp events // but it is possible that we are dealing with a Alt+NumPad unicode key sequence, the final unicode char is revealed only when // the Alt key is released (i.e when the sequence is complete). To avoid noise, when the Alt key is down, we should eat up // any intermediate key strokes (from NumPad) that collectively forms the Unicode character. if (!IsKeyDownEvent(ir)) { // if (keyCode != AltVKCode) continue; } char ch = (char) ir.keyEvent.uChar; // In a Alt+NumPad unicode sequence, when the alt key is released uChar will represent the final unicode character, we need to // surface this. VirtualKeyCode for this event will be Alt from the Alt-Up key event. This is probably not the right code, // especially when we don't expose ConsoleKey.Alt, so this will end up being the hex value (0x12). VK_PACKET comes very // close to being useful and something that we could look into using for this purpose... if (ch == 0) { // Skip mod keys. if (IsModKey(ir)) continue; } // When Alt is down, it is possible that we are in the middle of a Alt+NumPad unicode sequence. // Escape any intermediate NumPad keys whether NumLock is on or not (notepad behavior) ConsoleKey key = (ConsoleKey) keyCode; if (IsAltKeyDown(ir) && ((key >= ConsoleKey.NumPad0 && key <= ConsoleKey.NumPad9) || (key == ConsoleKey.Clear) || (key == ConsoleKey.Insert) || (key >= ConsoleKey.PageUp && key <= ConsoleKey.DownArrow))) { continue; } if (ir.keyEvent.repeatCount > 1) { ir.keyEvent.repeatCount--; _cachedInputRecord = ir; } break; } } // we did NOT have a previous keystroke with repeated characters. } // lock(ReadKeySyncObject) ControlKeyState state = (ControlKeyState) ir.keyEvent.controlKeyState; bool shift = (state & ControlKeyState.ShiftPressed) != 0; bool alt = (state & (ControlKeyState.LeftAltPressed | ControlKeyState.RightAltPressed)) != 0; bool control = (state & (ControlKeyState.LeftCtrlPressed | ControlKeyState.RightCtrlPressed)) != 0; ConsoleKeyInfo info = new ConsoleKeyInfo((char)ir.keyEvent.uChar, (ConsoleKey) ir.keyEvent.virtualKeyCode, shift, alt, control); if (!intercept) Console.Write(ir.keyEvent.uChar); return info; } // public static ConsoleKeyInfo ReadKey(bool intercept) public static bool KeyAvailable { [System.Security.SecuritySafeCritical] // auto-generated [ResourceExposure(ResourceScope.Process)] [ResourceConsumption(ResourceScope.Process)] [HostProtection(UI=true)] get { if (_cachedInputRecord.eventType == Win32Native.KEY_EVENT) return true; Win32Native.InputRecord ir = new Win32Native.InputRecord(); int numEventsRead = 0; while (true) { bool r = Win32Native.PeekConsoleInput(ConsoleInputHandle, out ir, 1, out numEventsRead); if (!r) { int errorCode = Marshal.GetLastWin32Error(); if (errorCode == Win32Native.ERROR_INVALID_HANDLE) throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ConsoleKeyAvailableOnFile")); __Error.WinIOError(errorCode, "stdin"); } if (numEventsRead == 0) return false; // Skip non key-down && mod key events. if (!IsKeyDownEvent(ir) || IsModKey(ir)) { // // Exempt Alt keyUp for possible Alt+NumPad unicode sequence. //short keyCode = ir.keyEvent.virtualKeyCode; //if (!IsKeyDownEvent(ir) && (keyCode == AltVKCode)) // return true; r = Win32Native.ReadConsoleInput(ConsoleInputHandle, out ir, 1, out numEventsRead); if (!r) __Error.WinIOError(); } else { return true; } } } // get } // public static bool KeyAvailable public static bool NumberLock { [System.Security.SecuritySafeCritical] // auto-generated [ResourceExposure(ResourceScope.Process)] [ResourceConsumption(ResourceScope.Process)] get { short s = Win32Native.GetKeyState(NumberLockVKCode); return (s & 1) == 1; } } public static bool CapsLock { [System.Security.SecuritySafeCritical] // auto-generated [ResourceExposure(ResourceScope.Process)] [ResourceConsumption(ResourceScope.Process)] get { short s = Win32Native.GetKeyState(CapsLockVKCode); return (s & 1) == 1; } } public static bool TreatControlCAsInput { [System.Security.SecuritySafeCritical] // auto-generated [ResourceExposure(ResourceScope.None)] [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)] get { IntPtr handle = ConsoleInputHandle; if (handle == Win32Native.INVALID_HANDLE_VALUE) throw new IOException(Environment.GetResourceString("IO.IO_NoConsole")); int mode = 0; bool r = Win32Native.GetConsoleMode(handle, out mode); if (!r) __Error.WinIOError(); return (mode & Win32Native.ENABLE_PROCESSED_INPUT) == 0; } [System.Security.SecuritySafeCritical] // auto-generated [ResourceExposure(ResourceScope.Process)] [ResourceConsumption(ResourceScope.Process)] set { new UIPermission(UIPermissionWindow.SafeTopLevelWindows).Demand(); IntPtr handle = ConsoleInputHandle; if (handle == Win32Native.INVALID_HANDLE_VALUE) throw new IOException(Environment.GetResourceString("IO.IO_NoConsole")); int mode = 0; bool r = Win32Native.GetConsoleMode(handle, out mode); if (value) mode &= ~Win32Native.ENABLE_PROCESSED_INPUT; else mode |= Win32Native.ENABLE_PROCESSED_INPUT; r = Win32Native.SetConsoleMode(handle, mode); if (!r) __Error.WinIOError(); } } #endif // !FEATURE_PAL // During an appdomain unload, we must call into the OS and remove // our delegate from the OS's list of console control handlers. If // we don't do this, the OS will call back on a delegate that no // longer exists. So, subclass CriticalFinalizableObject. // This problem would theoretically exist during process exit for a // single appdomain too, so using a critical finalizer is probably // better than the appdomain unload event (I'm not sure we call that // in the default appdomain during process exit). internal sealed class ControlCHooker : CriticalFinalizerObject { private bool _hooked; [System.Security.SecurityCritical] // auto-generated private Win32Native.ConsoleCtrlHandlerRoutine _handler; [System.Security.SecurityCritical] // auto-generated internal ControlCHooker() { _handler = new Win32Native.ConsoleCtrlHandlerRoutine(BreakEvent); } [ResourceExposure(ResourceScope.None)] [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] ~ControlCHooker() { Unhook(); } [System.Security.SecuritySafeCritical] // auto-generated [ResourceExposure(ResourceScope.Process)] [ResourceConsumption(ResourceScope.Process)] internal void Hook() { if (!_hooked) { bool r = Win32Native.SetConsoleCtrlHandler(_handler, true); if (!r) __Error.WinIOError(); _hooked = true; } } [System.Security.SecuritySafeCritical] // auto-generated [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] [ResourceExposure(ResourceScope.Process)] [ResourceConsumption(ResourceScope.Process)] internal void Unhook() { if (_hooked) { bool r = Win32Native.SetConsoleCtrlHandler(_handler, false); if (!r) __Error.WinIOError(); _hooked = false; } } } // internal sealed class ControlCHooker // A class with data so ControlC handlers can be called on a Threadpool thread. private sealed class ControlCDelegateData { internal ConsoleSpecialKey ControlKey; internal bool Cancel; internal bool DelegateStarted; internal ManualResetEvent CompletionEvent; internal ConsoleCancelEventHandler CancelCallbacks; internal ControlCDelegateData(ConsoleSpecialKey controlKey, ConsoleCancelEventHandler cancelCallbacks) { this.ControlKey = controlKey; this.CancelCallbacks = cancelCallbacks; this.CompletionEvent = new ManualResetEvent(false); // this.Cancel defaults to false // this.DelegateStarted defaults to false } } // Returns true if we've "handled" the break request, false if // we want to terminate the process (or at least let the next // control handler function have a chance). private static bool BreakEvent(int controlType) { // The thread that this gets called back on has a very small stack on 64 bit systems. There is // not enough space to handle a managed exception being caught and thrown. So, queue up a work // item on another thread for the actual event callback. if (controlType == Win32Native.CTRL_C_EVENT || controlType == Win32Native.CTRL_BREAK_EVENT) { // To avoid ---- between remove handler and raising the event ConsoleCancelEventHandler cancelCallbacks = Console._cancelCallbacks; if (cancelCallbacks == null) { return false; } // Create the delegate ConsoleSpecialKey controlKey = (controlType == 0) ? ConsoleSpecialKey.ControlC : ConsoleSpecialKey.ControlBreak; ControlCDelegateData delegateData = new ControlCDelegateData(controlKey, cancelCallbacks); WaitCallback controlCCallback = new WaitCallback(ControlCDelegate); // Queue the delegate if (!ThreadPool.QueueUserWorkItem(controlCCallback, delegateData)) { Contract.Assert(false, "ThreadPool.QueueUserWorkItem returned false without throwing. Unable to execute ControlC handler"); return false; } // Block until the delegate is done. We need to be robust in the face of the work item not executing // but we also want to get control back immediately after it is done and we don't want to give the // handler a fixed time limit in case it needs to display UI. Wait on the event twice, once with a // timout and a second time without if we are sure that the handler actually started. TimeSpan controlCWaitTime = new TimeSpan(0, 0, 30); // 30 seconds delegateData.CompletionEvent.WaitOne(controlCWaitTime, false); if (!delegateData.DelegateStarted) { Contract.Assert(false, "ThreadPool.QueueUserWorkItem did not execute the handler within 30 seconds."); return false; } delegateData.CompletionEvent.WaitOne(); delegateData.CompletionEvent.Close(); return delegateData.Cancel; } return false; } // This is the worker delegate that is called on the Threadpool thread to fire the actual events. It must guarantee that it // signals the caller on the ControlC thread so that it does not block indefinitely. private static void ControlCDelegate(object data) { ControlCDelegateData controlCData = (ControlCDelegateData)data; try { controlCData.DelegateStarted = true; ConsoleCancelEventArgs args = new ConsoleCancelEventArgs(controlCData.ControlKey); controlCData.CancelCallbacks(null, args); controlCData.Cancel = args.Cancel; } finally { controlCData.CompletionEvent.Set(); } } // Note: hooking this event allows you to prevent Control-C from // killing a console app, which is somewhat surprising for users. // Some permission seems appropriate. We chose UI permission for lack // of a better one. However, we also applied host protection // permission here as well, for self-affecting process management. // This allows hosts to prevent people from adding a handler for // this event. public static event ConsoleCancelEventHandler CancelKeyPress { [System.Security.SecuritySafeCritical] // auto-generated [ResourceExposure(ResourceScope.Process)] [ResourceConsumption(ResourceScope.Process)] add { new UIPermission(UIPermissionWindow.SafeTopLevelWindows).Demand(); lock(InternalSyncObject) { // Add this delegate to the pile. _cancelCallbacks += value; // If we haven't registered our control-C handler, do it. if (_hooker == null) { _hooker = new ControlCHooker(); _hooker.Hook(); } } } [System.Security.SecuritySafeCritical] // auto-generated [ResourceExposure(ResourceScope.Process)] [ResourceConsumption(ResourceScope.Process)] remove { new UIPermission(UIPermissionWindow.SafeTopLevelWindows).Demand(); lock(InternalSyncObject) { // If count was 0, call SetConsoleCtrlEvent to remove cb. _cancelCallbacks -= value; Contract.Assert(_cancelCallbacks == null || _cancelCallbacks.GetInvocationList().Length > 0, "Teach Console::CancelKeyPress to handle a non-null but empty list of callbacks"); if (_hooker != null && _cancelCallbacks == null) _hooker.Unhook(); } } } [HostProtection(UI=true)] [ResourceExposure(ResourceScope.Process)] [ResourceConsumption(ResourceScope.Process)] public static Stream OpenStandardError() { return OpenStandardError(DefaultConsoleBufferSize); } #if FEATURE_CORECLR [System.Security.SecurityCritical] // auto-generated #endif [HostProtection(UI=true)] [ResourceExposure(ResourceScope.Process)] [ResourceConsumption(ResourceScope.Process)] public static Stream OpenStandardError(int bufferSize) { if (bufferSize < 0) throw new ArgumentOutOfRangeException("bufferSize", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); Contract.EndContractBlock(); return GetStandardFile(Win32Native.STD_ERROR_HANDLE, FileAccess.Write, bufferSize); } [HostProtection(UI=true)] [ResourceExposure(ResourceScope.Process)] [ResourceConsumption(ResourceScope.Process)] public static Stream OpenStandardInput() { return OpenStandardInput(DefaultConsoleBufferSize); } #if FEATURE_CORECLR [System.Security.SecurityCritical] // auto-generated #endif [HostProtection(UI=true)] [ResourceExposure(ResourceScope.Process)] [ResourceConsumption(ResourceScope.Process)] public static Stream OpenStandardInput(int bufferSize) { if (bufferSize < 0) throw new ArgumentOutOfRangeException("bufferSize", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); Contract.EndContractBlock(); return GetStandardFile(Win32Native.STD_INPUT_HANDLE, FileAccess.Read, bufferSize); } [HostProtection(UI=true)] [ResourceExposure(ResourceScope.Process)] [ResourceConsumption(ResourceScope.Process)] public static Stream OpenStandardOutput() { return OpenStandardOutput(DefaultConsoleBufferSize); } #if FEATURE_CORECLR [System.Security.SecurityCritical] // auto-generated #endif [HostProtection(UI=true)] [ResourceExposure(ResourceScope.Process)] [ResourceConsumption(ResourceScope.Process)] public static Stream OpenStandardOutput(int bufferSize) { if (bufferSize < 0) throw new ArgumentOutOfRangeException("bufferSize", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); Contract.EndContractBlock(); return GetStandardFile(Win32Native.STD_OUTPUT_HANDLE, FileAccess.Write, bufferSize); } #if FEATURE_CORECLR [System.Security.SecurityCritical] // auto-generated #else [System.Security.SecuritySafeCritical] #endif [HostProtection(UI=true)] [ResourceExposure(ResourceScope.AppDomain)] public static void SetIn(TextReader newIn) { if (newIn == null) throw new ArgumentNullException("newIn"); Contract.EndContractBlock(); #pragma warning disable 618 new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Demand(); #pragma warning restore 618 newIn = TextReader.Synchronized(newIn); lock(InternalSyncObject) { _in = newIn; } } #if FEATURE_CORECLR [System.Security.SecurityCritical] // auto-generated #else [System.Security.SecuritySafeCritical] #endif [HostProtection(UI=true)] [ResourceExposure(ResourceScope.AppDomain)] public static void SetOut(TextWriter newOut) { if (newOut == null) throw new ArgumentNullException("newOut"); Contract.EndContractBlock(); #pragma warning disable 618 new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Demand(); #pragma warning restore 618 #if FEATURE_CODEPAGES_FILE // if no codepages file then we are locked into default codepage and this field is not used _isOutTextWriterRedirected = true; #endif newOut = TextWriter.Synchronized(newOut); lock(InternalSyncObject) { _out = newOut; } } #if FEATURE_CORECLR [System.Security.SecurityCritical] // auto-generated #else [System.Security.SecuritySafeCritical] #endif [HostProtection(UI=true)] [ResourceExposure(ResourceScope.AppDomain)] public static void SetError(TextWriter newError) { if (newError == null) throw new ArgumentNullException("newError"); Contract.EndContractBlock(); #pragma warning disable 618 new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Demand(); #pragma warning restore 618 #if FEATURE_CODEPAGES_FILE // if no codepages file then we are locked into default codepage and this field is not used _isErrorTextWriterRedirected = true; #endif newError = TextWriter.Synchronized(newError); lock(InternalSyncObject) { _error = newError; } } // // Give a hint to the code generator to not inline the common console methods. The console methods are // not performance critical. It is unnecessary code bloat to have them inlined. // // Moreover, simple repros for codegen bugs are often console-based. It is tedious to manually filter out // the inlined console writelines from them. // [HostProtection(UI=true)] [MethodImplAttribute(MethodImplOptions.NoInlining)] public static int Read() { return In.Read(); } [HostProtection(UI=true)] [MethodImplAttribute(MethodImplOptions.NoInlining)] public static String ReadLine() { return In.ReadLine(); } [HostProtection(UI=true)] [MethodImplAttribute(MethodImplOptions.NoInlining)] public static void WriteLine() { Out.WriteLine(); } [HostProtection(UI=true)] [MethodImplAttribute(MethodImplOptions.NoInlining)] public static void WriteLine(bool value) { Out.WriteLine(value); } [HostProtection(UI=true)] [MethodImplAttribute(MethodImplOptions.NoInlining)] public static void WriteLine(char value) { Out.WriteLine(value); } [HostProtection(UI=true)] [MethodImplAttribute(MethodImplOptions.NoInlining)] public static void WriteLine(char[] buffer) { Out.WriteLine(buffer); } [HostProtection(UI=true)] [MethodImplAttribute(MethodImplOptions.NoInlining)] public static void WriteLine(char[] buffer, int index, int count) { Out.WriteLine(buffer, index, count); } [HostProtection(UI=true)] [MethodImplAttribute(MethodImplOptions.NoInlining)] public static void WriteLine(decimal value) { Out.WriteLine(value); } [HostProtection(UI=true)] [MethodImplAttribute(MethodImplOptions.NoInlining)] public static void WriteLine(double value) { Out.WriteLine(value); } [HostProtection(UI=true)] [MethodImplAttribute(MethodImplOptions.NoInlining)] public static void WriteLine(float value) { Out.WriteLine(value); } [HostProtection(UI=true)] [MethodImplAttribute(MethodImplOptions.NoInlining)] public static void WriteLine(int value) { Out.WriteLine(value); } [HostProtection(UI=true)] [CLSCompliant(false)] [MethodImplAttribute(MethodImplOptions.NoInlining)] public static void WriteLine(uint value) { Out.WriteLine(value); } [HostProtection(UI=true)] [MethodImplAttribute(MethodImplOptions.NoInlining)] public static void WriteLine(long value) { Out.WriteLine(value); } [HostProtection(UI=true)] [CLSCompliant(false)] [MethodImplAttribute(MethodImplOptions.NoInlining)] public static void WriteLine(ulong value) { Out.WriteLine(value); } [HostProtection(UI=true)] [MethodImplAttribute(MethodImplOptions.NoInlining)] public static void WriteLine(Object value) { Out.WriteLine(value); } [HostProtection(UI=true)] [MethodImplAttribute(MethodImplOptions.NoInlining)] public static void WriteLine(String value) { Out.WriteLine(value); } [HostProtection(UI=true)] [MethodImplAttribute(MethodImplOptions.NoInlining)] public static void WriteLine(String format, Object arg0) { Out.WriteLine(format, arg0); } [HostProtection(UI=true)] [MethodImplAttribute(MethodImplOptions.NoInlining)] public static void WriteLine(String format, Object arg0, Object arg1) { Out.WriteLine(format, arg0, arg1); } [HostProtection(UI=true)] [MethodImplAttribute(MethodImplOptions.NoInlining)] public static void WriteLine(String format, Object arg0, Object arg1, Object arg2) { Out.WriteLine(format, arg0, arg1, arg2); } [HostProtection(UI=true)] [CLSCompliant(false)] [MethodImplAttribute(MethodImplOptions.NoInlining)] public static void WriteLine(String format, Object arg0, Object arg1, Object arg2,Object arg3, __arglist) { Object[] objArgs; int argCount; ArgIterator args = new ArgIterator(__arglist); //+4 to account for the 4 hard-coded arguments at the beginning of the list. argCount = args.GetRemainingCount() + 4; objArgs = new Object[argCount]; //Handle the hard-coded arguments objArgs[0] = arg0; objArgs[1] = arg1; objArgs[2] = arg2; objArgs[3] = arg3; //Walk all of the args in the variable part of the argument list. for (int i=4; i