diff options
Diffstat (limited to 'src/mscorlib/src/System/Console.cs')
-rw-r--r-- | src/mscorlib/src/System/Console.cs | 2140 |
1 files changed, 2140 insertions, 0 deletions
diff --git a/src/mscorlib/src/System/Console.cs b/src/mscorlib/src/System/Console.cs new file mode 100644 index 0000000000..d371777168 --- /dev/null +++ b/src/mscorlib/src/System/Console.cs @@ -0,0 +1,2140 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/*============================================================================= +** +** +** +** 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; + + 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; + +#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; + + // 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; +#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<Object>() != null); + if (s_InternalSyncObject == null) { + Object o = new Object(); +#pragma warning disable 0420 + Interlocked.CompareExchange<Object>(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<Object>() != null); + if (s_ReadKeySyncObject == null) + { + Object o = new Object(); +#pragma warning disable 0420 + Interlocked.CompareExchange<Object>(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 + get { + if (_consoleInputHandle == IntPtr.Zero) { + _consoleInputHandle = Win32Native.GetStdHandle(Win32Native.STD_INPUT_HANDLE); + } + return _consoleInputHandle; + } + } + + private static IntPtr ConsoleOutputHandle { + [System.Security.SecurityCritical] // auto-generated + get { + if (_consoleOutputHandle == IntPtr.Zero) { + _consoleOutputHandle = Win32Native.GetStdHandle(Win32Native.STD_OUTPUT_HANDLE); + } + return _consoleOutputHandle; + } + } + + +#if !FEATURE_CORECLR + [System.Security.SecuritySafeCritical] + 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] + 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)] + get { + Contract.Ensures(Contract.Result<TextReader>() != 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)] + get { + Contract.Ensures(Contract.Result<TextWriter>() != null); + // Hopefully this is inlineable. + if (_out == null) + InitializeStdOutError(true); + return _out; + } + } + + public static TextWriter Error { + [HostProtection(UI=true)] + get { + Contract.Ensures(Contract.Result<TextWriter>() != 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 + 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 + 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 + 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 + 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 + 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<Encoding>() != 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 + 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<Encoding>() != 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 + 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 + + [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 + 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 + 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 + 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 + 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 + 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 + 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); + } + + 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 + 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<sourceTop + sourceHeight; i++) { + writeCoord.Y = (short) i; + r = Win32Native.FillConsoleOutputCharacter(ConsoleOutputHandle, sourceChar, sourceWidth, writeCoord, out numWritten); + Contract.Assert(numWritten == sourceWidth, "FillConsoleOutputCharacter wrote the wrong number of chars!"); + if (!r) + __Error.WinIOError(); + + r = Win32Native.FillConsoleOutputAttribute(ConsoleOutputHandle, attr, sourceWidth, writeCoord, out numWritten); + if (!r) + __Error.WinIOError(); + } + + // Write text to new location + Win32Native.SMALL_RECT writeRegion = new Win32Native.SMALL_RECT(); + writeRegion.Left = (short) targetLeft; + writeRegion.Right = (short) (targetLeft + sourceWidth); + writeRegion.Top = (short) targetTop; + writeRegion.Bottom = (short) (targetTop + sourceHeight); + + fixed(Win32Native.CHAR_INFO* pCharInfo = data) + r = Win32Native.WriteConsoleOutput(ConsoleOutputHandle, pCharInfo, bufferSize, bufferCoord, ref writeRegion); + } // MoveBufferArea + + [System.Security.SecurityCritical] // auto-generated + private static Win32Native.CONSOLE_SCREEN_BUFFER_INFO GetBufferInfo() + { + bool junk; + return GetBufferInfo(true, out junk); + } + + // For apps that don't have a console (like Windows apps), they might + // run other code that includes color console output. Allow a mechanism + // where that code won't throw an exception for simple errors. + [System.Security.SecuritySafeCritical] // auto-generated + private static Win32Native.CONSOLE_SCREEN_BUFFER_INFO GetBufferInfo(bool throwOnNoConsole, out bool succeeded) + { + succeeded = false; + Win32Native.CONSOLE_SCREEN_BUFFER_INFO csbi; + bool success; + + IntPtr hConsole = ConsoleOutputHandle; + if (hConsole == Win32Native.INVALID_HANDLE_VALUE) { + if (!throwOnNoConsole) + return new Win32Native.CONSOLE_SCREEN_BUFFER_INFO(); + else + throw new IOException(Environment.GetResourceString("IO.IO_NoConsole")); + } + + // Note that if stdout is redirected to a file, the console handle + // may be a file. If this fails, try stderr and stdin. + success = Win32Native.GetConsoleScreenBufferInfo(hConsole, out csbi); + if (!success) { + success = Win32Native.GetConsoleScreenBufferInfo(Win32Native.GetStdHandle(Win32Native.STD_ERROR_HANDLE), out csbi); + if (!success) + success = Win32Native.GetConsoleScreenBufferInfo(Win32Native.GetStdHandle(Win32Native.STD_INPUT_HANDLE), out csbi); + + if (!success) { + int errorCode = Marshal.GetLastWin32Error(); + if (errorCode == Win32Native.ERROR_INVALID_HANDLE && !throwOnNoConsole) + return new Win32Native.CONSOLE_SCREEN_BUFFER_INFO(); + __Error.WinIOError(errorCode, null); + } + } + + if (!_haveReadDefaultColors) { + // Fetch the default foreground and background color for the + // ResetColor method. + Contract.Assert((int)Win32Native.Color.ColorMask == 0xff, "Make sure one byte is large enough to store a Console color value!"); + _defaultColors = (byte) (csbi.wAttributes & (short) Win32Native.Color.ColorMask); + _haveReadDefaultColors = true; + } + + succeeded = true; + return csbi; + } + + public static int BufferHeight { + [System.Security.SecuritySafeCritical] // auto-generated + get { + Win32Native.CONSOLE_SCREEN_BUFFER_INFO csbi = GetBufferInfo(); + return csbi.dwSize.Y; + } + set { + SetBufferSize(BufferWidth, value); + } + } + + public static int BufferWidth { + [System.Security.SecuritySafeCritical] // auto-generated + get { + Win32Native.CONSOLE_SCREEN_BUFFER_INFO csbi = GetBufferInfo(); + return csbi.dwSize.X; + } + set { + SetBufferSize(value, BufferHeight); + } + } + + [System.Security.SecuritySafeCritical] // auto-generated + public static void SetBufferSize(int width, int height) + { + new UIPermission(UIPermissionWindow.SafeTopLevelWindows).Demand(); + + // Ensure the new size is not smaller than the console window + Win32Native.CONSOLE_SCREEN_BUFFER_INFO csbi = GetBufferInfo(); + Win32Native.SMALL_RECT srWindow = csbi.srWindow; + if (width < srWindow.Right + 1 || width >= 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 + get { + Win32Native.CONSOLE_SCREEN_BUFFER_INFO csbi = GetBufferInfo(); + return csbi.srWindow.Bottom - csbi.srWindow.Top + 1; + } + set { + SetWindowSize(WindowWidth, value); + } + } + + public static int WindowWidth { + [System.Security.SecuritySafeCritical] // auto-generated + get { + Win32Native.CONSOLE_SCREEN_BUFFER_INFO csbi = GetBufferInfo(); + return csbi.srWindow.Right - csbi.srWindow.Left + 1; + } + set { + SetWindowSize(value, WindowHeight); + } + } + + [System.Security.SecuritySafeCritical] // auto-generated + 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 + 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 + 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 + get { + Win32Native.CONSOLE_SCREEN_BUFFER_INFO csbi = GetBufferInfo(); + return csbi.srWindow.Left; + } + set { + SetWindowPosition(value, WindowTop); + } + } + + public static int WindowTop { + [System.Security.SecuritySafeCritical] // auto-generated + get { + Win32Native.CONSOLE_SCREEN_BUFFER_INFO csbi = GetBufferInfo(); + return csbi.srWindow.Top; + } + set { + SetWindowPosition(WindowLeft, value); + } + } + + [System.Security.SecuritySafeCritical] // auto-generated + 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 + get { + Win32Native.CONSOLE_SCREEN_BUFFER_INFO csbi = GetBufferInfo(); + return csbi.dwCursorPosition.X; + } + set { + SetCursorPosition(value, CursorTop); + } + } + + public static int CursorTop { + [System.Security.SecuritySafeCritical] // auto-generated + get { + Win32Native.CONSOLE_SCREEN_BUFFER_INFO csbi = GetBufferInfo(); + return csbi.dwCursorPosition.Y; + } + set { + SetCursorPosition(CursorLeft, value); + } + } + + [System.Security.SecuritySafeCritical] // auto-generated + 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 + 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 + 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 + 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 + 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(); + } + } + + [System.Security.SecurityCritical] + [DllImport(JitHelpers.QCall, CharSet = CharSet.Ansi)] + [SuppressUnmanagedCodeSecurity] + private static extern Int32 GetTitleNative(StringHandleOnStack outTitle, out Int32 outTitleLength); + + public static String Title { + [System.Security.SecuritySafeCritical] // auto-generated + 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 + 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(); + } + } + + [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)] + 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)] + 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)) { + // Unicode IME input comes through as KeyUp event with no accompanying KeyDown. + 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 + [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)) { + // Unicode IME input comes through as KeyUp event with no accompanying KeyDown + + // 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 + get { + short s = Win32Native.GetKeyState(NumberLockVKCode); + return (s & 1) == 1; + } + } + + public static bool CapsLock { + [System.Security.SecuritySafeCritical] // auto-generated + get { + short s = Win32Native.GetKeyState(CapsLockVKCode); + return (s & 1) == 1; + } + } + + public static bool TreatControlCAsInput { + [System.Security.SecuritySafeCritical] // auto-generated + 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 + 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(); + } + } + + // 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); + } + + ~ControlCHooker() + { + Unhook(); + } + + [System.Security.SecuritySafeCritical] // auto-generated + 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)] + 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 the race condition 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 + 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 + 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)] + public static Stream OpenStandardError() { + return OpenStandardError(DefaultConsoleBufferSize); + } + + #if FEATURE_CORECLR + [System.Security.SecurityCritical] // auto-generated + #endif + [HostProtection(UI=true)] + 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)] + public static Stream OpenStandardInput() { + return OpenStandardInput(DefaultConsoleBufferSize); + } + + #if FEATURE_CORECLR + [System.Security.SecurityCritical] // auto-generated + #endif + [HostProtection(UI=true)] + 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)] + public static Stream OpenStandardOutput() { + return OpenStandardOutput(DefaultConsoleBufferSize); + } + + #if FEATURE_CORECLR + [System.Security.SecurityCritical] // auto-generated + #endif + [HostProtection(UI=true)] + 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)] + 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)] + 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)] + 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<argCount; i++) { + objArgs[i] = TypedReference.ToObject(args.GetNextArg()); + } + + Out.WriteLine(format, objArgs); + } + + + [HostProtection(UI=true)] + [MethodImplAttribute(MethodImplOptions.NoInlining)] + public static void WriteLine(String format, params Object[] arg) + { + if (arg == null) // avoid ArgumentNullException from String.Format + Out.WriteLine(format, null, null); // faster than Out.WriteLine(format, (Object)arg); + else + Out.WriteLine(format, arg); + } + + [HostProtection(UI=true)] + [MethodImplAttribute(MethodImplOptions.NoInlining)] + public static void Write(String format, Object arg0) + { + Out.Write(format, arg0); + } + + [HostProtection(UI=true)] + [MethodImplAttribute(MethodImplOptions.NoInlining)] + public static void Write(String format, Object arg0, Object arg1) + { + Out.Write(format, arg0, arg1); + } + + [HostProtection(UI=true)] + [MethodImplAttribute(MethodImplOptions.NoInlining)] + public static void Write(String format, Object arg0, Object arg1, Object arg2) + { + Out.Write(format, arg0, arg1, arg2); + } + + [HostProtection(UI=true)] + [CLSCompliant(false)] + [MethodImplAttribute(MethodImplOptions.NoInlining)] + public static void Write(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<argCount; i++) { + objArgs[i] = TypedReference.ToObject(args.GetNextArg()); + } + + Out.Write(format, objArgs); + } + + + [HostProtection(UI=true)] + [MethodImplAttribute(MethodImplOptions.NoInlining)] + public static void Write(String format, params Object[] arg) + { + if (arg == null) // avoid ArgumentNullException from String.Format + Out.Write(format, null, null); // faster than Out.Write(format, (Object)arg); + else + Out.Write(format, arg); + } + + [HostProtection(UI=true)] + [MethodImplAttribute(MethodImplOptions.NoInlining)] + public static void Write(bool value) + { + Out.Write(value); + } + + [HostProtection(UI=true)] + [MethodImplAttribute(MethodImplOptions.NoInlining)] + public static void Write(char value) + { + Out.Write(value); + } + + [HostProtection(UI=true)] + [MethodImplAttribute(MethodImplOptions.NoInlining)] + public static void Write(char[] buffer) + { + Out.Write(buffer); + } + + [HostProtection(UI=true)] + [MethodImplAttribute(MethodImplOptions.NoInlining)] + public static void Write(char[] buffer, int index, int count) + { + Out.Write(buffer, index, count); + } + + [HostProtection(UI=true)] + [MethodImplAttribute(MethodImplOptions.NoInlining)] + public static void Write(double value) + { + Out.Write (value); + } + + [HostProtection(UI=true)] + [MethodImplAttribute(MethodImplOptions.NoInlining)] + public static void Write(decimal value) + { + Out.Write (value); + } + + [HostProtection(UI=true)] + [MethodImplAttribute(MethodImplOptions.NoInlining)] + public static void Write(float value) + { + Out.Write (value); + } + + [HostProtection(UI=true)] + [MethodImplAttribute(MethodImplOptions.NoInlining)] + public static void Write(int value) + { + Out.Write (value); + } + + [HostProtection(UI=true)] + [CLSCompliant(false)] + [MethodImplAttribute(MethodImplOptions.NoInlining)] + public static void Write(uint value) + { + Out.Write (value); + } + + [HostProtection(UI=true)] + [MethodImplAttribute(MethodImplOptions.NoInlining)] + public static void Write(long value) + { + Out.Write (value); + } + + [HostProtection(UI=true)] + [CLSCompliant(false)] + [MethodImplAttribute(MethodImplOptions.NoInlining)] + public static void Write(ulong value) + { + Out.Write (value); + } + + [HostProtection(UI=true)] + [MethodImplAttribute(MethodImplOptions.NoInlining)] + public static void Write(Object value) + { + Out.Write (value); + } + + [HostProtection(UI=true)] + [MethodImplAttribute(MethodImplOptions.NoInlining)] + public static void Write(String value) + { + Out.Write (value); + } + + } // public static class Console +} // namespace System |