我试图从任何基于DOS的应用程序中获取结果,实际上让C#像操作用户一样操作它。
我可以让它执行命令,然后显示输出。问题是知道输出何时结束!例如,如果我开始/运行“cmd.exe”,键入“D:”,然后“cd D:\”,然后“树”,它在D驱动器上输出我的文件夹结构,然后允许我输入我的下一个命令(仅 后,它已完成打印列表)。
但是我无法在代码中找到方法让它意识到它已经完成,并且应该允许下一个命令(基本上当cmd.exe开始闪烁光标时)。
public Process p = null;
private void Form1_Load(object sender, System.EventArgs e)
{
ProcessStartInfo procStarter = new ProcessStartInfo("cmd.exe");
procStarter.RedirectStandardOutput = true;
procStarter.RedirectStandardInput = true;
procStarter.UseShellExecute = false;
procStarter.CreateNoWindow = true;
p = Process.Start(procStarter);
}
private void Form1_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
p.Close();
}
private void btnSend_Click(object sender, System.EventArgs e)
{
p.StandardInput.WriteLine("D:");
p.StandardInput.WriteLine(@"cd D:\");
txtOutput.Text = SendCommand(txtInput.Text);
}
private string SendCommand(string cmd)
{
p.StandardInput.WriteLine(cmd);
return p.StandardOutput.ReadToEnd();
}
在SendCommand(string cmd)中,如果我按照上面的代码运行p.StandardOutput.ReadToEnd(),它会永远挂起,大概等待应用程序关闭?
如果我遍历p.StandardOutput.ReadLine(),它会显示所有文本(包括闪烁光标之前的“D:\>”,但它没有意识到它结束了,再次调用ReadLine,并以熟悉的方式挂起到ReadToEnd。如果当前行以“>”结尾,则一个肮脏的解决方法是将其视为响应的结束,但是如果一行在任何地方结束,那么它就会分崩离析回应。
我尝试逐个字符循环,并且最后没有发送特殊字符。
有什么想法吗?
注意:我的最终目标是提供一个轻型库,我可以用它来执行任何DOS可执行文件(可能需要传递给它的几个类型命令,而不仅仅是打开时通过命令行传递的一个关闭参数),解析结果使用正则表达式模板返回,并返回提取的结果。我想如果我能在windows应用程序中有效地重新实现cmd.exe,那么就可以使用这样的库。
谢谢, 利
答案 0 :(得分:2)
我怀疑你的方法不起作用。当您运行的命令或是否已完成时,cmd.exe
不会通过StandardOutput与您通信。 (我应该指出,这并不能阻止你运行多个命令。你可能只是发送命令行而不是需要等待它完成。)
也许更合适的方法可能根本不使用cmd.exe
。而是使用Process.Start()
来运行每个单独的命令。然后你可以使用StandardOutput.ReadToEnd()
,它将在完成过程后结束,你可以运行下一个过程。
答案 1 :(得分:1)
我同意Timwi,但看看下面的内容是否有帮助
ProcessStartInfo procStarter = new ProcessStartInfo("cmd.exe");
procStarter.RedirectStandardOutput = true;
procStarter.RedirectStandardInput = true;
procStarter.UseShellExecute = false;
procStarter.CreateNoWindow = true;
procStarter.WorkingDirectory = @"D:\";
procStarter.Arguments = "/C dir";
Process p = Process.Start(procStarter);
string output = p.StandardOutput.ReadToEnd();
一旦完成工作,/ cm命令行到cmd.exe将终止cmd.exe。您还可以使用p.Exited(退出事件)来了解它何时发生。
但是它不会保持cmd.exe始终运行。但你真的需要让它继续运行吗?
答案 2 :(得分:0)
如果您正在寻找'如何等待产生的进程终止',那么Process.WaitForExit应该是什么诀窍。 您可以为每个“命令”生成一个新的shell。
答案 3 :(得分:0)
大约一年前,我为Windows编写了一个telnet服务器,允许远程用户针对cmd.exe
发出命令。也许您可以将它作为自己项目的起点。
答案 4 :(得分:0)
通过读取输出异步,我已经使这个工作(几乎像你描述的那样):
public Process p = null;
private void Send_Click(object sender, System.EventArgs e)
{
p.StandardInput.WriteLine("D:");
p.StandardInput.WriteLine(@"cd D:\");
p.StandardInput.WriteLine(txtInput.Text);
}
private void Form1_Load_1(object sender, EventArgs e)
{
ProcessStartInfo procStarter = new ProcessStartInfo("cmd.exe");
procStarter.RedirectStandardOutput = true;
procStarter.RedirectStandardInput = true;
procStarter.UseShellExecute = false;
procStarter.CreateNoWindow = true;
p = Process.Start(procStarter);
p.OutputDataReceived += new DataReceivedEventHandler(p_OutputDataReceived);
p.BeginOutputReadLine();
}
void p_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
addTextToOutput(e.Data);
}
private void addTextToOutput(string text)
{
if (txtOutput.InvokeRequired)
{
addTextCallback cb = new addTextCallback(addTextToOutput);
this.Invoke(cb, new Object[] { text });
}
else
{
txtOutput.Text += text+ System.Environment.NewLine;
}
}
delegate void addTextCallback(String text);
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
p.Close();
}