如果winform没有响应则重新启动程序

时间:2015-10-31 12:39:19

标签: c# winforms backgroundworker sendmessage watchdog

想想我们在我们的计划中有这个部分:

private void button1_Click(object sender, EventArgs e)
        {
            while (true) ;
        }

如果我们运行该程序,它将崩溃并说“#34; Not Responding"”。如何防止这种情况。我希望程序检查自己,如果没有响应,重启自己。

注意:
我们可以使用BackgroundWorker类。像这样:

private readonly BackgroundWorker worker;

    public Form1()
            {
                InitializeComponent();

                worker = new BackgroundWorker();
                worker.WorkerReportsProgress = true;
                worker.DoWork += Form1_Load;
                worker.ProgressChanged += button1_Click;
                worker.RunWorkerCompleted += worker_RunWorkerCompleted;
            }

但是该类中没有方法或属性或事件可以理解没有响应。 任何帮助将不胜感激。

<小时/> 编辑3:
我将BackgroundWorker与ThredTimer一起使用,并检查进程是否为#34; Not Responding&#34;。这不是关闭程序,而是开始一个新程序 当然这不是一个干净的代码,但它是一种方式。我仍然在寻找如何使用BeginInvoke作为@micky说或其他方式使这美丽。感谢你们所有人

    private readonly BackgroundWorker _Worker;

    public Form1()
    {
        InitializeComponent();

        _Worker = new BackgroundWorker();
        _Worker.DoWork += new DoWorkEventHandler(_Worker_DoWork);
        _Worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(_Worker_RunWorkerCompleted);
        _Worker.WorkerReportsProgress = true;
        _Worker.WorkerSupportsCancellation = true;
    }


    // BCW starts here.
    private void button1_Click(object sender, EventArgs e)
    {
        _Worker.RunWorkerAsync();
        while (true) ;
    }

    // ThreadTimer will run here. 
    void _Worker_DoWork(object sender, DoWorkEventArgs e)
    {

        if (_Worker.IsBusy == true)
        {
            if (_Worker.CancellationPending)
            {
                e.Cancel = true;
            }
            TimerCallback tmrCallBack = new TimerCallback(CheckStatusThreadHealth);
            System.Threading.Timer tmr = new System.Threading.Timer(tmrCallBack, null, 10000, 10000);
        }

    }        


    // This will call by ThreadTimer and check processes for not responding
    public void CheckStatusThreadHealth(object IsBusy)
    {
        Process application = null;

        foreach (var process in Process.GetProcesses())
        {
            if (process.ProcessName == "WindowsFormsApplication1")
            {
                application = process;
                break;
            }
        }

        if (!application.Responding)
        {
            // This should end BCW and go to _Worker_RunWorkerCompleted. But it didn't
            _Worker.CancelAsync();

            // This Restart program but did not close the last one.
            Application.Restart();
        }
    }

    // this should run when BCW has error or cancel, But never this happen
    void _Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {

        Application.Restart();
        return;
    }
}


<小时/> 答案:感谢Jason Williams 我使用看门狗程序作为解决方案并通过此link在两个程序之间进行通信代码更改为:

在主程序中

public partial class Form1 : Form
{
    // Use SendMessage API
    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern IntPtr SendMessage(IntPtr hwnd, uint Msg, IntPtr wParam, IntPtr lParam);

    // define a message
    private const int RF_TESTMESSAGE = 0xA123;

    // The timer will begin with the form
    public Form1()
    {
        InitializeComponent();

        var timer = new Timer();
        timer.Tick += new EventHandler(timer_Tick);
        timer.Interval = 10000; //10 seconds
        timer.Start();
    }

    //Timer look for a Watch Dog Program and send message to it
    void timer_Tick(object sender, EventArgs e)
    {
        try
        {
            Process WatchDogProccess = Process.GetProcessesByName("Watch Dog")[0];
            SendMessage(WatchDogProccess.MainWindowHandle, RF_TESTMESSAGE, IntPtr.Zero, IntPtr.Zero);
        }
        catch
        {
         //if Watch Dog is not running, will reach here
        }
    }

    // if we click this button we will got "Not Responding"
    private void button1_Click(object sender, EventArgs e)
    {
        while (true) ;
    }
}



在看门狗计划中

public partial class Form2 : Form
{
    //the message that have been define in main program
    private const int RF_TESTMESSAGE = 0xA123;

    //Recive the message
    protected override void WndProc(ref Message message)
    {
        if (message.Msg == RF_TESTMESSAGE)
        {
            // this mean the mian program run perfectly
        }
        else
        {
            //the main program is not responding

            //Main program's name and address
            string FileAddress = @"C:\Users\...\MainProgram.exe";
            string FileName = "MainProgram";

            // This will restart the main program
            RestartProgram(FileAddress, FileName);
        }
        base.WndProc(ref message);
    }

    // This will restart the main program
    public void RestartProgram(string FileAddress, string FileName)
    {
        //Find the Process
        Process[] prs = Process.GetProcessesByName(FileName);

        foreach (Process pr in prs)
        {
            if (!pr.Responding)
            {
                try
                {
                    pr.Kill();

                    //then to restart-
                    var process = new Process
                    {
                        StartInfo = new ProcessStartInfo
                        {
                            FileName = FileAddress
                        }
                    };
                    process.Start();
                }
                catch { }
            }
        }
    }
    public Form2()
    {
        InitializeComponent();

    }
}

}

1 个答案:

答案 0 :(得分:0)

您可以使用后台线程来解决此问题,该后台线程会以某种方式检测到ui线程没有响应。但是这个线程将如何重置/重启你的ui线程?这可能很难干净利落,因为你不得不将整个应用程序中的所有状态重置为已知的良好状态。

所以传统的做法是改为拥有一只独立的看门狗&#34;处理。这可以检测到您的应用程序已死,终止其进程然后运行新实例。

那么如何检测它已经死了?有许多聪明的方法可以做到这一点,但最简单和最可靠的方法是使用Windows窗体计时器定期(例如每秒一次)从您的应用程序向看门狗发送消息 - 如果您的ui线程忙,它将会不处理计时器事件,因此不会发送消息,几秒钟后,您的看门狗会确信它没有响应,并且能够重新启动它。