如何在C#中执行多个.BAT文件

时间:2013-09-24 11:34:45

标签: c# winforms batch-file process cmd

我需要使用“c#windows form application”执行多个批处理文件。如果bat包含一行或多行如:“start filename.exe”我的程序会一直等到“filename.exe”终止,显然这不是我需要的东西。 附上我用过的代码片段你会找到一个示例windows窗体应用程序。

提前致谢。

弗朗西斯

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Sample
{
    public partial class Form1 : Form
    {

        /*
         * Batch files
         * 
             c:\batch1.bat
                    echo startExecution
                    start /b calc.exe
                    echo endExecution
                    exit
         * 
         * 
            c:\batch2.bat
                    echo startExecution2
                    start /b notepad.exe
                    echo endExecution2
                    exit

         */

        public Form1()
        {
            //Just for sample is unsafe
            Control.CheckForIllegalCrossThreadCalls = false;
            InitializeComponent();
            this.button1.Click += button1_Click;   
        }


        private void button1_Click(object sender, EventArgs e)
        {
            this.richTextBox1.Text = "Initialized\r\n";
            BatchExecution be = new BatchExecution("c:\\batch1.bat");
            be.endOccurs += be_endOccurs;
            be.DoWork();
            be = new BatchExecution("c:\\batch2.bat");
            be.endOccurs += be_endOccurs;
            be.DoWork();
        }

        private void be_endOccurs(BatchExecution sender)
        {
            this.richTextBox1.AppendText(sender.output);
            sender = null;
        }
    }

    public class BatchExecution
    {

        private String batch { get; set; }
        public Process process { get; private set; }

        public delegate void workHasEndedHandler(BatchExecution sender);
        public event workHasEndedHandler endOccurs;

        private Boolean _hasEnded = false;
        public Boolean hasEnded
        {
            get
            {
                return _hasEnded;
            }
            set
            {
                _hasEnded = value;
                if (_hasEnded)
                {
                    endOccurs(this);
                }
            }
        }

        public String output { get; set; }

        public BatchExecution(String batFile)
        {
            batch = batFile;
        }

        private void workCompleted()
        {
            if (process != null)
            {
                process.Close();
                process.Dispose();
                GC.SuppressFinalize(process);
                process = null;
            }

            output += "Batch ended\r\n";
            hasEnded = true;
        }

        public void DoWork()
        {
            output = "Batch output:\r\n";
            process = new Process();
            process.StartInfo.CreateNoWindow = true;
            process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
            process.StartInfo.FileName = "cmd.exe";
            process.StartInfo.Arguments = " /c \"" + batch + "\"";
            process.StartInfo.UseShellExecute = false;
            process.StartInfo.RedirectStandardOutput = true;
            process.StartInfo.RedirectStandardError = true;
            process.ErrorDataReceived += process_ErrorDataReceived;
            process.OutputDataReceived += process_OutputDataReceived;
            process.Start();
            process.BeginOutputReadLine();
            process.WaitForExit();
            workCompleted();
        }

        private void process_ErrorDataReceived(object sender, DataReceivedEventArgs e)
        {
            output += "" + e.Data + "\r\n";
        }

        private void process_OutputDataReceived(object sender, DataReceivedEventArgs e)
        {
            output += "" + e.Data + "\r\n";
        }
    }

}

从Kenneth的建议开始,我删除了“process.WaitForExit()”。现在使用BackgroundWorker我可以检查批量执行是否完成。它似乎已经解决但我不太喜欢它。有人有更好的主意吗?

