天天看點

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 裡出現。詳細代碼如下:

C#WinForm程式異常退出的捕獲、繼續執行與自動重新開機
/// <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();
        }      
C#WinForm程式異常退出的捕獲、繼續執行與自動重新開機

我自己稍微修改了點邏輯,你都懂的。

C#WinForm程式異常退出的捕獲、繼續執行與自動重新開機
C#WinForm程式異常退出的捕獲、繼續執行與自動重新開機
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

 如果程式需要重新開機隻需要在捕獲的事件處理時啟動目前應用程式的代碼即可。參考如下:

C#WinForm程式異常退出的捕獲、繼續執行與自動重新開機
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);//必須等待,否則重新開機的程式還未啟動完成;根據情況調整等待時間
        }      
C#WinForm程式異常退出的捕獲、繼續執行與自動重新開機

 另外一種重新開機程序的方式:

//重新開機程式,需要時加上重新開機的參數
            System.Diagnostics.ProcessStartInfo cp = new System.Diagnostics.ProcessStartInfo();
            cp.FileName = Application.ExecutablePath;
            cp.Arguments = "cmd params";
            cp.UseShellExecute = true;
            System.Diagnostics.Process.Start(cp);      

完整代碼:

C#WinForm程式異常退出的捕獲、繼續執行與自動重新開機
C#WinForm程式異常退出的捕獲、繼續執行與自動重新開機
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);

        }
    }      

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();
        }      
//處理未捕獲的異常
            Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
            //處理UI線程異常
            Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
            //處理非UI線程異常
            AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);      
C#WinForm程式異常退出的捕獲、繼續執行與自動重新開機
/// <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();
        }      
C#WinForm程式異常退出的捕獲、繼續執行與自動重新開機
C#WinForm程式異常退出的捕獲、繼續執行與自動重新開機
C#WinForm程式異常退出的捕獲、繼續執行與自動重新開機
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);
            }
        }

    }      
C#WinForm程式異常退出的捕獲、繼續執行與自動重新開機
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);//必須等待,否則重新開機的程式還未啟動完成;根據情況調整等待時間
        }      
C#WinForm程式異常退出的捕獲、繼續執行與自動重新開機
//重新開機程式,需要時加上重新開機的參數
            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);

        }
    }      

繼續閱讀