C# 从连续运行的exe文件中删除闪烁

C# 从连续运行的exe文件中删除闪烁,c#,windows,winapi,C#,Windows,Winapi,我有几个.exe文件,我运行如下: public void RunCalculator(Calculator calculator) { var query = Path.Combine(EpiPath, calculator.ExeName + ".exe"); if (File.Exists(Path.Combine(EpiPath, "ffs.exe"))) { var p = new Process(

我有几个.exe文件,我运行如下:

   public void RunCalculator(Calculator calculator)
    {
        var query = Path.Combine(EpiPath, calculator.ExeName + ".exe");

        if (File.Exists(Path.Combine(EpiPath, "ffs.exe")))
        {
            var p = new Process();
            p.StartInfo.FileName = query;
            p.StartInfo.WorkingDirectory = EpiPath;
            p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
            p.StartInfo.UseShellExecute = false;
            p.StartInfo.CreateNoWindow = true;
            p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
            p.StartInfo.Arguments = String.Join(" ", calculator.Arguments);
            p.Start();
            p.WaitForExit();
        }
        else throw new InvalidOperationException();
    }
这段代码可以工作,但仍然有一些闪烁是由多次运行exe-s引起的。有没有办法消除闪烁,因为它真的很烦人的用户体验,因为它发生了几秒钟(有相当多的exe正在运行)

我尝试使用一个任务在不同的线程上执行,但由于每个exe都依赖于前一个线程(它写入文件)上的工作,因此我得到了一个IO异常

似乎exe文件只有在ProcessPriority设置为Realtime时才能工作

编辑:

有关我最近尝试的内容的更多详细信息: 正如@Jack Hughes建议的那样,我尝试使用一名背景工作者来解决这个问题:

以下是我所做的:

我在后台工作程序上调用RunWorkerAsync()函数,然后依次为每个计算器调用RunCalculator函数。闪烁仍然存在

编辑2: 我已经创建了一个详细的存储库,其中包含我运行exe文件、exe文件和ProcessHelper类的方式,这是Old Fox建议的。 您可以在自述文件中找到有关如何使用存储库的说明


链接到存储库:

将工作放在后台线程中,这样就不会阻塞主GUI线程

大概是这样的:

public class MainWindow : Window
{
    private readonly BackgroundWorker worker = new BackgroundWorker();

    public MainWindow()
    {
        this.Loaded += MyWindow_Loaded;
        worker.DoWork += worker_DoWork;
        worker.RunWorkerCompleted += worker_RunWorkerCompleted;
    }

    private void MyWindow_Loaded(object sender, RoutedEventArgs e)
    {
        // Start the background worker. May be better started off on a button or something else app specific
        worker.RunWorkerAsync();
    }

    private void worker_DoWork(object sender, DoWorkEventArgs e)
    {
       // run all .exes here...
       // Note: you cannot access the GUI elements directly from the background thread
       RunCalculator();
       RunOtherExes();
    }

    private void worker_RunWorkerCompleted(object sender, 
                                           RunWorkerCompletedEventArgs e)
    {
        //update ui once worker complete its work
    }

    private void RunCalculator()
    {
        var p = new Process();
        p.StartInfo.FileName = query;
        p.StartInfo.WorkingDirectory = path;
        p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
        p.StartInfo.CreateNoWindow = true;
        p.StartInfo.Arguments = String.Join(" ", calculator.Arguments);
        p.Start();
        p.WaitForExit();
    }

    private void RunOtherExes()
    {
        // ...
    }

}
如果需要,您也可以使用后台线程的进度更新GUI线程。

我遇到了与您在使用C#创建
ActiveX
扩展时描述的相同的“闪烁”问题。扩展必须启动一个隐藏的
控制台应用程序
,但是每次我启动应用程序时,控制台都会出现几毫秒

为了解决这个问题,我尝试了很多方法,比如:获取
进程
类的源代码并进行调试,
UAC
检查,
VM
与真实机器的对比等等

我找到的解决方案是使用
Win32Api
。以下代码段启动了一个没有“闪烁”的新进程:

这不是一个好的解决方案!然而,只有当你开始一个过程时,你才需要睡眠。。。所以我试着利用这些信息:

    private  void Button_Click(object sender, RoutedEventArgs e)
    {
        var ac = new Action(() => Application.Current.Dispatcher.Invoke(
            () =>
            {
                Thread.Sleep(50);
            }));
        Task.Factory.StartNew(() =>
        {

            //Provide path to epi
            string epiPath = @"c:/EPISUITE41";
            Level3ntCalculator cl = new Level3ntCalculator();
            var runner = new Calculators.Epi.Runners.ProcessRunner(epiPath, ac);


            runner.WriteXSmilesFiles("CCCCC1CCCCCCC1");
                    cl.Calculate(runner);

        });

    }
