How do I stop a running program?

Asked

Viewed 166 times

0

I created a program that compresses files using 7z and as there are several files within a loop and the program should compress 1 file at a time, I used WaitForExit()

The program works perfectly, but now I would like to put a cancel button and I’m not getting it, because I believe that the WaitForExit() do not let me click the button until you have finished the process.

How can I make this button cancel?

My code:

foreach (string currentFile in txtFiles)
{
    game = PastaDestino + 
Path.GetFileName(currentFile).Replace(Path.GetExtension(currentFile), "") + 
".7z";
    bin = currentFile;
    cue = currentFile.Replace(Path.GetExtension(currentFile), "") + ".cue";
    command = String.Format("a -t7z \"{0}\" \"{1}\" \"{2}\" -mx=9", game, 
bin, cue);

p = new ProcessStartInfo
{
    FileName = "7z.exe",
    Arguments = command,
    WindowStyle = ProcessWindowStyle.Hidden
};

    x = Process.Start(p);
    x.WaitForExit();
}

thank you.

3 answers

2

x.Close()

I put in the Github for future reference.

Always read the documentation complete when using a component.

Obviously it will only be executed when possible. The WaitForExit() will prevent anything from being executed until the end of the process.

Ideal when you want to do something like this is to use an API instead of launching a process that you have no control over

  • So but my application it does not answer I click on the button and does not let click is as if I have not answered, I believe that it should be the Waitforexit that does it, stop the process itself I know how to do but the problem is that it does not let press the button and if I do not use the Waitforexit it does not work and does not compact the files

2


To kill the Voce process you can call process.Kill();

Yet the trick is in not calling WaitForExit since this method will wait until the process ends and this way will also block your graphic interface.

In other words Voce has to subscribe to the event Exited.

Due to the functioning of 7zip Voce has the restriction to release only one process at a time to add an archive to the zip file. This has implications in terms of code. You cannot simply scroll through the files. You have to re-launch the process only when the previous process is finished.

Each time a file is added Voce can also have a progress bar. This progress notification mechanism will also serve to determine when the process of adding all the files to the zip has completed.

In this particular algorithm I do not allow the cancellation of the process itself. I simply stop adding files to the archive. What this means is if Voce has quite large files then the cancellation will only be processed once that file is added.

One way to do this is this::

public partial class Form1 : Form, IProgress<int>
{
    private CancellationTokenSource _cancellation;
    public Form1()
    {
        InitializeComponent();
    }

    private void ZipFiles(IList<string> files, IProgress<int> progress, CancellationToken token)
    {
        Process Zip(string file)
        {
            var cue = Path.ChangeExtension(file, ".cue");
            var process = new Process()
            {
                EnableRaisingEvents = true,
                StartInfo = new ProcessStartInfo
                {
                    FileName = "7z.exe",
                    Arguments = $"a zip.7z {file} {cue}",
                    WindowStyle = ProcessWindowStyle.Hidden
                }
            };
            process.Start();
            return process;
        }

        var count = 0;
        void Handler(object o, EventArgs a)
        {
            var p = o as Process;
            if (_cancellation.Token.IsCancellationRequested)
            {
                return;
            }
            if (count < files.Count)
            {
                var next = Zip(files[count]);
                count++;
                next.Exited += Handler;
            }
            progress.Report(count * 100 / files.Count);
            p.Exited -= Handler;
        }
        {
            var process = Zip(files[count]);
            process.Exited += Handler;
        }
    }

    private void btnZip_Click(object sender, EventArgs e)
    {
        btnZip.Enabled = false;
        _cancellation = new CancellationTokenSource();
        var files = Directory.EnumerateFiles(@"C:\code", "*.cs", SearchOption.AllDirectories)
            .Take(100)
            .ToList();
        ZipFiles(files, this, _cancellation.Token);
    }

    private void btnCancel_Click(object sender, EventArgs e)
    {
        _cancellation.Cancel();
        progressBar.Value = 0;
        btnZip.Enabled = true;
    }

    public void Report(int value)
    {
        Invoke((Action)(() =>
        {
            progressBar.Value = value;
            if (value == 100)
            {
                btnZip.Enabled = true;
            }
        }));
    }
}

