The Labs \ Source Viewer \ SSCLI \ System.IO \ __ConsoleStream

  1. // ==++==
  2. //
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. //
  14. // ==--==
  15. /*============================================================
  16. **
  17. ** Class:  ConsoleStream
  18. **
  19. **
  20. ** Purpose: Exposes a separate Stream for Console IO and
  21. ** handles WinCE appropriately.  Also keeps us from using the
  22. ** ThreadPool for all Console output.
  23. **
  24. **
  25. ===========================================================*/
  26. using System;
  27. using System.Runtime.InteropServices;
  28. using System.Security;
  29. using Microsoft.Win32;
  30. using Microsoft.Win32.SafeHandles;
  31. using System.Runtime.CompilerServices;
  32. using System.Runtime.Versioning;
  33. namespace System.IO
  34. {
  35.    
  36.     internal sealed class __ConsoleStream : Stream
  37.     {
  38.         internal const int DefaultBufferSize = 128;
  39.        
  40.         // From winerror.h
  41.         private const int ERROR_BROKEN_PIPE = 109;
  42.         // ERROR_NO_DATA ("The pipe is being closed") is returned when we write to
  43.         // a console that is closing.
  44.         private const int ERROR_NO_DATA = 232;
  45.        
  46.         private SafeFileHandle _handle;
  47.         private bool _canRead;
  48.         private bool _canWrite;
  49.        
  50.         [ResourceExposure(ResourceScope.Process)]
  51.         internal __ConsoleStream(SafeFileHandle handle, FileAccess access)
  52.         {
  53.             BCLDebug.Assert(handle != null && !handle.IsInvalid, "__ConsoleStream expects a valid handle!");
  54.             _handle = handle;
  55.             _canRead = access == FileAccess.Read;
  56.             _canWrite = access == FileAccess.Write;
  57.         }
  58.        
  59.         public override bool CanRead {
  60.             get { return _canRead; }
  61.         }
  62.        
  63.         public override bool CanWrite {
  64.             get { return _canWrite; }
  65.         }
  66.        
  67.         public override bool CanSeek {
  68.             get { return false; }
  69.         }
  70.        
  71.         public override long Length {
  72.             get {
  73.                 __Error.SeekNotSupported();
  74.                 return 0;
  75.                 // compiler appeasement
  76.             }
  77.         }
  78.        
  79.         public override long Position {
  80.             get {
  81.                 __Error.SeekNotSupported();
  82.                 return 0;
  83.                 // compiler appeasement
  84.             }
  85.             set { __Error.SeekNotSupported(); }
  86.         }
  87.        
  88.         protected override void Dispose(bool disposing)
  89.         {
  90.             // We're probably better off not closing the OS handle here. First,
  91.             // we allow a program to get multiple instances of __ConsoleStreams
  92.             // around the same OS handle, so closing one handle would invalidate
  93.             // them all. Additionally, we want a second AppDomain to be able to
  94.             // write to stdout if a second AppDomain quits.
  95.             if (_handle != null) {
  96.                 _handle = null;
  97.             }
  98.             _canRead = false;
  99.             _canWrite = false;
  100.             base.Dispose(disposing);
  101.         }
  102.        
  103.         public override void Flush()
  104.         {
  105.             if (_handle == null)
  106.                 __Error.FileNotOpen();
  107.             if (!CanWrite)
  108.                 __Error.WriteNotSupported();
  109.         }
  110.        
  111.         public override void SetLength(long value)
  112.         {
  113.             __Error.SeekNotSupported();
  114.         }
  115.        
  116.         [ResourceExposure(ResourceScope.None)]
  117.         [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
  118.         public override int Read(        [In(), Out()]
  119. byte[] buffer, int offset, int count)
  120.         {
  121.             if (buffer == null)
  122.                 throw new ArgumentNullException("buffer");
  123.             if (offset < 0 || count < 0)
  124.                 throw new ArgumentOutOfRangeException((offset < 0 ? "offset" : "count"), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
  125.             if (buffer.Length - offset < count)
  126.                 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
  127.             if (!_canRead)
  128.                 __Error.ReadNotSupported();
  129.            
  130.             int errorCode = 0;
  131.             int result = ReadFileNative(_handle, buffer, offset, count, 0, out errorCode);
  132.             if (result == -1) {
  133.                 __Error.WinIOError(errorCode, String.Empty);
  134.             }
  135.             return result;
  136.         }
  137.        
  138.         public override long Seek(long offset, SeekOrigin origin)
  139.         {
  140.             __Error.SeekNotSupported();
  141.             return 0;
  142.             // compiler appeasement
  143.         }
  144.        
  145.         [ResourceExposure(ResourceScope.None)]
  146.         [ResourceConsumption(ResourceScope.Process, ResourceScope.Process)]
  147.         public override void Write(byte[] buffer, int offset, int count)
  148.         {
  149.             if (buffer == null)
  150.                 throw new ArgumentNullException("buffer");
  151.             if (offset < 0 || count < 0)
  152.                 throw new ArgumentOutOfRangeException((offset < 0 ? "offset" : "count"), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
  153.             if (buffer.Length - offset < count)
  154.                 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
  155.             if (!_canWrite)
  156.                 __Error.WriteNotSupported();
  157.            
  158.             int errorCode = 0;
  159.             int result = WriteFileNative(_handle, buffer, offset, count, 0, out errorCode);
  160.             if (result == -1) {
  161.                 //BCLDebug.ConsoleError("__ConsoleStream::Write: throwing on error. Error code: "+errorCode+" 0x"+errorCode.ToString("x")+" handle: "+_handle.ToString());
  162.                 __Error.WinIOError(errorCode, String.Empty);
  163.             }
  164.             return;
  165.         }
  166.        
  167.         // P/Invoke wrappers for writing to and from a file, nearly identical
  168.         // to the ones on FileStream. These are duplicated to save startup/hello
  169.         // world working set.
  170.         [ResourceExposure(ResourceScope.Process)]
  171.         [ResourceConsumption(ResourceScope.Process)]
  172.         unsafe private static int ReadFileNative(SafeFileHandle hFile, byte[] bytes, int offset, int count, int mustBeZero, out int errorCode)
  173.         {
  174.             BCLDebug.Assert(offset >= 0, "offset >= 0");
  175.             BCLDebug.Assert(count >= 0, "count >= 0");
  176.             BCLDebug.Assert(bytes != null, "bytes != null");
  177.            
  178.             // Don't corrupt memory when multiple threads are erroneously writing
  179.             // to this stream simultaneously.
  180.             if (bytes.Length - offset < count)
  181.                 throw new IndexOutOfRangeException(Environment.GetResourceString("IndexOutOfRange_IORaceCondition"));
  182.            
  183.             // You can't use the fixed statement on an array of length 0.
  184.             if (bytes.Length == 0) {
  185.                 errorCode = 0;
  186.                 return 0;
  187.             }
  188.            
  189.             int r;
  190.             int numBytesRead;
  191.             fixed (byte* p = bytes) {
  192.                 r = ReadFile(hFile, p + offset, count, out numBytesRead, Win32Native.NULL);
  193.             }
  194.             if (r == 0) {
  195.                 errorCode = Marshal.GetLastWin32Error();
  196.                 if (errorCode == ERROR_BROKEN_PIPE) {
  197.                     // A pipe into stdin was closed. Not an error, but EOF.
  198.                     return 0;
  199.                 }
  200.                 return -1;
  201.             }
  202.             else
  203.                 errorCode = 0;
  204.             return numBytesRead;
  205.         }
  206.        
  207.         [ResourceExposure(ResourceScope.Process)]
  208.         [ResourceConsumption(ResourceScope.Process)]
  209.         unsafe private static int WriteFileNative(SafeFileHandle hFile, byte[] bytes, int offset, int count, int mustBeZero, out int errorCode)
  210.         {
  211.             BCLDebug.Assert(offset >= 0, "offset >= 0");
  212.             BCLDebug.Assert(count >= 0, "count >= 0");
  213.             BCLDebug.Assert(bytes != null, "bytes != null");
  214.             BCLDebug.Assert(bytes.Length >= offset + count, "bytes.Length >= offset + count");
  215.            
  216.             // You can't use the fixed statement on an array of length 0.
  217.             if (bytes.Length == 0) {
  218.                 errorCode = 0;
  219.                 return 0;
  220.             }
  221.            
  222.             int numBytesWritten = 0;
  223.             int r;
  224.             fixed (byte* p = bytes) {
  225.                 r = WriteFile(hFile, p + offset, count, out numBytesWritten, Win32Native.NULL);
  226.             }
  227.             if (r == 0) {
  228.                 errorCode = Marshal.GetLastWin32Error();
  229.                 if (errorCode == ERROR_NO_DATA || errorCode == ERROR_BROKEN_PIPE)
  230.                     return 0;
  231.                 return -1;
  232.             }
  233.             else {
  234.                 errorCode = 0;
  235.             }
  236.             return numBytesWritten;
  237.         }
  238.        
  239.         // The P/Invoke declarations for ReadFile and WriteFile are here for a reason! This prevents us from loading several classes
  240.         // in the trivial hello world case.
  241.         [DllImport(Win32Native.KERNEL32, SetLastError = true), SuppressUnmanagedCodeSecurityAttribute()]
  242.         [ResourceExposure(ResourceScope.Process)]
  243.         unsafe private static extern int ReadFile(SafeFileHandle handle, byte* bytes, int numBytesToRead, out int numBytesRead, IntPtr mustBeZero);
  244.        
  245.         [DllImport(Win32Native.KERNEL32, SetLastError = true), SuppressUnmanagedCodeSecurityAttribute()]
  246.         [ResourceExposure(ResourceScope.Process)]
  247.         unsafe static internal extern int WriteFile(SafeFileHandle handle, byte* bytes, int numBytesToWrite, out int numBytesWritten, IntPtr mustBeZero);
  248.     }
  249. }

Developer Fusion