C#窗口异步调用DOS程序并返回结果
郝伟 2022/08/17

1 简介

本文章包括两在核心内容:

2 DOS程序调用

经测试,以下代码效果非常好,可以达到以下效果:

  1. 运行指定的DOS程序;
  2. 运行一定时间后会返回,防止失去响应;
  3. 结果返回为字符串。

代码如下:

/// <summary>
/// 用于执行第三方程序,并返回执行结果。
/// </summary>
/// <param name="exefile_path">可执行的程序的路径。</param>
/// <param name="arglist">可执行程序的参数列表,默认为 ""。</param>
/// <param name="timeout">超时时间,单位秒,默认为10秒。</param>
/// <returns></returns>
public static string RunCommand(string exefile_path, string arglist = "", double timeout = 10)
{
    // 1. 保证可执行程序存在,否则报错。
    var fullpath = Path.GetFullPath(exefile_path);
    if (!File.Exists(fullpath))
    {
        return "Error: 转换器模块不存在。";
    }

    // 2. 使用Process类初始化一个进程用于处理DOS程序
    Process p = new Process();
    p.StartInfo.FileName = Path.GetFullPath(exefile_path);   // 获得全路径
    p.StartInfo.Arguments = arglist;                         // 参数列表已经格式化,如: "a b.txt" c 10
    p.StartInfo.UseShellExecute = false;                     // 不显示用户界面
    p.StartInfo.RedirectStandardOutput = true;               // 是否重定位输出于当前输出。
    p.StartInfo.CreateNoWindow = true;                       // 不创建新窗口。

    // 3. 任务执行  为防止出错,使用了 try-catch-finally 逻辑进行容错
    string retInfo = "";
    try
    {
        // 3.1 开始任务,此时是异步执行,所以不会卡住
        if (p.Start())
        {
            // 3.2 强制同步等待指定时间,不限时也可以,但有有隐患所以还是加上了
            p.WaitForExit((int)(timeout * 1000));

            // 3.3 到时间如果还没有结束,就将任务线程关闭
            if (!p.HasExited)
                p.Kill();

            // 3.4 无计是否执行完成都可以从控制台读取出输出的信息
            retInfo = p.StandardOutput.ReadToEnd();
        }
    }
    // 4. 如果出现异常,则将错误信息返回,目前尚未发现有异常出现。
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);//捕获异常,输出异常信息
        retInfo = "Error: " + ex.Message;
    }
    // 5. 强制关闭线程以节省资源
    finally
    {
        if (p != null)
            p.Close();
    }

    // 6. 返回执行结果, <表示开始,>表示结果, E表示错误
    return retInfo;
}

3 异步调用

异步调用可以保证界面不会卡死,实现代码如下:

private async void button1_Click(object sender, EventArgs e)
{
    var result = "";
    await Task.Run(() =>
    {
        DosArguments da = DosArguments.New("abc", "info");
        result = RunCommand("Converter.exe", da.ToDosString(), (double)numericUpDown1.Value);
    });
    textBox1.Text += result + "\r\n";
}

异步的原理很简单,就是先调用,有了结果返回后再处理结果。

扩展 异步任务的目标可以理解为主界面有n个可并行的工作,安排了n个线程去执行,然后任何一个线程执行完后会返回到主线程,主线程再执行之前定好的尾工作。