如果 winform 没有响应,请重新启动程序
restart program if winform is not responding
认为我们的程序中有这部分:
private void button1_Click(object sender, EventArgs e)
{
while (true) ;
}
如果我们 运行 程序会崩溃并显示 "Not Responding"。如何防止这种情况。我希望程序自行检查,如果它没有响应,请自行重启。
注:
我们可以使用 BackgroundWorker class。像这样:
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;
}
但是 class 中没有方法或 属性 或事件来理解不响应。
任何帮助将不胜感激。
编辑 3:
我将 BackgroundWorker 与 ThredTimer 一起使用,并检查进程是否为 "Not Responding"。这不会关闭程序,而是启动一个新程序。
当然这不是干净的代码,但它是一种方式。我仍在寻找如何使用 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();
}
}
}
您可以使用后台线程解决此问题,该线程以某种方式检测到 ui 线程没有响应。但是这个线程如何 reset/restart 你的 ui 线程?这可能很难干净地完成,因为您将不得不以某种方式将整个应用程序的所有状态重置为已知的良好状态。
所以传统的方法是有一个单独的 "watch dog" 过程。这可以检测到您的应用已死,终止其进程,然后 运行 一个新实例。
那么如何检测死机呢?有许多聪明的方法可以做到这一点,但最简单和最可靠的是使用 Windows 表单计时器定期(例如每秒一次)从您的应用程序向看门狗发送消息 - 如果您的 ui 线程很忙,它不会处理定时器事件,因此不会发送消息,几秒钟后你的看门狗会确信它没有响应,并能够重新启动它。
认为我们的程序中有这部分:
private void button1_Click(object sender, EventArgs e)
{
while (true) ;
}
如果我们 运行 程序会崩溃并显示 "Not Responding"。如何防止这种情况。我希望程序自行检查,如果它没有响应,请自行重启。
注:
我们可以使用 BackgroundWorker class。像这样:
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;
}
但是 class 中没有方法或 属性 或事件来理解不响应。
任何帮助将不胜感激。
编辑 3:
我将 BackgroundWorker 与 ThredTimer 一起使用,并检查进程是否为 "Not Responding"。这不会关闭程序,而是启动一个新程序。
当然这不是干净的代码,但它是一种方式。我仍在寻找如何使用 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();
}
}
}
您可以使用后台线程解决此问题,该线程以某种方式检测到 ui 线程没有响应。但是这个线程如何 reset/restart 你的 ui 线程?这可能很难干净地完成,因为您将不得不以某种方式将整个应用程序的所有状态重置为已知的良好状态。
所以传统的方法是有一个单独的 "watch dog" 过程。这可以检测到您的应用已死,终止其进程,然后 运行 一个新实例。
那么如何检测死机呢?有许多聪明的方法可以做到这一点,但最简单和最可靠的是使用 Windows 表单计时器定期(例如每秒一次)从您的应用程序向看门狗发送消息 - 如果您的 ui 线程很忙,它不会处理定时器事件,因此不会发送消息,几秒钟后你的看门狗会确信它没有响应,并能够重新启动它。