第一次写博客,如有错误,请大家及时告知,本人立即改之。
如果您有好的想法或者建议,我随时与我联系。
如果发现代码有误导时,请与我联系,我立即改之。
好了不多说,直接贴代码。
一般的错误,使用下面三个就可以了。我不太赞同项目里面大量使用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); } }
好了,就写这么多吧。一般情况下,这些应该可以帮助我们解决大部分问题了。