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执行命令。

我如何正确地使一个函数启动一个异步进程,但仍然等待,直到它完成返回?

c#在读取async时等待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;
    }