从dll中捕获C#中的stdout

时间:2012-09-07 16:07:23

标签: c# .net threadpool named-pipes

我正在尝试使用以下代码来捕获/重定向blind printf从dll到WPF文本框。

DLL:

#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.

C#代码:

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();


}
}

此代码不像现在这样工作。然而,这些是我的问题:

  1. 如果将模块级私有变量移动到mainwindow(),它将工作并显示文本框的所有内容。我可以在dll中调用多个方法并显示输出,只要它们在mainwindow()中。
  2. 即使它确实有效,一旦mainwindow()完成,当我点击调用dll的按钮时,它不再记录任何输出。我的期望是按钮应该调用dll,并且应该有数据写入stdout / pipe,并且线程仍应该拾取它(我在这里错了吗?)。我认为使变量模块级别有所帮助,但如果我这样做,我就没有结果。

0 个答案:

没有答案