2012-01-30 95 views
4

我試圖顯示在C#程序中的文本框中的DLL中的方法的控制檯輸出(cout)。每次我調用該方法時,控制檯輸出都將顯示在Visual Studio的輸出窗格中。有沒有辦法將輸出窗格的內容重定向到文本框?重定向cout從c + + dll到C#中的文本框#

該DLL是由其他人在C++寫的,我無法控制它的改變。 該DLL使用SWIG打包,以便可以通過我的C#代碼進行調用。

+1

有一個看看這個:http://pastebin.com/f3eda7c8 – 2012-01-30 09:26:26

回答

5

在遵循David建議的鏈接之後,我決定爲您的問題寫一個更具體的解決方案。該版本允許您通過BackgroundWorkerPropertyChangedEventHandler回撥在GUI中接收標準輸出。

下面是該ConsoleRedirector代碼:

public class ConsoleRedirector : IDisposable 
{ 
    private static ConsoleRedirector _instance; 

    public static void attach(ProgressChangedEventHandler handler, bool forceConsoleRedirection) 
    { 
     Debug.Assert(null == _instance); 
     _instance = new ConsoleRedirector(handler, forceConsoleRedirection); 

    } 

    public static void detatch() 
    { 
     _instance.Dispose(); 
     _instance = null; 
    } 

    public static bool isAttached 
    { 
     get 
     { 
      return null != _instance; 
     } 
    } 

    private static void ResetConsoleOutStream() 
    { 
     //Force console to recreate its output stream the next time Write/WriteLine is called 
     typeof(Console).GetField("_out", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic).SetValue(null, null); 
    } 

    private const int PERIOD = 500; 
    private const int BUFFER_SIZE = 4096; 
    private volatile bool _isDisposed; 
    private BackgroundWorker _worker; 
    private readonly IntPtr _stdout; 
    private readonly Mutex _sync; 
    private readonly System.Threading.Timer _timer; 
    private readonly char[] _buffer; 
    private readonly AnonymousPipeServerStream _outServer; 
    private readonly TextReader _outClient; 
    private readonly bool _forceConsoleRedirection; 

    private StreamWriter _consoleStandardOut; 

    private ConsoleRedirector(ProgressChangedEventHandler handler, bool forceConsoleRedirection) 
    { 
     bool ret; 
     _forceConsoleRedirection = forceConsoleRedirection; 

     if (!_forceConsoleRedirection) 
     { 
      //Make sure Console._out is initialized before we redirect stdout, so the redirection won't affect it 
      TextWriter temp = Console.Out; 
     } 

     AnonymousPipeClientStream client; 

     _worker = new BackgroundWorker(); 
     _worker.ProgressChanged += handler; 
     _worker.DoWork += _worker_DoWork; 
     _worker.WorkerReportsProgress = true; 

     _stdout = GetStdHandle(STD_OUTPUT_HANDLE); 

     _sync = new Mutex(); 
     _buffer = new char[BUFFER_SIZE]; 

     _outServer = new AnonymousPipeServerStream(PipeDirection.Out); 
     client = new AnonymousPipeClientStream(PipeDirection.In, _outServer.ClientSafePipeHandle); 
     Debug.Assert(_outServer.IsConnected); 
     _outClient = new StreamReader(client, Encoding.Default); 
     ret = SetStdHandle(STD_OUTPUT_HANDLE, _outServer.SafePipeHandle.DangerousGetHandle()); 
     Debug.Assert(ret); 

     if (_forceConsoleRedirection) 
     { 
      ResetConsoleOutStream(); //calls to Console.Write/WriteLine will now get made against the redirected stream 
     } 

     _worker.RunWorkerAsync(_outClient); 

     _timer = new System.Threading.Timer(flush, null, PERIOD, PERIOD); 

    } 

    void _worker_DoWork(object sender, DoWorkEventArgs e) 
    { 
     BackgroundWorker worker = (BackgroundWorker)sender; 
     TextReader client = (TextReader)e.Argument; 
     try 
     { 
      while (true) 
      { 
       int read = client.Read(_buffer, 0, BUFFER_SIZE); 
       if (read > 0) 
        worker.ReportProgress(0, new string(_buffer, 0, read)); 
      } 
     } 
     catch (ObjectDisposedException) 
     { 
      // Pipe was closed... terminate 

     } 
     catch (Exception ex) 
     { 

     } 
    } 

    private void flush(object state) 
    { 
     _outServer.Flush(); 
    } 

    public void Dispose() 
    { 
     Dispose(true); 
    } 

    ~ConsoleRedirector() 
    { 
     Dispose(false); 
    } 

    private void Dispose(bool disposing) 
    { 
     if (!_isDisposed) 
     { 
      lock (_sync) 
      { 
       if (!_isDisposed) 
       { 
        _isDisposed = true; 
        _timer.Change(Timeout.Infinite, Timeout.Infinite); 
        _timer.Dispose(); 
        flush(null); 

        try { SetStdHandle(STD_OUTPUT_HANDLE, _stdout);} 
        catch (Exception) { } 
        _outClient.Dispose(); 
        _outServer.Dispose(); 

        if (_forceConsoleRedirection) 
        { 
         ResetConsoleOutStream(); //Calls to Console.Write/WriteLine will now get redirected to the original stdout stream 
        } 

       } 
      } 
     } 
    } 

    private const int STD_OUTPUT_HANDLE = -11; 

    [DllImport("kernel32.dll")] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    private static extern bool SetStdHandle(int nStdHandle, IntPtr hHandle); 

    [DllImport("kernel32.dll")] 
    private static extern IntPtr GetStdHandle(int nStdHandle); 
} 

下面是一個完整的示例形式的鏈接,演示瞭如何使用它:ConsoleRedirector Example Form

+0

它的工作原理!非常感謝!! – 2012-01-31 05:40:33

+0

+1優秀作品! – 2012-01-31 07:43:19

+0

我一直在我的應用中使用這個輝煌的代碼,在Windows 7中工作得很好!當我升級到Windows 10時,這不再起作用。你有什麼想法,Windows 10可能破壞了上面的代碼? – bradcarman 2017-05-22 15:54:26