Advertisement
Guest User

Robert Fraser

a guest
Sep 21st, 2009
5,543
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 5.85 KB | None | 0 0
  1. using System;
  2. using System.Diagnostics;
  3. using System.IO;
  4. using System.IO.Pipes;
  5. using System.Runtime.InteropServices;
  6. using System.Text;
  7. using System.Threading;
  8. using mime.shared.util;
  9.  
  10. namespace mime.server.util
  11. {
  12.     internal sealed class ConsoleRedirector : IDisposable
  13.     {
  14.         private static readonly Log log = LogManager.getLog(typeof(ConsoleRedirector));
  15.         private static ConsoleRedirector _instance;
  16.  
  17.         public static void attach(ILogListener listener)
  18.         {
  19.             Debug.Assert(null == _instance);
  20.             _instance = new ConsoleRedirector(listener);
  21.         }
  22.  
  23.         public static void detatch()
  24.         {
  25.             _instance.Dispose();
  26.             _instance = null;
  27.         }
  28.  
  29.         public static bool isAttached
  30.         {
  31.             get
  32.             {
  33.                 return null != _instance;
  34.             }
  35.         }
  36.  
  37.         //----------------------------------------------------------------------
  38.  
  39.         private const int PERIOD = 500;
  40.         private const int BUFFER_SIZE = 4096;
  41.         private volatile bool _isDisposed;
  42.         private readonly ILogListener _logListener;
  43.         private readonly IntPtr _stdout;
  44.         private readonly IntPtr _stderr;
  45.         private readonly Mutex _sync;
  46.         private readonly Timer _timer;
  47.         private readonly char[] _buffer;
  48.         private readonly AnonymousPipeServerStream _outServer;
  49.         private readonly AnonymousPipeServerStream _errServer;
  50.         private readonly TextReader _outClient;
  51.         private readonly TextReader _errClient;
  52.  
  53.         // ReSharper disable UseObjectOrCollectionInitializer
  54.         private ConsoleRedirector(ILogListener logListener)
  55.         {
  56.             log.info("Redirecting stdout and stderr to log");
  57.  
  58.             bool ret;
  59.             AnonymousPipeClientStream client;
  60.  
  61.             _logListener = logListener;
  62.             _stdout = GetStdHandle(STD_OUTPUT_HANDLE);
  63.             _stderr = GetStdHandle(STD_ERROR_HANDLE);
  64.             _sync = new Mutex();
  65.             _buffer = new char[BUFFER_SIZE];
  66.            
  67.             _outServer = new AnonymousPipeServerStream(PipeDirection.Out);
  68.             client = new AnonymousPipeClientStream(PipeDirection.In, _outServer.ClientSafePipeHandle);
  69.             //client.ReadTimeout = 0;
  70.             Debug.Assert(_outServer.IsConnected);
  71.             _outClient = new StreamReader(client, Encoding.Default);
  72.             ret = SetStdHandle(STD_OUTPUT_HANDLE, _outServer.SafePipeHandle.DangerousGetHandle());
  73.             Debug.Assert(ret);
  74.  
  75.             _errServer = new AnonymousPipeServerStream(PipeDirection.Out);
  76.             client = new AnonymousPipeClientStream(PipeDirection.In, _errServer.ClientSafePipeHandle);
  77.             //client.ReadTimeout = 0;
  78.             Debug.Assert(_errServer.IsConnected);
  79.             _errClient = new StreamReader(client, Encoding.Default);
  80.             ret = SetStdHandle(STD_ERROR_HANDLE, _errServer.SafePipeHandle.DangerousGetHandle());
  81.             Debug.Assert(ret);
  82.  
  83.             Thread outThread = new Thread(doRead);
  84.             Thread errThread = new Thread(doRead);
  85.             outThread.Name = "stdout logger";
  86.             errThread.Name = "stderr logger";
  87.             outThread.Start(_outClient);
  88.             errThread.Start(_errClient);
  89.             _timer = new Timer(flush, null, PERIOD, PERIOD);
  90.         }
  91.         // ReSharper restore UseObjectOrCollectionInitializer
  92.  
  93.         private void flush(object state)
  94.         {
  95.             _outServer.Flush();
  96.             _errServer.Flush();
  97.         }
  98.  
  99.         private void doRead(object clientObj)
  100.         {
  101.             TextReader client = (TextReader) clientObj;
  102.             try
  103.             {
  104.                 while(true)
  105.                 {
  106.                     int read = client.Read(_buffer, 0, BUFFER_SIZE);
  107.                     if(read > 0)
  108.                         _logListener.writeChars(_buffer, 0, read);
  109.                 }
  110.             }
  111.             catch(ObjectDisposedException)
  112.             {
  113.                 // Pipe was closed... terminate
  114.             }
  115.         }
  116.  
  117.         public void Dispose()
  118.         {
  119.             Dispose(true);
  120.         }
  121.  
  122.         ~ConsoleRedirector()
  123.         {
  124.             Dispose(false);
  125.         }
  126.  
  127.         // ReSharper disable InconsistentNaming
  128.         // ReSharper disable UnusedParameter.Local
  129.         // ReSharper disable EmptyGeneralCatchClause
  130.         private void Dispose(bool disposing)
  131.         {
  132.             if(!_isDisposed)
  133.             {
  134.                 lock(_sync)
  135.                 {
  136.                     if(!_isDisposed)
  137.                     {
  138.                         _isDisposed = true;
  139.                         _timer.Change(Timeout.Infinite, Timeout.Infinite);
  140.                         _timer.Dispose();
  141.                         flush(null);
  142.  
  143.                         try { SetStdHandle(STD_OUTPUT_HANDLE, _stdout); } catch(Exception) {}
  144.                         _outClient.Dispose();
  145.                         _outServer.Dispose();
  146.  
  147.                         try { SetStdHandle(STD_ERROR_HANDLE, _stderr); } catch (Exception) {}
  148.                         _errClient.Dispose();
  149.                         _errServer.Dispose();
  150.                     }
  151.                 }
  152.             }
  153.         }
  154.         // ReSharper restore EmptyGeneralCatchClause
  155.         // ReSharper restore UnusedParameter.Local
  156.         // ReSharper restore InconsistentNaming
  157.  
  158.         // ReSharper disable InconsistentNaming
  159.         private const int STD_OUTPUT_HANDLE = -11;
  160.         private const int STD_ERROR_HANDLE = -12;
  161.  
  162.         [DllImport("kernel32.dll")]
  163.         [return:MarshalAs(UnmanagedType.Bool)]
  164.         private static extern bool SetStdHandle(int nStdHandle, IntPtr hHandle);
  165.        
  166.         [DllImport("kernel32.dll")]
  167.         private static extern IntPtr GetStdHandle(int nStdHandle);
  168.         // ReSharper restore InconsistentNaming
  169.     }
  170. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement