我正在尝试使用以下代码将盲 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();
}
}
这段代码不能像现在这样工作。但是这些是我的问题:
- 如果模块级别的私有变量被移动到 mainwindow(),它将工作并显示文本框的所有内容。只要它们在 mainwindow() 中,我就可以在 dll 中调用多个方法并显示输出。
- 即使它确实有效,一旦 mainwindow() 完成,当我单击调用 dll 的按钮时,它不再记录任何输出。我的期望是按钮应该调用 dll,并且应该有数据写入标准输出/管道,并且线程仍然应该拾取它(我错了吗?)。我认为制作变量模块级别会有所帮助,但如果我这样做,我不会得到任何结果。