C#在读取异步代码时等待shell命令返回 [英] C# wait for shell command to return while reading async

查看:103
本文介绍了C#在读取异步代码时等待shell命令返回的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要从C#应用程序运行一个外部进程,但要等它返回后再继续执行.同时,我需要从stdout获取并更新带有进度信息的文本框.由于该命令可能会运行几分钟并在此期间打印信息,因此显示该信息绝对必要;但是可能会运行多个命令且这些命令必须顺序执行,因此等待也是如此.

I need to run an external process from a C# app, but wait for it to return before continuing execution. At the same time, I need to get and update a text box with progress info from stdout. Since the command may run for a few minutes and print info during that time, displaying that is absolutely necessary; but multiple commands are likely to be run and must be in order, so waiting is as well.

我尝试使用:

p = Process.Start();
p.BeginOutputReadLine();
p.WaitForExit();

但是在等待时冻结了UI线程,并阻止了输出的出现.这个:

but that froze the UI thread while waiting and prevented the output from appearing. This:

p.Start();
p.BeginOutputReadLine();

while (!p.HasExited)
{
    Application.DoEvents();
    Thread.Sleep(100);
}

效果更好,但完全是错误的/不好的主意,实际上并没有等待整个周期.

works better, but is completely wrong/a bad idea and doesn't actually wait the full period.

我也曾短暂尝试过使用BackgroundWorker启动Shell进程,但是我不确定如何使UI线程等待而不会阻塞工人的完成.

I also briefly attempted using a BackgroundWorker to launch the shell process, but I'm not sure how to make the UI thread wait without blocking for the worker to finish.

我想做的是提供一个 DialogResult ShellExecute(String cmd),它与 ShowDialog()类似,如果返回OK/Cancel(/fail)结果,用户允许命令完成,单击取消"或命令的返回码.在命令完成(或取消)之前,它不应该返回.

What I want to do is provide a DialogResult ShellExecute(String cmd) similar to ShowDialog() that returns an OK/Cancel(/fail) result, if the user allowed the command to complete, clicked cancel, or the command's return code. It shouldn't return until the command has completed (or been canceled).

所有shell命令都使用以下命令运行:

All the shell commands are run with:

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

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

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

to redirect the output and effectively shell execute the command.

我该如何正确地创建一个启动异步过程但仍然等待该函数返回的函数?

How would I go about correctly making a function that launches an async process, but still waits until that is finished to return?

推荐答案

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

Reworked most of the code to get this to work correctly.

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

The ProgressForm class provides a QueueCommand method, taking the desired shell command and pre/post delegates. When shown, the progress form uses a background worker to execute each command, handle the return code and execute the next command if appropriate.

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

The background worker waits for each shell command to finish (Process.WaitForExit()) while asynchronously feeding the UI thread output. When finished, it calls a method enabling the successful/ok button and hiding the progress bar.

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

这篇关于C#在读取异步代码时等待shell命令返回的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