【问题标题】:C# console application stdin/stdout redirectionC# 控制台应用程序标准输入/标准输出重定向
【发布时间】:2012-12-08 14:11:41
【问题描述】:

我在从 C# WPF 应用程序启动控制台应用程序并重定向其标准输入和标准输出时遇到了一个有趣(阅读:令人沮丧)的问题。

它大部分都在工作,但一旦我开始重定向标准输入,我似乎最终没有从标准输出获得一些数据。

我会用一个例子来说明。如果我没有在 STARTUPINFO 结构中设置 hStdInput,当我启动子进程时,我会收到以下信息:

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

然而,一旦我设置了 hStdInput,我就会得到这个:

MongoDB shell version: 2.2.0
connecting to: test

我知道处理标准输出的 BackgroundWorker 仍在运行,因为如果我在标准输入上向进程发送内容,它会做出相应的响应。

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

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

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

我没有使用 .Net Process 类,因为它在控制台应用程序发送换行符之前没有从 stdout 获取数据,所以在那种情况下我也没有得到提示。

非常感谢任何帮助。

干杯。

【问题讨论】:

  • 顺便说一句,这里不需要不安全的代码,您可以将NULL 传递给pSectSec

标签: c# console pinvoke stdout


【解决方案1】:

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

  • 当您没有定义hStdInput 时,子进程使用附加到控制台的标准输入设备。子进程检测到标准输入是交互式控制台设备并编写提示。
  • 当您定义hStdInput 时,子进程检测到标准输入是管道,因此忽略编写提示。毕竟,提示非交互式输入设备有什么意义?

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

我的结论是,一切都按设计和预期工作。

【讨论】:

  • 这是有道理的,并为我提供了探索的途径。谢谢。
猜你喜欢
  • 2014-03-17
  • 1970-01-01
  • 1970-01-01
  • 2010-09-21
  • 1970-01-01
  • 2019-03-15
  • 1970-01-01
  • 2014-12-08
  • 2010-11-06
相关资源
最近更新 更多