zyfsky666 发表于 2021-11-9 19:15:09

C# 后台调用 CMD 执行命令

C# 后台调用 CMD 执行命令
有时会在程序中调用系统的命令行工具 cmd.exe 来静默执行一些系统命令,然后获取返回值。本文将展示 .NET/C# 静默运行 cmd 并执行命令的方法,包括 有返回值 和 无返回值 两种。

无返回值
public static void Execute(string command)
{
    var processInfo = new ProcessStartInfo("cmd.exe", "/S /C " + command)
    {
      CreateNoWindow = true,
      UseShellExecute = true,
      WindowStyle = ProcessWindowStyle.Hidden
    };

    Process.Start(processInfo);
}

有返回值
public static string ExecuteWithOutput(string command)
{
    var processInfo = new ProcessStartInfo("cmd.exe", "/S /C " + command)
    {
      CreateNoWindow = true,
      UseShellExecute = false,
      WindowStyle = ProcessWindowStyle.Hidden,
      RedirectStandardOutput = true
    };

    var process = new Process {StartInfo = processInfo};
    process.Start();
    var outpup = process.StandardOutput.ReadToEnd();

    process.WaitForExit();
    return outpup;
}
————————————————
在读取StandardOutput流时,有两种方式,即同步和异步。

同步方式,会在读取流的一方和写入流的一方形成依赖关系,这种依赖关系形成了死锁的条件。当要写或读足够多的数据时,双方会等待对方写完或者读完,彼此的等待导致了死锁的产生。具体的解释可以参见msdn:http://msdn.microsoft.com/en-us/library/system.diagnostics.process.standardoutput(v=VS.80).aspx

如果我们不需要重定向输出,可以将psi.RedirectStandardOutput设置为false。

如果需要重定向输出,那么必须解决潜在的死锁问题,方法有两个:

方法一:Call ReadToEnd() before WaitForExit()

private static void ExecuteTool(string toolFile, string args)
      {
            Process p;
            ProcessStartInfo psi;
            psi = new ProcessStartInfo(toolFile);
            psi.Arguments += args;

            psi.UseShellExecute = false;
            psi.RedirectStandardOutput = true;//允许重定向标准输出
            psi.CreateNoWindow = true;
            psi.RedirectStandardError = true;
            psi.WindowStyle = ProcessWindowStyle.Hidden;

            p = Process.Start(psi);

    string output = p.StandardOutput.ReadToEnd(); //Call ReadToEnd() before WaitForExit()

            p.WaitForExit();
            p.Close();
      }

方法二:采用异步方式(适用于同时获取标准输出流和错误流)

private static void ExecuteTool(string toolFile, string args)
      {
            Process p;
            ProcessStartInfo psi;
            psi = new ProcessStartInfo(toolFile);
            psi.Arguments += args;

            psi.UseShellExecute = false;
            psi.RedirectStandardOutput = true;//允许重定向标准输出

    psi.RedirectStandardError = true;
            psi.CreateNoWindow = true;
            psi.RedirectStandardError = true;
            psi.WindowStyle = ProcessWindowStyle.Hidden;

            p = Process.Start(psi);

    p.OutputDataReceived += new DataReceivedEventHandler(OnDataReceived);
            p.BeginOutputReadLine();

            p.WaitForExit();

    if (p.ExitCode != 0)
            {
                result.Append(p.StandardError.ReadToEnd());
            }         
            p.Close();
      }

  private static void OnDataReceived(object Sender, DataReceivedEventArgs e)
      {
            if (e.Data != null)
            {
                result.Append(e.Data);
            }
      }

------------------------------------------------------------------------------------------------------------------
这使用异步/等待来启动进程,然后使用进程输出事件来更新UI。
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Windows.Forms;
using System.IO;

namespace SendInput
{
    public partial class Form1: Form
    {
   private SynchronizationContext _syncContext;

   public Form1()
   {
      InitializeComponent();
   }

   private async void btnCommand_Click(object sender, EventArgs e)
   {
      CheckForIllegalCrossThreadCalls = false;

      await StartProcessAsync();
   }

   private Task StartProcessAsync()
   {
      return Task.Run(()=>
      {
       try
       {
      //Create Process Start information
      ProcessStartInfo processStartInfo =
         new ProcessStartInfo(@"C:\Users\devPC\Desktop\Server\run.bat");
      processStartInfo.ErrorDialog = false;
      processStartInfo.UseShellExecute = false;
      processStartInfo.RedirectStandardError = true;
      processStartInfo.RedirectStandardInput = true;
      processStartInfo.RedirectStandardOutput = true;

      //Execute the process
      Process process = new Process();
      process.StartInfo = processStartInfo;

      process.OutputDataReceived += (sender, args) => UpdateText(args.Data);
      process.ErrorDataReceived += (sender, args) => UpdateErrorText(args.Data);

      process.Start();
      process.BeginOutputReadLine();
      process.BeginErrorReadLine();
      process.WaitForExit();
       }
       catch (Exception ex)
       {
      MessageBox.Show(ex.Message);
       }
      });
   }

   private void UpdateText(string outputText)
   {
      _syncContext.Post(x => rtbConsole.AppendText("Output \n==============\n"), null);   
      _syncContext.Post(x => rtbConsole.AppendText(outputText), null);
   }

   private void UpdateErrorText(string outputErrorText)
   {
      _syncContext.Post(x => rtbConsole.AppendText("\nError\n==============\n"), null);
      _syncContext.Post(x => rtbConsole.AppendText(outputErrorText), null);
   }
    }
}
页: [1]
查看完整版本: C# 后台调用 CMD 执行命令