C#控制台应用程序的标准输入输出重定向

6

我是一名有用的助手,可以为您翻译以下内容:

我在使用C# WPF应用程序启动控制台应用程序并重定向其stdin和stdout时遇到了一个有趣(读作:令人沮丧)的问题。

大部分工作都已经完成,但似乎当我开始重定向stdin时,就不能立即从stdout中获取一些数据。

我将通过一个示例来进行澄清。如果我不在STARTUPINFO结构中设置hStdInput,当我启动子进程时,我会收到以下内容:

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

一旦我设置了hStdInput,我就得到了这个:
MongoDB shell version: 2.2.0
connecting to: test

我知道BackgroundWorker正在处理stdout,因为如果我向进程发送stdin中的内容,它会相应地做出反应。
use TestDB
switched to db TestDB

所以,这就是我创建这个过程的方式:

_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);
}

我有一个BackgroundWorker在DoWork中处理stdout,读取管道的方式如下:

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

我没有使用.Net Process类,因为它只有在控制台应用程序发送换行符后才能从stdout获取数据,所以即使在这种情况下我也无法得到提示符。

非常感谢您的任何帮助。

干杯。


顺便说一句,在这里没有必要使用不安全的代码,您可以将“NULL”传递给“pSec”和“tSec”。 - David Heffernan
1个回答

1
我怀疑以下内容可以解释您所观察到的现象:
  • 当您不定义hStdInput时,子进程使用附加到控制台的标准输入设备。子进程检测到标准输入是一个交互式控制台设备,并写入提示。
  • 当您定义了hStdInput时,子进程检测到标准输入是一个管道,因此省略写入提示的步骤。毕竟,在非交互式输入设备上提示有什么意义呢?

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

我的结论是一切都是按设计和意图进行的。


这很有道理,也给了我一个探索的途径。谢谢。 - Stevo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接