2

My C# program runs a process that starts a command prompt application passing in arguments to it, when the specific button is clicked.

  1. the program gets a directory path from the user selection, and checks to see if it is empty.

  2. If it is not empty the for each loop will loop through the array of full paths to each file in the directory. It will also set a progress bar to 0 and ready it for incrementation

  3. As it loops through it will run the cli-task using Process

Here is the problem: Upon completion of the task of looping through the file I want it to delete the file and increment the progress bar.

This works fine if do have it go through one by one like this:

process.WaitForExit(10000);
File.Delete(fileName);
progressBar1.Increment(1);

but the program is incredibly slow. as it waits for each process to complete before it starts the next one.

So I then attempted the code below:

string[] files = Directory.GetFiles(label1.Text);

if (files.Length != 0)
{
    progressBar1.Value = 0;
    progressBar1.Minimum = 0;
    progressBar1.Maximum = files.Length;

    foreach (string fileName in files)
    {
        System.Diagnostics.Process process = new System.Diagnostics.Process();
        System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
        //startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
        startInfo.FileName = @"C:\Program Files\cli-tool\cli.exe";
        startInfo.Arguments = "-i " + "\"" + fileName + "\"" + " -o " + "\"" + label2.Text + "\\" + Path.GetFileName(fileName) + "\"" + " -s -t";
        process.StartInfo = startInfo;
        process.EnableRaisingEvents = true;
        process.Start();
        process.Exited += delegate
        {
            File.Delete(fileName);
            progressBar1.Increment(1);
        };
    }

Unfortunately when I run it this way it crashes the program when it gets to the File.Delete(fileName) part, but the original process.start task works, but it is able to remove the first file of the first process that exited it looks like.

the following error is shown in the debug console of visual studio:

A first chance exception of type 'System.InvalidOperationException' occurred in System.Windows.Forms.dll The program '[3308] IonicFolderProtector.vshost.exe: Managed (v4.0.30319)' has exited with code 0 (0x0).

I cannot determine what is wrong with this code. Am I wrong to think that process.Exited += delegate { // some code }; will run each time as each process that is created at the same time?

Behzad
  • 3,502
  • 4
  • 36
  • 63
adbarads
  • 1,253
  • 2
  • 20
  • 43
  • "it crashes the program" is way too broad. What specifically is the error? – mason Jun 02 '16 at 16:14
  • A first chance exception of type 'System.InvalidOperationException' occurred in System.Windows.Forms.dll The program '[3308] IonicFolderProtector.vshost.exe: Managed (v4.0.30319)' has exited with code 0 (0x0). – adbarads Jun 02 '16 at 16:17
  • You need to get the message from the exception, and any inner exceptions if they're present. – mason Jun 02 '16 at 16:18
  • 1
    Shouldn't you set the process.Exited delegate before starting the process? – PaulF Jun 02 '16 at 16:22
  • Catch it, call ToString on it, and stick it in an [edit] –  Jun 02 '16 at 16:23
  • Probably the Exited event is called from a background thread. Try to remove the line `progressBar1.Increment(1);` to verify that. If that works without exceptions, you have to dispatch the call `progressBar1.Increment(1);` to the GUI thread. – JanDotNet Jun 02 '16 at 16:24
  • @JNS - I just tried your suggestion and it appeared to have worked. It prevented the crash from happening. But what's throwing me off now is that only 1 file from the directory is being deleted, unless I click the button again and re-run the process. It is almost as if the loop isn't working. – adbarads Jun 02 '16 at 16:29
  • Try to add the line `var file = fileName` before the delete stament in the delegate and pass the `file` to the delete method. Otherwise only the last file will be deleted (n time). – JanDotNet Jun 02 '16 at 16:33
  • @JNS - nope that didn't work. But I did do a `System.Diagnostics.Debug.WriteLine(file);` and it showed the same file getting consoled out each time which explains why that didn't work. This is weird seems like the foreach loop is not working. and I just solved it by placing the `var file = fileName;` outside of the delegate right above that line of code. I guess that variable doesn't change once it is inside of the delegate. – adbarads Jun 02 '16 at 16:39
  • @JNS - so going back to your original explanation for the first issue: `If that works without exceptions, you have to dispatch the call progressBar1.Increment(1); to the GUI thread.` How do I do this? can you point me to stack overflow or google somewhere? Not sure what this means. Pretty new to all this. – adbarads Jun 02 '16 at 16:43

1 Answers1

5

Pretty sure you are running in to a variable capture issue, put a var temp = filename; inside the foreach then do File.Delete(temp); in the delegate.

foreach (string fileName in files)
{
    var temp = fileName;
    System.Diagnostics.Process process = new System.Diagnostics.Process();
    System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
    //startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
    startInfo.FileName = @"C:\Program Files\cli-tool\cli.exe";
    startInfo.Arguments = "-i " + "\"" + fileName + "\"" + " -o " + "\"" + label2.Text + "\\" + Path.GetFileName(fileName) + "\"" + " -s -t";
    process.StartInfo = startInfo;
    process.EnableRaisingEvents = true;
    process.Start();
    process.Exited += delegate
    {
        File.Delete(temp);
        progressBar1.Increment(1);
    };
}

This will make sure the correct file is actually being deleted. You also may need to do a invoke for progressBar1.Increment() because I don't know if the event will be running on the UI thread.

    process.Exited += delegate
    {
        File.Delete(temp);
        progressBar1.Invoke(new Action(() => progressBar1.Increment(1)));
    };
Community
  • 1
  • 1
Scott Chamberlain
  • 124,994
  • 33
  • 282
  • 431
  • Missing ) at the end of `progressBar1.Invoke(new Action(() => progressBar1.Increment(1));` but I have tried it, and all is working now. thanks. – adbarads Jun 02 '16 at 17:13