using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.ExceptionServices; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Windows; using System.Windows.Threading; using Tango.Logging; namespace Tango.Logging { /// /// Represents an optimized WPF global exception trapper. /// /// public class WpfGlobalExceptionTrapper : IGlobalExceptionTrapper { private DateTime _lastGlobalExceptionTime = DateTime.Now.AddMinutes(-1); private Application _app; /// /// Occurs when the global exception trapper has detected an unhandled exception. /// public event EventHandler ApplicationCrashed; /// /// Initializes the specified application. /// /// The application. public void Initialize(Application app) { _app = app; AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; app.Dispatcher.UnhandledException += Dispatcher_UnhandledException; Application.Current.DispatcherUnhandledException += Current_DispatcherUnhandledException; TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException; } /// /// Use only when need to simulate application crash! /// public void Disable() { AppDomain.CurrentDomain.UnhandledException -= CurrentDomain_UnhandledException; _app.Dispatcher.UnhandledException -= Dispatcher_UnhandledException; Application.Current.DispatcherUnhandledException -= Current_DispatcherUnhandledException; TaskScheduler.UnobservedTaskException -= TaskScheduler_UnobservedTaskException; } /// /// Handles the UnobservedTaskException event of the TaskScheduler control. /// /// The source of the event. /// The instance containing the event data. private void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e) { e.SetObserved(); OnApplicationCrash(e.Exception); } /// /// Handles the DispatcherUnhandledException event of the Current control. /// /// The source of the event. /// The instance containing the event data. private void Current_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e) { e.Handled = OnApplicationCrash(e.Exception); } /// /// Handles the UnhandledException event of the Dispatcher control. /// /// The source of the event. /// The instance containing the event data. private void Dispatcher_UnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e) { e.Handled = OnApplicationCrash(e.Exception); } /// /// Handles the UnhandledException event of the CurrentDomain control. /// /// The source of the event. /// The instance containing the event data. private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) { OnApplicationCrash(new Exception(e.ExceptionObject.ToStringSafe())); } /// /// Called when any unhandled application exception has occurred and write to log. /// /// The error. private bool OnApplicationCrash(Exception exception) { if (DateTime.Now < _lastGlobalExceptionTime.AddSeconds(1)) { _lastGlobalExceptionTime = DateTime.Now; return true; } _lastGlobalExceptionTime = DateTime.Now; ApplicationCrashedEventArgs e = new ApplicationCrashedEventArgs(exception); ApplicationCrashed?.Invoke(this, e); return e.TryRecover; } public Task GetLastApplicationCrashEventLog(int maxMinutes = 10) { return Task.Factory.StartNew(() => { MessageLogItem logItem = null; try { var applicationEvents = new EventLog("Application"); var events = applicationEvents.Entries.Cast().Where(x => x.EntryType == EventLogEntryType.Error && x.Source == ".NET Runtime" && x.TimeWritten > DateTime.Now.AddMinutes(-maxMinutes)).OrderByDescending(x => x.TimeWritten).ToList(); Regex reg = new Regex("Application: (.+)"); foreach (var ev in events) { Match match = reg.Match(ev.Message); if (match.Groups.Count > 1) { String exeName = match.Groups[1].Value; String assemblyName = Path.GetFileNameWithoutExtension(exeName); if (assemblyName == Assembly.GetEntryAssembly().GetName().Name) { logItem = new MessageLogItem(); logItem.Message = "Application terminated unexpectedly in the previous run!\n"; logItem.Message += "This crash report was retrieved from the windows event logs.\n"; logItem.Message += "---------------------------------------------------------------------------\n\n"; logItem.Message += ev.Message; logItem.TimeStamp = DateTime.Now; logItem.Category = LogCategory.Critical; break; } } } } catch { } return logItem; }); } } }