C#控制台应用程序stdin/stdout重定向 [英] C# console application stdin/stdout redirection

查看:526
本文介绍了C#控制台应用程序stdin/stdout重定向的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个有趣的(令人沮丧的)问题,它从C#WPF应用程序启动控制台应用程序并重定向其stdin和stdout.

I have an interesting (read: frustrating) problem kicking off a console application from a C# WPF app and redirecting its stdin and stdout.

它大部分可以正常工作,但是我似乎一开始重定向stdin就无法从stdout获取一些数据.

It is mostly up and working but I seem to end up not getting some data from stdout as soon as I start redirecting stdin.

我将举例说明.如果未在STARTUPINFO结构中设置hStdInput,则在启动子进程时会收到以下消息:

I'll clarify with an example. If I don't set hStdInput in the STARTUPINFO structure, when I start the child process I receive the following:

MongoDB shell version: 2.2.0
connecting to: test
local:PRIMARY>

但是,一旦我设置了hStdInput,我就会得到:

Once I set hStdInput however, I just get this:

MongoDB shell version: 2.2.0
connecting to: test

我知道BackgroundWorker处理stdout仍在起作用,因为如果我向stdin上的进程发送内容,它会做出相应的响应.

I know that the BackgroundWorker processing stdout is still functioning because if I send something to the process on stdin, it responds accordingly.

use TestDB
switched to db TestDB

因此,这就是我创建流程的方式:

So, this is how I create the process:

_processInfo = new ProcessInfo();

bool ok = false;

SECURITY_ATTRIBUTES sattr = new SECURITY_ATTRIBUTES();
sattr.bInheritHandle = 1;
unsafe
{
    sattr.lpSecurityDescriptor = null;
}
sattr.nLength = Marshal.SizeOf(sattr);

IntPtr hWrite;
ok = CreatePipe(out _hReadStdOut, out hWrite, ref sattr, 0);
ok = SetHandleInformation(_hReadStdOut, HANDLE_FLAGS.INHERIT, 0);
IntPtr hRead;
ok = CreatePipe(out hRead, out _hWriteStdIn, ref sattr, 0);
ok = SetHandleInformation(_hWriteStdIn, HANDLE_FLAGS.INHERIT, 0);

var startInfo = new StartupInfo
{
    dwFlags = 0x0001 | 0x0100,
    wShowWindow = 0,
    hStdOutput = hWrite,
    hStdError = hWrite,
    hStdInput = hRead // If this is IntPtr.Zero, I get everything from stdout
};

SECURITY_ATTRIBUTES pSec = new SECURITY_ATTRIBUTES();
pSec.nLength = Marshal.SizeOf(pSec);
SECURITY_ATTRIBUTES tSec = new SECURITY_ATTRIBUTES();
tSec.nLength = Marshal.SizeOf(tSec);

unsafe
{
    ok = CreateProcess(
        null,
        pathToExeAndArgs,
        ref pSec,
        ref tSec,
        true,
        0,
        IntPtr.Zero,
        null,
        ref startInfo,
        out _processInfo);
}

我在DoWork上有一个BackgroundWorker处理stdout,它像这样读取管道:

I have a BackgroundWorker processing stdout on DoWork which reads the pipe like so:

success = ReadFile(
    _hReadStdOut,
    bufPtr,
    1024,
    &read,
    IntPtr.Zero);

我没有使用.Net Process类,因为它直到控制台应用程序发送换行符时才从stdout获取数据,因此在这种情况下我也没有得到提示.

I'm not using the .Net Process class because it didn't obtain data from stdout until the console application sent a newline, so I didn't get the prompt back in that case either.

任何对此表示感谢的帮助.

Any help with this greatly appreciated.

干杯.

推荐答案

我怀疑以下内容可以解释您所观察到的内容:

I suspect the following explains what you have observed:

  • 当您未定义hStdInput时,子进程将使用连接到控制台的标准输入设备.子进程检测到标准输入是交互式控制台设备,并编写提示.
  • 当您定义hStdInput时,子进程会检测到标准输入是管道,因此忽略编写提示.毕竟,提示非交互式输入设备有什么意义?
  • When you don't define hStdInput the child process uses the standard input device attached to the console. The child process detects that standard input is an interactive console device and writes a prompt.
  • When you do define hStdInput the child process detects that the standard input is a pipe and so neglects to write a prompt. After all, what's the point of prompting a non-interactive input device?

子进程将使用GetFileType(GetStdHandle(STD_INPUT_HANDLE))来检测标准输入连接了哪种类型的设备.值FILE_TYPE_CHAR表示控制台.当您将管道附加到标准输入时,标准输入文件类型将为FILE_TYPE_PIPE.

The child process will use GetFileType(GetStdHandle(STD_INPUT_HANDLE)) to detect what type of device is attached to the standard input. A value of FILE_TYPE_CHAR indicates a console. When you attach a pipe to the standard input then the standard input file type will be FILE_TYPE_PIPE.

我的结论是,一切都按设计和预期进行.

My conclusion is that everything is working as designed and intended.

这篇关于C#控制台应用程序stdin/stdout重定向的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