【问题标题】:Receiving user input after reading piped input读取管道输入后接收用户输入
【发布时间】:2014-03-13 20:11:20
【问题描述】:

我正在 .NET 4 中编写一个小型的交互式控制台应用程序。我想扩展它以能够处理可选的重定向输入,例如:

echo hello | myapp.exe

问题当然是重定向的输入窃取了“键盘流”,因此任何对 Console.Read*() 的调用都返回 null。

我现在拥有的是:

// Read piped input
try
{
    bool keyAvailable = Console.KeyAvailable;
}
catch
{
    string redirected = Console.In.ReadToEnd();
    // Need to do something here to "un-redirect" stdin back to keyboard
}

// Always returns null
String userInput = Console.ReadLine();

在 UNIX 上,我可以打开到 /dev/tty 的流以获取用户输入,但是如何在 Windows 上实现这一点?

谢谢!

[编辑]

基于 Craig 的回答的工作解决方案:

[System.Runtime.InteropServices.DllImport("kernel32.dll")]
static extern bool AttachConsole(int dwProcessId);
[System.Runtime.InteropServices.DllImport("kernel32.dll")]
static extern bool FreeConsole();

try
{
     bool keyAvailable = Console.KeyAvailable;
}
catch
{
    string redirectedInput = Console.In.ReadToEnd();
    bool freed = FreeConsole();
    bool attached = AttachConsole(-1);
    Console.SetIn(new StreamReader(Console.OpenStandardInput()));
}

我必须首先使用完全脱离控制台

FreeConsole().

我可以选择使用

创建一个全新的控制台
AllocConsole()

但这会创建另一个控制台窗口,我并不真正想要。相反,我使用

附加到父控制台(现有的 cmd.exe)
AttachConsole(-1) // -1 = "Parent".

我只能推测 .NET 类 Console 持有对先前标准输入流的引用,但只有在调用 Console.SetIn() 之后,Console.ReadLine() 才回到它的阻塞行为,等待用户输入。

现在开始研究如果我在应用程序的标准输出重定向的情况下运行会发生什么:

echo hello | myapp.exe | somewhere ...

【问题讨论】:

    标签: c# .net io console-application stdin


    【解决方案1】:

    AttachConsole 函数应该可以完成这项工作,尽管我只是用它来重新获得输出而不是输入。

    【讨论】:

    • 结合使用 P/Invoke ofFreeConsole()/AttachConsole() 和 Console.SetIn() 确实有效,谢谢!! (我会更新原帖以显示完整代码)