我正在尝试从子控制台应用程序中捕获输出。
Console.ReadKey()
表示在重定向stdInput时无法读取密钥。
但是,我没有重定向输入(仅输出)。我在这里缺少什么?
子代码(将项目设置为控制台应用程序):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ChildProcess
{
internal class Program
{
private static void Main(string[] args)
{
char key = Console.ReadKey().KeyChar;
Console.Out.WriteLine("stdout");
Console.Error.WriteLine("stderr");
}
}
}
父应用代码:(将项目设置为Windows应用)
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RedirectProcessOutput
{
internal class Program
{
private static void Main(string[] args)
{
string fileName = @"ChildPRocess.exe";
string arg = "i";
string processOutput = "?";
Process p = new Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.CreateNoWindow = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardError = false;
p.StartInfo.FileName = fileName;
p.StartInfo.Arguments = arg;
p.Start();
processOutput = p.StandardOutput.ReadToEnd();
p.WaitForExit();
Console.WriteLine("The child process output is:" + processOutput);
}
}
}
我期待应用程序在没有崩溃的情况下运行,即使父级是一个窗口应用程序,因为孩子应该拥有自己的控制台,而我不会重定向输入。 顺便说一句 - 一切都有效:
答案 0 :(得分:1)
由于父进程是控制台应用程序时它可以正常工作,为什么不暂时将其转换成一个?
[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool AllocConsole();
[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool FreeConsole();
private static void Main(string[] args)
{
Process p = new Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.CreateNoWindow = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardError = false;
p.StartInfo.FileName = "Child.exe";
p.StartInfo.Arguments = "i";
AllocConsole();
p.Start();
FreeConsole();
string processOutput = p.StandardOutput.ReadToEnd();
p.WaitForExit();
Debug.WriteLine("The child process output is:" + processOutput);
}
如果您使用lock
/ AllocConsole
/ Start
周围的FreeConsole
,您甚至可以启动多个子进程,每个子进程都有自己的控制台窗口。
这是一个较旧的“解决方案”,无法正常运行。
看看CreateProcess flags。不设置CREATE_NO_WINDOW不会为您提供新的控制台对象;你需要CREATE_NEW_CONSOLE。 [不,这是错的;见下文]
不幸的是,这不会在.NET API中公开。如果您使用Process.Start
,ShellExecute
会做正确的事情,但是您无法重定向stdout。我认为System.Diagnostics.Process
无法完成你想做的事情,你必须P / Invoke CreateProcess
。
就在昨天,我编写了自己的System.Diagnostics.Process
替代方案,因为我需要MS实现未提供的另一个功能 - 将stdout和stderr重定向到同一个流。请随意重用my code,但请记住,它还没有得到太多测试。
我已经使用ProcessRunner
测试了您的示例,如果父进程是控制台应用程序,它会按预期工作 - 子进程拥有自己的新控制台窗口(不会将父进程重用为{{}它可以System.Diagnostics.Process
,并且stdout会被重定向到父级。
但是如果父进程是一个Windows应用程序,那么它会崩溃 - ReadKey()
失败;并且ReadKey()
输出也不可见。 (这与stderr
完全相同,我只是没有意识到System.Diagnostics.Process
也没有用。原因是你不能只重定向其中一个流 - 如设置stderr
后,所有流都会重定向。
现在我不确定如果父应用程序是控制台,它为什么会起作用。也许重定向的stdin / stderr句柄指的是当前控制台,而不是调用STARTF_USESTDHANDLES
时当前的控制台。
但是如果在Windows应用程序中调用GetStdHandle
,则返回INVALID_HANDLE。我不确定是否有办法获得一个创建控制台后有效的句柄。
答:不要这样做,只需提前创建控制台(参见开头的新解决方案)。