winforms 如何在一个循环中一个一个地运行进程?

2ul0zpep  于 2023-06-06  发布在  其他
关注(0)|答案(2)|浏览(725)

我尝试在for循环中向进程传递文件路径,并让ffmpeg.exe每次只读取一个视频文件的格式。但是,它在文本框的文本包含第一个视频的内容后停止。我试过process.close(),process.hasExited等,但这些都不能阻止程序启动多个进程,并导致委托大量更新文本框(输出没有按正确的顺序列出,我无法分辨哪些行属于哪个视频,一些输出丢失或在文本中显示两次)。如何在for循环中每次只执行一个进程,然后再执行下一个进程?

foreach (String file in inputList)
            {
                if (flag == true)
                {
                    flag = false;
                    //textBox1.Text += file + Environment.NewLine;
                    checkvideoFormat(file);
                }

            }
            
            

        }
        catch (Exception err)
        {
            MessageBox.Show(err.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
    }
    private void checkvideoFormat(String filePath)
    {
        Process process1 = new Process();
        process1.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
        process1.StartInfo.CreateNoWindow = true;
        process1.StartInfo.UseShellExecute = false;
        process1.StartInfo.FileName = ".\\ffmpeg.exe";
        process1.StartInfo.WorkingDirectory = ".\\";
        process1.EnableRaisingEvents = true;
        process1.StartInfo.RedirectStandardOutput = true; //if this is true, UseShellExecute must be false. true if output should be written to StandardOutput
        process1.StartInfo.RedirectStandardError = true;
        //indicates that the associated Process has written a line that's terminated with a newline
        process1.ErrorDataReceived += new DataReceivedEventHandler(inputHandler);
        
        process1.Exited += (ending, p) =>
        {
            flag = true;
            Console.WriteLine(flag);
            //textBox1.Text += "Hey " + file + Environment.NewLine;
            //process1.CancelOutputRead();
            //process1.CancelErrorRead();//
        };
        
        process1.StartInfo.Arguments = "-i " + " \"" + filePath + "\"";
        Console.WriteLine(process1.StartInfo.Arguments);
        process1.Start();
        process1.BeginOutputReadLine();
        process1.BeginErrorReadLine();
        //process1.Close();
        //process1.WaitForExit();
        /*
        if(process1.HasExited == true)
        {
            //process1.Refresh();
            flag = true;
            //process1.Close();
            //process1.Kill();
            Thread.Sleep(1000);
        }
        */
    }


    int test_123 = 0;
    private void inputHandler(object sender, DataReceivedEventArgs l)
    {
        cba.Append(test_123 + l.Data + "\n");
        videoInput = test_123 + l.Data + Environment.NewLine;
        //Console.WriteLine(cba);
        //Process p = sender as Process;
        Console.WriteLine(videoInput);
        
        this.Invoke(new MethodInvoker(() =>
        {

            if (!String.IsNullOrEmpty(videoInput))
            {
                textBox1.Text += videoInput;
            }

        }));

        test_123++;

    }
eiee3dmh

eiee3dmh1#

我建议重写你的程序来使用异步模式。在.Net 5+中,您可以使用WaitForExitAsync

private async Task CheckvideoFormat(string filePath)
{
   using var process1 = new Process();

   ...

    return await process1.WaitForExitAsync() ; // make sure process is not disposed before the task has completed.
}

并确保在循环中await这个调用。此模式应避免阻塞UI线程。
对于旧版本,您可能可以使用exited事件和TaskCompletionSource事件来模拟行为。

eqqqjvef

eqqqjvef2#

我已经尝试使用@JonasH的建议使用异步模式编写代码。此外,我还尝试让所有实际工作并行运行,然后只在所有工作完成后才写入文本框,从而确保其顺序正确。我不确定这样做是否有任何不必要的副作用。我也不确定你想为每个文件写什么,但这应该很容易纠正。
希望有用🙂

private async void Button_Click(object sender, RoutedEventArgs e)
    {
            string[] inputList = { "fileName1", "fileName2" };

        try
        {
            int fileNumber = 0;

            var output = await Task.WhenAll(inputList.Select(x => checkvideoFormat(x, fileNumber++)));

            foreach (var outputLine in output.Where(x => x != null))
            {
                textBox1.Text += outputLine + Environment.NewLine;
            }

        }
        catch (Exception err)
        {
            MessageBox.Show(err.Message, "Error", MessageBoxButton.OK);
        }
    }

    private async Task<string?> checkvideoFormat(string filePath, int fileNumber)
    {
        string? backText = null;
        Process process1 = new Process();
        process1.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
        process1.StartInfo.CreateNoWindow = true;
        process1.StartInfo.UseShellExecute = false;
        process1.StartInfo.FileName = ".\\ffmpeg.exe";
        process1.StartInfo.WorkingDirectory = ".\\";
        process1.EnableRaisingEvents = true;
        process1.StartInfo.RedirectStandardOutput = true; //if this is true, UseShellExecute must be false. true if output should be written to StandardOutput
        process1.StartInfo.RedirectStandardError = true;
        //indicates that the associated Process has written a line that's terminated with a newline
        process1.ErrorDataReceived += (sender, args) =>
        {
            backText = $"{fileNumber} {args.Data}";
        };

        process1.Exited += (ending, p) =>
        {
            // Don't know if you want to add something to backText here?
        };

        process1.StartInfo.Arguments = "-i " + " \"" + filePath + "\"";
        Console.WriteLine(process1.StartInfo.Arguments);
        process1.Start();
        await process1.WaitForExitAsync();

        return backText;
    }

相关问题