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

发布于 2024-12-29 21:36:24 字数 187 浏览 1 评论 0原文

我正在尝试将 dll 中方法的控制台输出 (cout) 显示到 C# 程序中的文本框。每次调用该方法时,控制台输出都会显示在 Visual Studio 的输出窗格中。有没有办法将输出窗格的内容重定向到文本框?

该 dll 是由其他人用 C++ 编写的,我无法控制更改它。 该 dll 使用 SWIG 进行包装,以便我的 C# 代码可以调用它。

I'm trying to display the console output (cout) of a method in a dll to a textbox in C# program. Every time I call the method, the console output will be displayed in the Output Pane of Visual Studio. Is there a way to redirect the content of the Output Pane to the textbox?

The dll was written by someone else in C++ and I have no control in changing it.
The dll is wrapped using SWIG so that it can be called by my C# code.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

相思碎 2025-01-05 21:36:24

在遵循大卫建议的链接后,我决定为您的问题编写一个更具体的解决方案。此版本允许您通过 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 示例表单

After following the link suggested by David, I decided to write a solution to your problem which is more specific to your case. This version allows you to receive the stdout in your GUI via a BackgroundWorker PropertyChangedEventHandler call back.

Here's the code for the 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);
}

Here's a link to a complete sample form which demonstrates how to use it: ConsoleRedirector Example Form

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文