界面异常捕获 ---在创建窗口句柄之前,不能在控件上调用Invoke或BeginInvoke

@坏坏Dong
在项目中遇到问题,在创建窗口句柄之前,不能在控件上调用Invoke或BeginInvoke的问题。在项目过程中,在Visual Studio中调试的时候,程序在运行过程中经常有这个错误,整个界面异常。且出错时间无规律,有时候几天没有错误,有时候运行频繁报错;且本界面运行的时候,会占用到CPU90%以上的资源,造成有时候界面很卡顿。
程序员经常说“「我爱你」三个字,讲出来只要三秒钟,解释要三小时,证明却要一辈子。「Bug」三个字母,发现需要三秒,找到需要三小时,Debug却要一辈子。”。就算是资深的程序员也会写出Bug,但Bug并不可怕,重要的是在Bug发生的时候迅速定位Bug。
在这里插入图片描述
和师兄请教问题的解决办法:
首先,我在主界面的线程和相关方法中在代码中加了try{}catch{}异常捕获,但是没有奏效;发现界面运行什么都不做,不执行任何操作,就会中断抛出异常,于是又尝试了以下的措施:

1.粗暴的在程序入口处添加异常捕捉

把这种异常捕获方法加到代码的方法中,可以捕捉出错的位置

try
{

}
catch (Exception ex)
{
   MessageBox.Show("位置:" + "[" + ex.Source + "]" +  "\r\n" + ex.StackTrace +  "\r\n" 
                   + "信息:" + "[" + ex.GetType() + "]" + ex.Message, "ExceptionInfo");
}
//说明
//ex.Source      获取导致错误的应用对象的名称
//ex.StackTrace  异常堆栈,获取调用堆栈上的字符串表示形式
//ex.GetType()     获取错误的类型

在这里插入图片描述
捕获错误:
位置:[Separator]在 xxxx(定位到报错的函数位置)
显示错误的地方的详细信息(工程,目录,某个.cs代码 以及行号)
信息:获取错误类型并提示中文错误信息

2.全局异常捕获,捕获整个程序的异常

在program程序的入口处设置try……Catch,捕获异常
异常是通过Throw命令抛出,一路从抛出的模块里上抛,如果中途没有被try…catch…抓住的话就会一直抛到CLR(公共语言运行时)。如果用栈来描述这个过程的话,那就是异常会从栈的栈顶一路下沉,直到中途被try…catch…抓住或者直至沉到栈底,被CLR接住。CLR接收到异常之后的处理方式非常的简单粗暴——直接报错,然后关闭程序

try
{
   Application.EnableVisualStyles();
   Application.SetCompatibleTextRenderingDefault(false);
   Application.Run(new Form1());
}
catch (Exception ex)
{
   MessageBox.Show("位置:" + "[" + ex.Source + "]" +  "\r\n" + ex.StackTrace +  "\r\n"
                   + "信息:" + "[" + ex.GetType() + "]" + ex.Message, "ExceptionInfo");
}

全局异常捕获一下。整个程序的异常一下子捕获,不用一个一个加了,这种方法也不知道能不能捕获到子线程中的异常

3.事件监听 Application.ThreadException

Application类负责控制整个Windows 程序的运行, 用到一个Application类的一个事件:ThreadException

static void Main()
{
    AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandleException);
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Application.Run(new Form1());
}
private static void CurrentDomain_UnhandleException(object sender,UnhandledExceptionEventArgs e)
{
    Exception ex = e.Exception;
    MessageBox.Show(string.Format("捕获到未处理异常:{0}\r\n异常信息:{1}\r\n异常堆栈:{2}", ex.GetType(), ex.Message, ex.StackTrace));
}

结果:失败了

4.子线程异常捕获 AppDomain.CurrentDomain.UnhandledException

可以通过监听Application.ThreadException事件来捕获程序异常,但这个Application.ThreadException事件只能捕获程序主线程上发生的异常。如果你用到了多线程,而且在子线程中发生了异常,不会触发Application.ThreadException事件的。如果要监听子线程的异常,我们就需要再注册一个事件:AppDomain.CurrentDomain.UnhandledException这个事件是在当前程序域内发生未处理异常时才会发生(如果没有监听Application.ThreadException事件的话,主线程异常最终也会触发这个事件)

static class Program
{
    /// <summary>
    /// 应用程序的主入口点。
    /// </summary>
    [STAThread]
    static void Main()
    {
        //处理UI线程异常
        Application.ThreadException += Application_ThreadException;
        //处理非UI线程异常
        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));
    }
     
    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事件有一个事件参数叫UnhandledExceptionEventArgs e,它有一个bool类型的IsTerminating属性。这个属性指示了公共语言运行时(CLR)会不会因为本次异常而退出。如果这个属性是true的话,那么我们可以称这个错误是不可挽回的,就算我们监听到了这个事件,在这个事件的代码执行结束后,整个程序还是会崩溃退出的(因为我在VS里,所以被VS捕捉到了。)

用这种方法捕捉到异常了,
在这里插入图片描述
参考学习网址:
https://www.cnblogs.com/tomahawk/articles/5993874.html
https://www.cnblogs.com/wangshenhe/archive/2012/11/14/2769605.html

最后:
在Windows程序里,如果同时监听了Application.ThreadException事件和AppDomain.CurrentDomain.UnhandledException事件的话,则异常优先被Application.ThreadException事件捕获。但Application.ThreadException事件只能监听程序主线程抛出的异常。

扫描二维码关注公众号,回复: 10861467 查看本文章
发布了18 篇原创文章 · 获赞 0 · 访问量 233

猜你喜欢

转载自blog.csdn.net/qq_39217004/article/details/105280726