从dll捕获C#中的标准输出

从dll捕获C#中的标准输出,c#,.net,threadpool,named-pipes,C#,.net,Threadpool,Named Pipes,我正在尝试使用以下代码捕获/重定向blindprintf,将其从dll发送到WPF文本框 动态链接库: 此代码的工作方式与现在不同。然而,这些是我的问题: 如果模块级私有变量移动到mainwindow(),它将工作并在文本框中显示所有内容。我可以在dll中调用多个方法并显示输出,只要它们在mainwindow()中 即使它可以工作,一旦mainwindow()完成,当我单击调用dll的按钮时,它也不再记录任何输出。我的期望是按钮应该调用dll,并且应该有数据写入到stdout/pipe,线程仍然

我正在尝试使用以下代码捕获/重定向blindprintf,将其从dll发送到WPF文本框

动态链接库:

此代码的工作方式与现在不同。然而,这些是我的问题:

  • 如果模块级私有变量移动到mainwindow(),它将工作并在文本框中显示所有内容。我可以在dll中调用多个方法并显示输出,只要它们在mainwindow()中
  • 即使它可以工作,一旦mainwindow()完成,当我单击调用dll的按钮时,它也不再记录任何输出。我的期望是按钮应该调用dll,并且应该有数据写入到stdout/pipe,线程仍然应该拾取它(我在这里错了吗?)。我原以为在变量模块级别创建变量会有所帮助,但如果这样做,我就没有结果了
  • #include <stdlib.h>
    #include <string.h>
    #include "stdafx.h"
    #define EXTERN_DLL_EXPORT __declspec(dllexport)
    
    
    extern "C" EXTERN_DLL_EXPORT int startPipe()
    {
        setvbuf(stdout, NULL, _IONBF, 0);
        printf("hey");
        return 20;
    }
    
    //Morepipe2, etc just return different test words.
    
    using System;
    using System.Diagnostics;
    using System.IO;
    using System.IO.Pipes;
    using System.Runtime.InteropServices;
    using System.Threading;
    using System.Windows;
    
    namespace PipeTest {
    
    
    public partial class MainWindow : Window {
        private NamedPipeServerStream serverPipe;
        private NamedPipeClientStream clientPipe;
        private int id;
        private StreamReader stm;
        private HandleRef hr11;
        private String txt;
    
        private delegate void updateCallback(string pipetext);
    
        [DllImport("kernel32.dll", SetLastError = true)]
        protected static extern bool SetStdHandle(int nStdHandle, IntPtr hConsoleOutput);
    
        public MainWindow() {
            InitializeComponent();
    
            id = Process.GetCurrentProcess().Id; // make this instance unique
            serverPipe = new NamedPipeServerStream("consoleRedirect" + id, PipeDirection.In, 1);
            clientPipe = new NamedPipeClientStream(".", "consoleRedirect" + id, PipeDirection.Out, PipeOptions.WriteThrough);
            ThreadPool.QueueUserWorkItem(state => {
                serverPipe.WaitForConnection();
                using (stm = new StreamReader(serverPipe)) {
                    while (serverPipe.IsConnected) {
                        try {
                            txt = stm.ReadLine();
                            if (!string.IsNullOrEmpty(txt))
    
                                UpdateElement(txt + "\n");
                        } catch (IOException) {
                            break; // normal disconnect
                        }
                    }
                }
            }, null);
            clientPipe.Connect();
            hr11 = new HandleRef(clientPipe,
             clientPipe.SafePipeHandle.DangerousGetHandle());
            SetStdHandle(-11, hr11.Handle); // redirect stdout to my pipe
    
            PipeServer.morePipe1();
            PipeServer.morePipe2();
    
            PipeServer.startPipe();
            PipeServer.morePipe1();
            PipeServer.morePipe2();
            Thread.Sleep(10000);
            PipeServer.startPipe();
            PipeServer.startPipe();
        }
    
        private void ender() {
            //clientPipe.Dispose();
            //serverPipe.Dispose();
        }
    
        private void button1_Click(object sender, RoutedEventArgs e) {
            PipeServer.startPipe();
        }
    
        private void button2_Click(object sender, RoutedEventArgs e) {
            PipeServer.morePipe1();
        }
    
        private void button3_Click(object sender, RoutedEventArgs e) {
            PipeServer.morePipe2();
        }
    
        private void UpdateElement(string pipetext) {
            if (textBox1.Dispatcher.CheckAccess() == false) {
                updateCallback uCallBack = new updateCallback(UpdateElement);
                this.Dispatcher.Invoke(uCallBack, pipetext);
            } else {
                textBox1.Text += pipetext;
            }
        }
    }
    
    public static class PipeServer {
    
         private const CallingConvention conv = CallingConvention.StdCall;
    
        [DllImport(@"PipeServer2.dll", CallingConvention = conv)]
        public static extern int startPipe();
    
        [DllImport(@"PipeServer2.dll", CallingConvention = conv)]
        public static extern int morePipe1();
    
    
    }
    }