0

I need to execute multiples batch files using "c# windows form application". Just in case of bat containing one or more line like: "start filename.exe" my program waits until "filename.exe" will be terminated, and obviously this isn't what i need i have
attached the piece of code i used hop you'll find a sample windows form app.

Thanks in advance.

Francesco

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

}

Starting from Kenneth suggestion i removed "process.WaitForExit()". Now using a BackgroundWorker i can check if batch execution is completed. It seems solved but i don't like it very much. Anybody has better idea?

so the new version of Form1's code is:

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
  • Do you need to use batch files if you are using C#? Just putting that out there as generally it is much easier to maintain and debug C# code than batch files. If the batch files are very simple, you can probably just run the commands from C# and easily control the flow. If they are very complex... well, you would probably benefit from porting it to C# anyway as batch files are painful to use (coming from someone who loves batch files). Commented Sep 24, 2013 at 13:22
  • Yes i really need it. The requested feature is to execute multiple batch files which are edited and maintained by the users. Commented Sep 24, 2013 at 13:37

2 Answers 2

1

Try executing each of your files in a seperate thread. That way, they are independent of eachother.

Example:

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);
  // ...
}
Sign up to request clarification or add additional context in comments.

2 Comments

Unfortunately i can't, all executions must be sync. I need to be sure second execution starts at the end of first, third at the end of second etc...
In that case, try using a callback with the bat threads, so your main thread can start new bat threads as needed and wont be blocked while the bat executes.
0

If you remove the call to process.WaitForExit(); the program will continue and not wait until the process exits.

Obviously, your call to WorkCompleted than just merely means that all batches were started.

4 Comments

Yes, because from what I can see you're killing the process, which still might be running
That's what I was driving at. Your answer didn't specifically mention this
Actually, now that I've investigated your code a bit better @Beta-Carotin's answer is better.
Unfortunately i can't, all executions must be sync. I need to be sure second execution starts at the end of first, third at the end of second etc...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.