wpf 单例模式和异常处理 (原发布 csdn 2017-04-12 20:34:12)
程序员文章站
2023-11-09 16:37:04
第一次写博客,如有错误,请大家及时告知,本人立即改之。 如果您有好的想法或者建议,我随时与我联系。 如果发现代码有误导时,请与我联系,我立即改之。 好了不多说,直接贴代码。 一般的错误,使用下面三个就可以了。我不太赞同项目里面大量使用try{}catch{}(释放资源除外) 特殊情况下,此函数可检测 ......
第一次写博客,如有错误,请大家及时告知,本人立即改之。
如果您有好的想法或者建议,我随时与我联系。
如果发现代码有误导时,请与我联系,我立即改之。
好了不多说,直接贴代码。
一般的错误,使用下面三个就可以了。我不太赞同项目里面大量使用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); } }
好了,就写这么多吧。一般情况下,这些应该可以帮助我们解决大部分问题了。