Monitor process when closing C #

0

I have a problem with the following code, what I try is that a process calling ffmpeg that runs inside the system is closed giving a warning that the work is finished.

private void btnIniciar_Click(object sender, EventArgs e)
        {
            btnIniciar.Enabled = false;
            btnCancelar.Enabled = true;
            Process p = new Process();
            ProcessStartInfo psi = new ProcessStartInfo("cmd.exe");
            //psi->WindowStyle = ProcessWindowStyle::Hidden;
            psi.Arguments = "/k ffmpeg -i " + txtArchivo.Text + " proceso\video.mp4";
            p.StartInfo = psi;
            p.Start();
            Thread.Sleep(1000);
            while(procesoFFMPEG())
            {
                lblEstado.Text = "Estado: En ejecucion...";
            }
            lblEstado.Text = "Estado: Finalizado";
            //p.Kill();
        }

public Boolean procesoFFMPEG()
        {
            if(Process.GetProcessesByName("ffmpeg").Length > 0)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

The problem is that when you run the program it frizea until the ffmpeg process is closed.

Where am I wrong?

greetings

    
asked by 44teru 16.01.2017 в 05:15
source

2 answers

3

You are blocking the thread that handles the UI , so the user interface stays fried.

Use a BackgroundWorker , you'll have to tune it up a bit, but it would be something like this:

private void btnIniciar_Click(object sender, EventArgs e) {
    btnIniciar.Enabled = false;
    btnCancelar.Enabled = true;

    lblEstado.Text = "Estado: En ejecucion...";
    Process p = new Process();
    ProcessStartInfo psi = new ProcessStartInfo("cmd.exe");
    psi.Arguments = "/k ffmpeg -i " + txtArchivo.Text + " proceso\video.mp4";
    p.StartInfo = psi;
    p.Start();

    var worker = new System.ComponentModel.BackgroundWorker() {
        WorkerReportsProgress = true,
        WorkerSupportsCancellation = true
    };
    btnCancelar.OnClick => (s, a) => worker.CancelAsync();

    worker.DoWork += (s, a) => {
        int n=0;
        while (procesoFFMPEG()) {
            if (worker.CancellationPending) { a.Cancel = true;  break; }
            worker.ReportProgress((n++)%100);
        }
    };
    worker.ProgressChanged += (s, a) => { } 

    worker.RunWorkerCompleted += (s,a) => {
        lblEstado.Text = "Estado: Finalizado";
    }
    worker.RunWorkerAsync();
}

Note that the code will run on another thread, and within DoWork you will not be able to access elements of the user interface, unless you use the Invoke method of the form or the control you want to access, so that that code is executed in the thread that handles the UI .

control.Invoke((MethodInvoker) (() => control.Text = "new text"));
    
answered by 16.01.2017 / 23:40
source
1

The problem is probably in your while(procesoFFMPEG()).. loop. This loop is blocking the main thread of the application, not letting the UI update.

Try putting a Thread.Sleep or a Application.DoEvents() into that loop, which will make the UI have time to process the events.

Edit

TL; DR; In 99% of cases, the most correct way to deal with these problems is indicated by @Blau in your response.

As pointed out by @Blau, DoEvents has several contraindications that deserve to be noted. It can cause a re-entry problem, because if any of the messages processed during execution cause an application event to fire, other parts of the code can run and cause errors that are difficult to debug. That's why Microsoft does not recommend using for operations that take a long time . In those cases, a BackgroundWorker or use async/await is preferable.

As an additional explanation, there is a debate about whether BackgroundWorker has been left, as of .Net 4.5, obsolete. In general, if we use .Net 4.5, there is a certain consensus that it is preferable to use async/await , especially if the work to be performed includes input / output operations. For cases like the one we are dealing with, the use of BackgroundWorker is correct.

However, and to defend my answer a bit, for loops that will take very little time, DoEvents is perfectly acceptable in my opinion.

    
answered by 16.01.2017 в 09:06