.Net下的全局异常捕获问题
全局异常捕获主要目标并不是为了将异常处理掉防止程序崩溃。因为当错误被你的全局异常捕获器抓到的时候,已经证实了你程序中存在BUG。
一般而言,我们的全局异常捕获主要作用就是接收到异常之后进行异常的反馈。
大家都知道,异常是通过Throw命令抛出,一路从抛出的模块里上抛,如果中途没有被try...catch...抓住的话就会一直抛到CLR(公共语言运行时)。如果用栈来描述这个过程的话,那就是异常会从栈的栈顶一路下沉,直到中途被try...catch...抓住或者直至沉到栈底,被CLR接住。CLR接收到异常之后的处理方式非常的简单粗暴——直接报错,然后关闭程序。
只要我们在程序把异常抛给CLR之前,抢先把异常捕获,那就可以做到全局异常处理了。不过这个try...catch...就必须放在栈的最下方。程序运行时栈的最下方函数其实就是程序运行时第一个调用的函数——main()函数。
static void Main() { try { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new FrmMain()); } catch (Exception ex) { MessageBox.Show(string.Format("捕获到未处理异常:{0}\r\n异常信息:{1}\r\n异常堆栈:{2}", ex.GetType(), ex.Message, ex.StackTrace)); } }
下面我们运用其他来处理全局异常。
一、Application.ThreadException
假设还是之前的那个程序,我们将程序的Program.cs内容填入以下代码: static class Program { /// <summary> /// 应用程序的主入口点。 /// </summary> [STAThread] static void Main() { Application.ThreadException += Application_ThreadException; Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new FrmMain()); } static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e) { Exception ex = e.Exception; MessageBox.Show(string.Format("捕获到未处理异常:{0}\r\n异常信息:{1}\r\n异常堆栈:{2}", ex.GetType(), ex.Message, ex.StackTrace)); } }
二、子线程异常捕获AppDomain.CurrentDomain.UnhandledException
/// <summary> /// 应用程序的主入口点。 /// </summary> [STAThread] static void Main() { Application.ThreadException += Application_ThreadException; AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new FrmMain()); } static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) { Exception ex = e.ExceptionObject as Exception; MessageBox.Show(string.Format("捕获到未处理异常:{0}\r\n异常信息:{1}\r\n异常堆栈:{2}\r\nCLR即将退出:{3}", ex.GetType(), ex.Message, ex.StackTrace, e.IsTerminating)); }
三、WPF的异常捕获
public App() { this.Startup += new StartupEventHandler(App_Startup); this.DispatcherUnhandledException += new System.Windows.Threading.DispatcherUnhandledExceptionEventHandler(App_DispatcherUnhandledException);//UI线程的异常 AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);//非UI线程的异常 System.Threading.Tasks.TaskScheduler.UnobservedTaskException += App_UnobservedTaskException;//异步线程的异常 } void App_Startup(object sender, StartupEventArgs e) { bool ret; mutex = new System.Threading.Mutex(true, "WpfMuerterrrterterttex", out ret); if (!ret) { MessageBox.Show("课堂已经启动!"); Environment.Exit(0); } } void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) { if (e.ExceptionObject is System.Exception) { } } void App_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e) { e.Handled = true; } void App_UnobservedTaskException(object obj, System.Threading.Tasks.UnobservedTaskExceptionEventArgs e) { } int MyExceptionfilter(ref long a) { MessageBox.Show(a.ToString()); return 0; }
在此处理未处理的异常:
/// <summary>
/// App.xaml 的交互逻辑
/// </summary>
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
//注册Application_Error
this.DispatcherUnhandledException += new DispatcherUnhandledExceptionEventHandler(App_DispatcherUnhandledException);
}
//异常处理逻辑
void App_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
//处理完后,我们需要将Handler=true表示已此异常已处理过
MessageBox.Show("程序执行时遇到未处理异常,即将关闭!\n错误信息:"+e.Exception.Message);
Environment.Exit(0);
e.Handled = true;
}
}
四、公共语言未能捕获的异常
引入API
public delegate int CallBack(ref long a); CallBack mycall; [System.Runtime.InteropServices.DllImport("kernel32")] private static extern Int32 SetUnhandledExceptionFilter(CallBack cb); [System.Runtime.InteropServices.DllImport("user32.dll")] public static extern int GetWindowText(IntPtr hWnd, ref string strBuffer, int nSize);
WPF的App中
mycall = new CallBack(MyExceptionfilter); SetUnhandledExceptionFilter(mycall);
处理:
int MyExceptionfilter(ref long a) { MessageBox.Show(a.ToString()); return 0; }