所以Form1代码的新版本是:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Sample
{
    public partial class Form1 : Form
    {

        /*
         * Batch files
         * 
             c:\batch1.bat
                    echo startExecution
                    start /b calc.exe
                    ping 1.1.1.1 -n 1 -w 10000
                    echo endExecution
                    exit

         * 
         * 
            c:\batch2.bat
                    echo startExecution2
                    start /b notepad.exe
                    echo endExecution2
                    exit

         */

        private List<String> batchFiles { get; set; }
        private Int32 batchIndex { get; set; }
        private BatchExecution be { get; set; }

        public Form1()
        {
            //Just for sample is unsafe
            Control.CheckForIllegalCrossThreadCalls = false;
            InitializeComponent();
            this.button1.Click += button1_Click;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            batchIndex = 0;
            batchFiles = new List<String>();
            batchFiles.Add("c:\\batch1.bat");
            batchFiles.Add("c:\\batch2.bat");
            this.richTextBox1.Text = "Initialized\r\n";

            be = new BatchExecution(batchFiles[batchIndex]);
            be.endOccurs += be_endOccurs;
            be.DoWork();
        }

        private void be_endOccurs(BatchExecution sender)
        {
            this.richTextBox1.AppendText(sender.output);
            if (sender.process != null)
            {
                sender.process.Close();
                sender.process.Dispose();
                GC.SuppressFinalize(sender.process);
                sender.process = null;
            }
            sender = null;
            batchIndex++;

            if (batchFiles != null && batchFiles.Count > batchIndex)
            {
                be = new BatchExecution(batchFiles[batchIndex]);
                be.endOccurs += be_endOccurs;
                be.DoWork(); 
            }

        }
    }

    public class BatchExecution
    {
        private String batch { get; set; }
        public Process process { get; set; }

        private BackgroundWorker asyncVerifier { get; set; }

        public delegate void workHasEndedHandler(BatchExecution sender);
        public event workHasEndedHandler endOccurs;

        private Boolean _hasEnded = false;
        public Boolean hasEnded
        {
            get
            {
                return _hasEnded;
            }
            private set
            {
                _hasEnded = value;
                if (_hasEnded)
                {
                    if (asyncVerifier != null)
                    {
                        asyncVerifier.Dispose();
                        GC.SuppressFinalize(asyncVerifier);
                        asyncVerifier = null;
                        output += "Batch ended\r\n";
                    }
                    endOccurs(this);
                }
            }
        }

        public String output { get; set; }

        public BatchExecution(String batFile)
        {
            batch = batFile;
        }

        public void DoWork()
        {
            output = "Batch output:\r\n";
            asyncVerifier = new BackgroundWorker();
            asyncVerifier.DoWork += asyncVerifier_DoWork;
            process = new Process();
            process.StartInfo.CreateNoWindow = true;
            process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
            process.StartInfo.FileName = "cmd.exe";
            process.StartInfo.Arguments = " /c \"" + batch + "\"";
            process.StartInfo.UseShellExecute = false;
            process.StartInfo.RedirectStandardOutput = true;
            process.StartInfo.RedirectStandardError = true;
            process.ErrorDataReceived += process_DataReceived;
            process.OutputDataReceived += process_DataReceived;
            process.Start();
            asyncVerifier.RunWorkerAsync();
            process.BeginOutputReadLine();
        }

        private void asyncVerifier_DoWork(object sender, DoWorkEventArgs e)
        {
            Boolean performCheck = true;

            while (performCheck)
            {
                if (process != null && !process.HasExited)
                {
                    System.Threading.Thread.Sleep(500);
                }
                else
                {
                    performCheck = false;
                }
            }
            hasEnded = true;
        }

        private void process_DataReceived(object sender, DataReceivedEventArgs e)
        {
            output += "" + e.Data + "\r\n";
        }
    }

}

2 个答案:

答案 0 :(得分:1)

尝试在单独的线程中执行每个文件。 这样,他们彼此独立。

示例:

class MyThreadData
{
  // bat info
};

void ThreadFunction(object arg)
{
  MyThreadData batInfo = (MyThreadData)arg;
  // do work
}

void ExecBats(void)
{
  System.Threading.Thread t1 = new System.Threading.Thread(ThreadFunction);
  MyThreadData bat1 = new MyThreadData();
  t1.Start(bat1);
  // ...
}

答案 1 :(得分:0)

如果您取消对process.WaitForExit();的调用,程序将继续,而不是等到该过程退出。

显然,您对WorkCompleted的呼吁不仅仅意味着所有批次都已启动。