【发布时间】:2015-12-24 09:14:58
【问题描述】:
我正在尝试使用 C# 和 Visual Studio 2013 Update 4 在我的 Windows 8.1 机器上为 EXE 编写我自己的交互式 shell。代码运行时没有任何错误,但我在任何一个中的读取调用中都看不到任何返回从 stdout 读取的循环或读取 stderr 的循环。读取调用永远不会返回。我的方法有什么问题?
我看到了这个相关的 SO 帖子,但我根本没有收到任何异常:
C# Read stdout of child process asynchronously
public partial class frmMain : Form
{
private const string DIR_CHILDPROCESS = @"C:\Users\Robert\Documents\Visual Studio 2012\ChildProcess-5.3.1 - IDAvatars\";
private const string EXE_NAME = @"childprocess.exe";
Process _childProcess = null;
public frmMain()
{
InitializeComponent();
}
private async Task ReadOutputFromChildProcess()
{
char[] aryC = new char[1];
while (true)
{
// Get output from ChildProcess.
int count = await this._childProcess.StandardOutput.ReadAsync(aryC, 0, 1);
Debug.Write(aryC[0]);
// await Task.Delay(50);
}
}
private async Task ReadFromErrorsChildProcess()
{
char[] aryC = new char[1];
while (true)
{
// Get output from ChildProcess.
int count = await this._childProcess.StandardError.ReadAsync(aryC, 0, 1);
Debug.Write(aryC[0]);
// await Task.Delay(50);
}
}
private void frmShell_Load(object sender, EventArgs e)
{
string target = Path.Combine(DIR_CHILDPROCESS, EXE_NAME);
this._childProcess = new Process();
this._childProcess.StartInfo.UseShellExecute = false;
this._childProcess.StartInfo.RedirectStandardOutput = true;
this._childProcess.StartInfo.RedirectStandardError = true;
this._childProcess.StartInfo.RedirectStandardInput = true;
this._childProcess.StartInfo.CreateNoWindow = true;
this._childProcess.EnableRaisingEvents = true;
this._childProcess.StartInfo.FileName = target;
this._childProcess.Exited += this._childProcess_Exited;
// this._childProcess.StartInfo.Arguments = arguments;
// this._childProcess.StartInfo.
this._childProcess.StartInfo.WorkingDirectory = DIR_CHILDPROCESS;
//this._childProcess.StartInfo.FileName = Path.Combine(DIR_CHILDPROCESS, EXE_NAME);
//this._childProcess.StartInfo.UseShellExecute = false;
//this._childProcess.StartInfo.RedirectStandardOutput = true;
//this._childProcess.StartInfo.RedirectStandardError = true;
//this._childProcess.StartInfo.RedirectStandardInput = true;
//this._childProcess.StartInfo.CreateNoWindow = true;
if (!this._childProcess.Start())
MessageBox.Show("ChildProcess failed to start.", "Error");
// Start the loop that reads output from ChildProcess.
this.ReadOutputFromChildProcess();
// Start the loop that reads error messages from ChildProcess.
this.ReadFromErrorsChildProcess();
Debug.WriteLine("ChildProcess launched successfully.");
// this._childProcess.WaitForExit();
}
void _childProcess_Exited(object sender, EventArgs e)
{
Debug.WriteLine("Child process exited with exit code: " + this._childProcess.ExitCode.ToString());
}
private void frmMain_FormClosing(object sender, FormClosingEventArgs e)
{
this._childProcess.Kill();
}
}
【问题讨论】:
-
子进程是否退出?如果没有,您可能需要关闭其输入句柄。它实际上是在产生输出吗?如果是,它实际上是在写入它的输出流还是直接将它发送到它的控制台?即,尝试在 cmd 中使用重定向输出执行应用程序;这行得通吗?
-
@StephenCleary - 只要主机 shell 应用程序处于活动状态,我想保持子进程处于活动状态,因此它不会退出(我通过确保子进程显示在任务管理器)。它肯定会产生输出。我尝试从 CMD 启动重定向输出,但捕获文件中没有出现任何内容。所以我认为这意味着它直接写入控制台而不是 StdOut?如果是这样,在这种情况下如何捕获输出?我认为这一定是可能的,因为 CMD 和其他 shell 这样做。
-
从技术上讲,保持子应用程序“活着”是不可能的;它会随时退出;您能做的最好的事情就是保留对它的引用(作为僵尸进程)。听起来您的子应用程序正在直接写入控制台,which is bad for you。可用的最佳解决方案(都不好):p/Invoke some nasty APIs 或 hook the child process' calls。
-
@StephenCleary 谢谢。保持子应用程序活着没有问题。在您输入“退出”之前它不会退出。第二点,子应用程序是使用 printf() 的 C++ 应用程序。尚未确认,但看起来 printf() 确实在 Linux 上打印到标准输出,但不是 Win32。也许是 C++ CRT lib 的东西?在上面找到这篇文章:gamedev.net/topic/…
-
@StephenCleary - 使用 Visual Studio 构建的使用 printf 的应用似乎不输出到标准输出:discuss.cocos2d-x.org/t/printf-stdout-do-not-work-on-win32/315/…
标签: c# asynchronous process stdout stdin