The best thing would be to put all the files you want to archive inside a structure, since the 7zip allows you to archive the files of a board. That way your code would be simpler.

7z a c:\archive3.zip dir2\dir3\

But in case you need different directories then the code I provided should solve.

  • So as I said kill the process I know, but the program does not let it gets locked it only releases access to the boot after it ends, I wish I could cancel the process, but if I do not use the Waitforexit does not work, it may be that I am doing something wrong, but my program takes a list and I use the foreach dai every loop of foreach I want it to compact a file and these files are large and time consuming, if I do not use the Wait it runs all loop and not compact anything

  • @Fabyoguimaraes Supplementing your question with a [mcve] will help you counter your goal.

  • thanks Bruno, but the code I posted is basically just that the rest of the code are checks, Try etc, the program lists a contents of a folder runs the loop and runs the 7z, my doubt this in this code block inside the loop I need to run a command and call the 7z to compress the file the loop is reading as compression is a time consuming process I used the Waitforexit, because if not use the loop runs over everything and calls the 7z all at once and does not work compact anything, my doubt is that even putting the boot cancel it does not answer only at the end when it finishes everything

  • @Fabyoguimaraes I updated my answer. In my application I have 2 butoes and a progress bar. None of this is even necessary. What interests him is the method ZipFiles

  • Thank you Bruno, I understood your idea and I’m trying to get it to work, but it’s giving System error.He argued Tofrangeexception: 'The index was out of range. It should be non-negative and smaller than the size of the collection. Zip(files[Count]); Count is 0, but I’ll try to fix it I’m just giving a return

  • Bruno worked out his code, only have a detail when I click cancel the program for at the time but I realized that the process is still running, I realized this because I was deleting 7z.zip and windows did not leave then I went to see the 7z.exe was running and continuing the work, thanks for the tips, I’m only giving a feedback but I will try to solve this problem, thanks

  • People who helped me a lot thanks, @Bruno Costa for this topic not getting too extensive was to give as solved, and with your answer it worked to do what I wanted, now that I’m trying other related problems I would create another topic focused on this new problem, thanks

Show 2 more comments

1

This kind of synchrony between threads is easy:

    public class Compressor
    {
        static object @lock = new object();
        static bool parar = false;
        static Process atual = null;
        public static async Task<bool> Comprimir(IEnumerable<string> txtFiles, string PastaDestino, string game, string bin, string cue)
        {
            bool completo = true;
            
            await Task.Run(() =>
            {
                string command = "";
                Process x;
                ProcessStartInfo p;

                foreach (string currentFile in txtFiles)
                {
                    if (parar)
                    {
                        completo = false;
                        break;
                    }
                        
                    game = PastaDestino +
                    Path.GetFileName(currentFile).Replace(Path.GetExtension(currentFile), "") +
                ".7z";
                    bin = currentFile;
                    cue = currentFile.Replace(Path.GetExtension(currentFile), "") + ".cue";
                    command = String.Format("a -t7z \"{0}\" \"{1}\" \"{2}\" -mx=9", game, bin, cue);

                    p = new ProcessStartInfo
                    {
                        FileName = "7z.exe",
                        Arguments = command,
                        WindowStyle = ProcessWindowStyle.Hidden
                    };

                    
                    lock(@lock)
                    {
                        x = Process.Start(p);
                        atual = x;
                    }
                    x.WaitForExit();
                    lock(@lock)
                    {
                        atual = null;
                    }
                }
                lock(@lock)
                {
                    atual = null;
                }
            });

            return completo;
        }

        public static void Parar()
        {
            lock(@lock)
            {
                parar = true;
                if(atual != null)
                {
                    try {atual.Kill();} catch {} // Só para garantir em caso de erro
                }
            }
        }

        public static void Reset()
        {
            parar = false;
            atual = null;
        }
    }

To rotate:

Compressor.Comprimir(arquivos, "destino", "game", "bin", "cue");

To stop:

Compressor.Parar();

To use it again:

Compressor.Reset();

Don’t forget to clean up the interrupted file if applicable.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.