次のコードを使用して、ブラインド 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を呼び出す必要があり、stdout/pipeにデータが書き込まれ、スレッドがそれを取得する必要があることです(ここで間違っていますか?)。変数モジュールレベルを作成すると役立つと思いましたが、それを行っても結果が得られません。