zoukankan      html  css  js  c++  java
  • C#WinForm程序异常退出的捕获、继续执行与自动重启

    本文参考网上搜索的信息,并做了适当修改可以让捕捉到异常之后阻止程序退出。

    另给出了通过命令行自动重启的方法。

    如果一个线程里运行除以零的计算,如下面的代码

            private void button1_Click(object sender, EventArgs e)
            {
                System.Threading.Thread t = new System.Threading.Thread(() =>
                {
                    int a = 0;
                    int c = 10 / a;
                });
                t.Start();
            }

    将会导致程序自动结束,而且没有任何提示信息 但是如果是在主线程里运行这个代码,是会弹出异常信息对话框的

    请问如何在线程里也出现这个异常信息对话框.或者避免程序直接退出,忽略异常,继续往下执行呢?
     
    在WINFORM主线程捕获全部异常就行,如下代码:
                //处理未捕获的异常
                Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
                //处理UI线程异常
                Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
                //处理非UI线程异常
                AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
     最常出现的错误在 :UnhandledException 里出现。详细代码如下:
    复制代码
            /// <summary>
            /// 应用程序的主入口点。
            /// </summary>
            [STAThread]
            static void Main(string[] args) 
            {
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
    
                //处理未捕获的异常
                Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
                //处理UI线程异常
                Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
                //处理非UI线程异常
                AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
    
                Application.Run(new Form1(args));
                glExitApp = true;//标志应用程序可以退出
            }
    
            /// <summary>
            /// 是否退出应用程序
            /// </summary>
            static bool glExitApp = false;
    
            static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
            {
                LogHelper.Save("CurrentDomain_UnhandledException", LogType.Error);
                LogHelper.Save("IsTerminating : " + e.IsTerminating.ToString(), LogType.Error);
                LogHelper.Save(e.ExceptionObject.ToString());
    
                while (true)
                {//循环处理,否则应用程序将会退出
                    if (glExitApp) {//标志应用程序可以退出,否则程序退出后,进程仍然在运行
                        LogHelper.Save("ExitApp");
                        return; 
                    }
                    System.Threading.Thread.Sleep(2*1000);
                };
            }
            
            static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
            {
                LogHelper.Save("Application_ThreadException:" +
                    e.Exception.Message, LogType.Error);
                LogHelper.Save(e.Exception);
                //throw new NotImplementedException();
            }
    复制代码
    我自己稍微修改了点逻辑,你都懂的。
        static class Program
        {
            private static log4net.ILog _log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
            /// <summary>
            /// 是否退出应用程序
            /// </summary>
            static bool glExitApp = false;
    
    
            /// <summary>
            /// 应用程序的主入口点。
            /// </summary>
            [STAThread]
            static void Main()
            {
                _log.Info("程序启动");
    
                try
                {
                    //处理未捕获的异常
                    System.Windows.Forms.Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
                    System.Windows.Forms.Application.ThreadException += Application_ThreadException;
                    AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
    
                    Application.EnableVisualStyles();
                    Application.SetCompatibleTextRenderingDefault(false);
    
                    Application.Run(new WebManager());
                    glExitApp = true;
                }
                catch (Exception ex)
                {
                    _log.Error(ex);
                }
                _log.Info("程序关闭");
    
            }
    
    
            private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
            {
                _log.Error("CurrentDomain_UnhandledException ==== IsTerminating : " + e.IsTerminating.ToString());
                _log.Error("e.ExceptionObject : " + e.ExceptionObject);
                _log.Error(e);
                if (e.IsTerminating)
                {
                    Common.Globalparams.ShowMessageDialog("系统发生错误,请联系系统管理员,程序即将关闭。");
                    //循环处理,否则应用程序将会退出
                    if (glExitApp)
                    {
                        //标志应用程序可以退出,否则程序退出后,进程仍然在运行
                        _log.Error("====ExitApp");
                        return;
                    }
                    System.Threading.Thread.Sleep(2 * 1000);
                    _log.Error("====UnhandledException  While......");
    
                    Common.StartupHelper.CmdStartSelf();
                }
            }
    
            private static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
            {
                var ex = e.Exception;
                if (ex != null)
                {
                    _log.Error(ex);
                }
            }
    
        }
    View Code

     如果程序需要重启只需要在捕获的事件处理时启动当前应用程序的代码即可。参考如下:

    复制代码
    CmdStartCTIProc(Application.ExecutablePath, "cmd params");//放到捕获事件的处理代码后,重启程序,需要时加上重启的参数
    
            /// <summary>
            /// 在命令行窗口中执行
            /// </summary>
            /// <param name="sExePath"></param>
            /// <param name="sArguments"></param>
            static void CmdStartCTIProc(string sExePath, string sArguments)
            {
                Process p = new Process();
                p.StartInfo.FileName = "cmd.exe";
                p.StartInfo.UseShellExecute = false;
                p.StartInfo.RedirectStandardInput = true;
                p.StartInfo.RedirectStandardOutput = true;
                p.StartInfo.RedirectStandardError = true;
                p.StartInfo.CreateNoWindow = false;
                p.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
                p.Start();
                p.StandardInput.WriteLine(sExePath + " " + sArguments);
                p.StandardInput.WriteLine("exit");
                p.Close();
    
                System.Threading.Thread.Sleep(2000);//必须等待,否则重启的程序还未启动完成;根据情况调整等待时间
            }
    复制代码

     另外一种重启进程的方式:

                //重启程序,需要时加上重启的参数
                System.Diagnostics.ProcessStartInfo cp = new System.Diagnostics.ProcessStartInfo();
                cp.FileName = Application.ExecutablePath;
                cp.Arguments = "cmd params";
                cp.UseShellExecute = true;
                System.Diagnostics.Process.Start(cp);

    完整代码:

        public class StartupHelper
        {
            /// <summary>
            /// 在命令行窗口中执行指定程序。(可以包括程序本身)
            /// </summary>
            /// <param name="exePath"></param>
            /// <param name="sArguments"></param>
            public static void CmdStartApp(string exePath, string sArguments)
            {
                System.Diagnostics.Process p = new System.Diagnostics.Process();
                p.StartInfo.FileName = "cmd.exe";
                p.StartInfo.UseShellExecute = false;
                p.StartInfo.RedirectStandardInput = true;
                p.StartInfo.RedirectStandardOutput = true;
                p.StartInfo.RedirectStandardError = true;
                p.StartInfo.CreateNoWindow = false;
                p.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
                p.Start();
                p.StandardInput.WriteLine(exePath + " " + sArguments);
                p.StandardInput.WriteLine("exit");
                p.Close();
    
                System.Threading.Thread.Sleep(2000);//必须等待,否则重启的程序还未启动完成;根据情况调整等待时间
            }
    
            /// <summary>
            /// 启动程序自己(一般程序异常退出时调用)
            /// </summary>
            /// <param name="strArguments"></param>
            public static void CmdStartSelf(string strArguments = "")
            {
                //重启程序,需要时加上重启的参数
                System.Diagnostics.ProcessStartInfo cp = new System.Diagnostics.ProcessStartInfo();
                cp.FileName = System.Windows.Forms.Application.ExecutablePath;
                cp.Arguments = strArguments;
                cp.UseShellExecute = true;
                System.Diagnostics.Process.Start(cp);
    
            }
        }
    View Code

    看了觉得有用的朋友,如果您方便的话,可以顶一下。谢谢!

    出处:https://www.cnblogs.com/zaspring/archive/2013/04/16/3023927.html

  • 相关阅读:
    U盘分区 将一个u盘分为3个区
    InnoDB索引最通俗的解释
    Centos7 安全加固
    final/static
    Java继承,方法重写
    UnrealEngine4血溅效果
    UnrealEngine4第一人称射击游戏之触碰掉血与掉盔甲功能实现
    UnrealEngine4第一人称射击游戏UI
    String字符串
    构造方法
  • 原文地址:https://www.cnblogs.com/mq0036/p/12196722.html
Copyright © 2011-2022 走看看