然后我更改了
ProcessRunner

    public void RunCalculator(Calculator calculator)
    {
     //bla bla bla...
        new Thread(new ThreadStart(_action)).Start();
        p.Start();
     //...
    }
在此代码段中,您在
UI
线程中执行
Thread.Sleep
的时间非常短(用户永远不会知道…)


这是一个糟糕的解决方案。。。但是它解决了问题。

仍然不清楚您正在经历什么样的闪烁,但是您在GUI线程上执行
WaitForExit()
这一事实看起来很麻烦。考虑到您正在运行一个外部程序,我真的看不到从另一个线程启动它并等待的意义,也许使用
Exited
事件而不是阻塞等待将释放GUI线程来完成其工作并停止问题


不要忘记将
EnableRaisingEvents
设置为true,并且IIRC将在线程池上引发事件,因此在触摸任何控件之前返回到UI上下文。

您所说的“闪烁”是什么意思?exe将运行,它们执行一些计算和一些IO操作,然后关闭。运行每个exe后,它将关闭,然后打开下一个exe。它们每个执行的操作都会导致整个窗口闪烁(我认为这与Windows的操作方式有关)。您是否从GUI线程启动上述操作以及其他许多操作?如果您正在GUI线程上做大量工作,并等待结果,那么您将阻止GUI更新。当它最终更新自己时,它可能看起来像是在闪烁。将您的处理放在后台线程中,并尽可能使主GUI线程保持空闲。@JackHughes,您能举个例子吗。我尝试使用一个任务在不同的线程上执行该任务,但由于每个exe都取决于前一个线程的工作(它写入文件),因此我得到了一个IO异常。如果查看接受的答案,您会发现一个很好的示例,说明如何执行该任务。如果我这样做,exe文件的执行顺序是否会同步?我需要它是同步的,以便得到正确的输出。这意味着我必须确保在执行exe文件B之前完成exe文件A。是<首先执行code>RunCalculator,并对进程调用
WaitForExit
,以便后台线程在启动下一个进程之前等待进程结束。然后调用
RunOtherExes
,这将对其他进程执行相同的操作。不幸的是,使用此方法仍然会导致闪烁。您可以发布项目的其余部分吗?由于保密协议,我不允许发布我正在处理的项目。我已经在我的问题tho中解释了大部分实现。感谢您的回复。我在没有WaitForExit的情况下尝试了相同的操作,但使用了一个timout,结果是一样的。UI线程上的任何等待都可能会导致问题,无论超时如何。如果不使用此方法运行Exe,可能会更改进程的优先级?不太清楚原因。如何执行方法
ProcessHelper.StartProcess
?(行的外观)请验证该进程未在
任务管理器
(进程选项卡)中启动。如果您愿意,我可以将一个示例上载到github。为什么不应该在任务管理器流程中启动该流程?无论如何,很难跟踪进程是否已启动,因为它几乎立即退出。我的错误是,您应该在
任务管理器
(进程选项卡)中看到它,但不应该在
应用程序
选项卡中看到它。现在我正在使用linux机器。稍后(大约5个小时后)我将上传一个工作示例。我会看看它是否适合用例并回复。你应得的赏金,虽然这个解决方案可能会被证明是有用的,但我想我最终将不得不伪装成应用程序,看看能做些什么。附言:我已经知道了
    private  void Button_Click(object sender, RoutedEventArgs e)
    {
        var ac = new Action(() => Application.Current.Dispatcher.Invoke(
            () =>
            {
                Thread.Sleep(50);
            }));
        Task.Factory.StartNew(() =>
        {

            //Provide path to epi
            string epiPath = @"c:/EPISUITE41";
            Level3ntCalculator cl = new Level3ntCalculator();
            var runner = new Calculators.Epi.Runners.ProcessRunner(epiPath, ac);


            runner.WriteXSmilesFiles("CCCCC1CCCCCCC1");
                    cl.Calculate(runner);

        });

    }
    public void RunCalculator(Calculator calculator)
    {
     //bla bla bla...
        new Thread(new ThreadStart(_action)).Start();
        p.Start();
     //...
    }