簡體   English   中英

將cout從C ++ dll重定向到C#中的文本框

[英]Redirect cout from C++ dll to a textbox in C#

我正在嘗試將一個方法的控制台輸出(cout)顯示在C#程序的文本框中。 每次調用該方法時,控制台輸出都將顯示在Visual Studio的輸出窗格中。 有沒有辦法將輸出窗格的內容重定向到文本框?

dll是由C ++中的其他人編寫的,我無法控制它。 使用SWIG包裝dll,以便可以通過我的C#代碼調用它。

在按照David建議的鏈接后,我決定為您的問題編寫一個更具針對性的解決方案。 此版本允許您通過BackgroundWorker PropertyChangedEventHandler回調接收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示例表單

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM