首页 文章

C#等待shell命令在读取异步时返回

提问于
浏览
2

我需要从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)结果,如果用户允许命令完成,单击取消,或者命令's return code. It shouldn' t返回,直到命令完成(或者取消) .

所有shell命令都运行于:

ProcessStartInfo info = new ProcessStartInfo
{
    UseShellExecute = false,
    CreateNoWindow = true,
    RedirectStandardOutput = true,
    RedirectStandardError = true,

    FileName = "cmd.exe",
    Arguments = "/c " + command
};

重定向输出并有效地执行命令 .

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

2 回答

  • 2

    从ProcessStartInfo创建您的流程,

    澄清:ProcessStartinfo si需要类似的东西

    si.CreateNoWindow=true;
    si.RedirectStandardOutput=true;
    si.RedirectStandardError=true;
    si.StandardOutputEncoding=Encoding.UTF8;
    si.StandardErrorEncoding=Encoding.UTF8;
    si.WindowStyle=ProcessWindowStyle.Hidden;
    

    然后呢

    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
    }
    
  • 1

    重写了大部分代码以使其正常工作 .

    ProgressForm 类提供 QueueCommand 方法,获取所需的shell命令和前/后委托 . 显示时,进度表单使用后台工作程序执行每个命令,处理返回代码并在适当时执行下一个命令 .

    后台工作程序等待每个shell命令完成( Process.WaitForExit() ),同时异步提供UI线程输出 . 完成后,它会调用一个启用成功/确定按钮并隐藏进度条的方法 .

    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;
        }
    

相关问题