• wpf 单例模式和异常处理 (原发布 csdn 2017-04-12 20:34:12)


    第一次写博客,如有错误,请大家及时告知,本人立即改之。

    如果您有好的想法或者建议,我随时与我联系。

    如果发现代码有误导时,请与我联系,我立即改之。

    好了不多说,直接贴代码。

    一般的错误,使用下面三个就可以了。我不太赞同项目里面大量使用try{}catch{}(释放资源除外)

    // 设置UI线程发生异常时处理函数
    System.Windows.Application.Current.DispatcherUnhandledException += App_DispatcherUnhandledException;
    
    // 设置非UI线程发生异常时处理函数
    AppDomain.CurrentDomain.UnhandledException += App_CurrentDomainUnhandledException;
    
    // 设置托管代码异步线程发生异常时处理函数
    TaskScheduler.UnobservedTaskException += EventHandler_UnobservedTaskException;
    

    特殊情况下,此函数可检测到c++封装的dll(不是百分之百可以检测到)

    public delegate int CallBack(ref long a);
    CallBack myCall;
    
    [DllImport("kernel32")]
    private static extern Int32 SetUnhandledExceptionFilter(CallBack cb);
        
    // 设置非托管代码发生异常时处理函数
    callBack = new CallBack(ExceptionFilter);
    SetUnhandledExceptionFilter(callBack);
    

    此函数可让程序"美化"结束。

    完整代码:

    public partial class App : Application
    {
            [System.Runtime.InteropServices.DllImport("kernel32")]
            private static extern Int32 SetUnhandledExceptionFilter(CallBack cb);
    
            private delegate int CallBack(ref long a);
    
            private CallBack callBack;
    
            private System.Threading.Mutex mutex;
    
            public App()
            {
                Startup += new System.Windows.StartupEventHandler(App_Startup);
            }
    
            private void App_Startup(object sender, System.Windows.StartupEventArgs e)
            {
                mutex = new System.Threading.Mutex(true, $"{System.Reflection.Assembly.GetEntryAssembly().GetName().Name} - 8F6F0AC4-B9A1-45fd-A8CF-72F04E6BDE8F", out bool ret);
                if (!ret)
                {
                    System.Windows.MessageBox.Show($"{System.Reflection.Assembly.GetEntryAssembly().GetName().Name} has already started up.",
                        "App_Startup",
                        System.Windows.MessageBoxButton.OK,
                        System.Windows.MessageBoxImage.Information);
                    Environment.Exit(0);
                    return;
                }
    
    		   Log4net.Init(typeof(MainWindow));
    		   
                // 设置UI线程发生异常时处理函数
                System.Windows.Application.Current.DispatcherUnhandledException += App_DispatcherUnhandledException;
    
                // 设置非UI线程发生异常时处理函数
                AppDomain.CurrentDomain.UnhandledException += App_CurrentDomainUnhandledException;
    
                // 设置非托管代码发生异常时处理函数
                callBack = new CallBack(ExceptionFilter);
                SetUnhandledExceptionFilter(callBack);
    
                // 设置托管代码异步线程发生异常时处理函数
                TaskScheduler.UnobservedTaskException += EventHandler_UnobservedTaskException;
            }
    
        void App_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
        {
            Log4net.gLogger.Error("--<App_DispatcherUnhandledException>--" + e.Exception.ToString());
            System.Windows.Forms.MessageBox.Show(e.Exception.ToString(),
                "Error",
                System.Windows.Forms.MessageBoxButtons.OK,
                System.Windows.Forms.MessageBoxIcon.Error);
    
            e.Handled = true;
        }
    
        void App_CurrentDomainUnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            Log4net.gLogger.Fatal("--<App_CurrentDomainUnhandledException>--" + e.ExceptionObject.ToString());
            if (System.Windows.Forms.DialogResult.Yes
                == System.Windows.Forms.MessageBox.Show(
                "软件出现不可恢复错误,即将关闭。是否选择生成Dump文件以供开发人员分析问题?",
                "Error", System.Windows.Forms.MessageBoxButtons.YesNo,
                System.Windows.Forms.MessageBoxIcon.Error, System.Windows.Forms.MessageBoxDefaultButton.Button1))
            {
                WriteDump();
            }
            Environment.Exit(0);
        }
    
        private int ExceptionFilter(ref long a)
        {
            Log4net.gLogger.Fatal("--<ExceptionFilter>--" + Environment.StackTrace);
            WriteDump();
            return 1;
        }
    
        private void WriteDump()
        {
            Dump.WriteDumpFile();
        }
    }
    

    对于一些问题,我们可以通过日志文件记录(我目前使用Log4net)。有时候日志不能完全帮助我们找到问题所在,这时dmp文件就可以帮助到我们。

    internal class DumpWriter
    {
        public enum MiniDumpType
        {
            None = 0x00010000,
            Normal = 0x00000000,
            WithDataSegs = 0x00000001,
            WithFullMemory = 0x00000002,
            WithHandleData = 0x00000004,
            FilterMemory = 0x00000008,
            ScanMemory = 0x00000010,
            WithUnloadedModules = 0x00000020,
            WithIndirectlyReferencedMemory = 0x00000040,
            FilterModulePaths = 0x00000080,
            WithProcessThreadData = 0x00000100,
            WithPrivateReadWriteMemory = 0x00000200,
            WithoutOptionalData = 0x00000400,
            WithFullMemoryInfo = 0x00000800,
            WithThreadInfo = 0x00001000,
            WithCodeSegs = 0x00002000
        }
    
        [DllImport("DbgHelp.dll")]
        private static extern bool MiniDumpWriteDump(
            IntPtr hProcess,
            Int32 processId,
            IntPtr fileHandle,
            MiniDumpType dumpType,
            ref MiniDumpExceptionInformation excepInfo,
            IntPtr userInfo,
            IntPtr extInfo);
    
        [DllImport("DbgHelp.dll")]
        private static extern bool MiniDumpWriteDump(
            IntPtr hProcess,
            Int32 processId,
            IntPtr fileHandle,
            MiniDumpType dumpType,
            IntPtr excepParam,
            IntPtr userInfo,
            IntPtr extInfo);
    
        [StructLayout(LayoutKind.Sequential, Pack = 4)]// Pack=4 is important! So it works also for x64!
        private struct MiniDumpExceptionInformation
        {
            public uint ThreadId;
            public IntPtr ExceptionPointers;
            [MarshalAs(UnmanagedType.Bool)]
            public bool ClientPointers;
        }
    
        [DllImport("kernel32.dll")]
        private static extern uint GetCurrentThreadId();
    
        private bool WriteDump(String dmpPath, MiniDumpType dmpType)
        {
            using (FileStream stream = new FileStream(dmpPath, FileMode.Create))
            {
                //取得进程信息
                Process process = Process.GetCurrentProcess();
    
                MiniDumpExceptionInformation mei = new MiniDumpExceptionInformation();
                mei.ThreadId = GetCurrentThreadId();
                mei.ExceptionPointers = Marshal.GetExceptionPointers();
                mei.ClientPointers = true;
    
                bool res = false;
    
                //如果不使用MiniDumpWriteDump重载函数
                //当mei.ExceptioonPointers == IntPtr.Zero => 无法保存dmp文件
                //且当mei.ClientPointers == false时程序直接崩溃(mei.ClientPointers == true程序不崩溃)
                //
                //以上测试信息硬件环境 cpu Pentium(R) Dual-Core CPU T4200 @ 2.00GHz
                //                 vs2013update5
                //在公司服务器上测试(64位系统、vs2013)不会出现上述情况
                /*res = MiniDumpWriteDump(
                    process.Handle,
                    process.Id,
                    stream.SafeFileHandle.DangerousGetHandle(),
                    dmpType,
                    ref mei,
                    IntPtr.Zero,
                    IntPtr.Zero);*/
    
                if (mei.ExceptionPointers == IntPtr.Zero)
                {
                    res = MiniDumpWriteDump(
                        process.Handle,
                        process.Id,
                        stream.SafeFileHandle.DangerousGetHandle(),
                        dmpType,
                        IntPtr.Zero,
                        IntPtr.Zero,
                        IntPtr.Zero);
                }
                else
                {
                    res = MiniDumpWriteDump(
                        process.Handle,
                        process.Id,
                        stream.SafeFileHandle.DangerousGetHandle(),
                        dmpType,
                        ref mei,
                        IntPtr.Zero,
                        IntPtr.Zero);
                }
                return res;
            }
        }
    
        public DumpWriter()
        {
            FilePath = Environment.CurrentDirectory + @"Dump";
            if (!Directory.Exists(FilePath))
                Directory.CreateDirectory(FilePath);
        }
    
        /// <summary>
        /// 保存dmp文件路径
        /// </summary>
        public string FilePath { get; protected set; }
        /// <summary>
        /// 保存dmp文件名称(包括路径)
        /// </summary>
        public string FileName { get; protected set; }
        /// <summary>
        /// 写dmp文件
        /// </summary>
        /// <param name="dmpType">参数,不同参数保存内容不一样</param>
        /// <returns></returns>
        public bool WriteDumpFile(MiniDumpType dmpType)
        {
            FileName = string.Format("{0}\{1}_{2}.dmp",
                FilePath,
                DateTime.Now.ToString("yyyy-MM-dd-HH-mm-ss-fff"),
                Process.GetCurrentProcess().ProcessName);
            return WriteDump(FileName, dmpType);
        }
    
    }
    

    好了,就写这么多吧。一般情况下,这些应该可以帮助我们解决大部分问题了。

  • 相关阅读:
    CDN实现原理
    openstack测试集群扩容配置
    ELK5.2.2自动化部署脚本
    Python多线程
    Python反射
    OpenStack快照分析:(三)从磁盘启动云主机离线(在线)快照分析
    OpenStack快照分析:(二)从镜像启动的云主机离在线快照分析
    OpenStack快照分析:(一)从镜像启动的云主机离线快照分析
    Python元编程
    Python源码阅读:对象
  • 原文地址:https://www.cnblogs.com/njit-77/p/11468942.html
Copyright © 2020-2023  润新知