c#在读取async时等待shell命令返回
本文关键字:shell 命令 返回 等待 读取 async | 更新日期: 2023-09-27 18:18:26
我需要从c#应用程序运行一个外部进程,但在继续执行之前等待它返回。同时,我需要从stdout获取和更新一个文本框的进度信息。由于该命令可能运行几分钟并在此期间打印信息,因此显示这些信息是绝对必要的;但是可能会运行多个命令,并且必须按顺序运行,因此等待也是如此。
我试图使用:
p = Process.Start();
p.BeginOutputReadLine();
p.WaitForExit();
但是在等待时冻结UI线程并阻止输出出现。:
p.Start();
p.BeginOutputReadLine();
while (!p.HasExited)
{
Application.DoEvents();
Thread.Sleep(100);
}
效果更好,但完全是错误的/一个坏主意,并且实际上没有等待整个周期。
我也简要地尝试使用BackgroundWorker来启动shell进程,但我不确定如何使UI线程等待而不阻塞工人完成。
我想做的是提供一个类似于ShowDialog()
的DialogResult ShellExecute(String cmd)
,如果用户允许命令完成,单击取消或命令的返回代码,则返回OK/Cancel(/fail)结果。在命令完成(或被取消)之前,它不应该返回。
所有shell命令都使用:
ProcessStartInfo info = new ProcessStartInfo
{
UseShellExecute = false,
CreateNoWindow = true,
RedirectStandardOutput = true,
RedirectStandardError = true,
FileName = "cmd.exe",
Arguments = "/c " + command
};
重定向输出并有效地shell执行命令。
我如何正确地使一个函数启动一个异步进程,但仍然等待,直到它完成返回?
从ProcessStartInfo创建进程,
澄清:ProcessStartinfo si需要类似
的东西si.CreateNoWindow=true;
si.RedirectStandardOutput=true;
si.RedirectStandardError=true;
si.StandardOutputEncoding=Encoding.UTF8;
si.StandardErrorEncoding=Encoding.UTF8;
si.WindowStyle=ProcessWindowStyle.Hidden;
then before
p.Start();
使用p.OutoutDataReceived+=OutputHandler;
private static void OutputHandler(object theProcess, DataReceivedEventArgs evtdata)
{
//evtdata.Data has the output data
//use it, display it, or discard it
}
重新编写了大部分代码以使其正常工作。
ProgressForm
类提供了一个QueueCommand
方法,使用所需的shell命令和pre/post委托。当显示时,进度表单使用后台工作线程执行每个命令,处理返回代码,并在适当的情况下执行下一个命令。
后台工作器等待每个shell命令完成(Process.WaitForExit()
),同时异步地提供UI线程输出。完成后,它调用一个方法,启用成功/ok按钮并隐藏进度条。
void m_Worker_DoWork(object sender, DoWorkEventArgs e)
{
int exec = 1;
while (CommandQueue.Count > 0)
{
if (e.Cancel)
{
e.Result = 1;
return;
}
WriteLine("Running command {0}, {1} remaining.", exec++, CommandQueue.Count);
StagedCommand command = CommandQueue.Peek();
try
{
if (command.Pre != null) command.Pre();
int result = ShellExec(command.Command);
if (command.Post != null) command.Post();
CommandQueue.Dequeue();
if (result != 0)
{
e.Result = result;
return;
}
}
catch (Exception exc)
{
WriteLine("Error: {0}", exc.Message);
e.Result = 1;
return;
}
}
WriteLine("All commands executed successfully.");
e.Result = 0;
return;
}
int ShellExec(String command)
{
WriteLine(command);
Style = ProgressBarStyle.Marquee;
ProcessStartInfo info = new ProcessStartInfo
{
UseShellExecute = false,
LoadUserProfile = true,
ErrorDialog = false,
CreateNoWindow = true,
WindowStyle = ProcessWindowStyle.Hidden,
RedirectStandardOutput = true,
StandardOutputEncoding = Encoding.UTF8,
RedirectStandardError = true,
StandardErrorEncoding = Encoding.UTF8,
FileName = "cmd.exe",
Arguments = "/c " + command
};
Process shell = new Process();
shell.StartInfo = info;
shell.EnableRaisingEvents = true;
shell.ErrorDataReceived += new DataReceivedEventHandler(ShellErrorDataReceived);
shell.OutputDataReceived += new DataReceivedEventHandler(ShellOutputDataReceived);
shell.Start();
shell.BeginErrorReadLine();
shell.BeginOutputReadLine();
shell.WaitForExit();
return shell.ExitCode;
}