// OpenTween - Client of Twitter // Copyright (c) 2022 kim_upsilon (@kim_upsilon) // All rights reserved. // // This file is part of OpenTween. // // This program is free software; you can redistribute it and/or modify it // under the terms of the GNU General public License as published by the Free // Software Foundation; either version 3 of the License, or (at your option) // any later version. // // This program is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General public License // for more details. // // You should have received a copy of the GNU General public License along // with this program. If not, see , or write to // the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, // Boston, MA 02110-1301, USA. #nullable enable using System; using System.Diagnostics; using System.Linq; using System.Net; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; using OpenTween.Connection; namespace OpenTween { public sealed class ErrorReportHandler : IDisposable { public bool IsDisposed { get; private set; } = false; public ErrorReportHandler() => this.RegisterHandlers(); private void RegisterHandlers() { TaskScheduler.UnobservedTaskException += this.TaskScheduler_UnobservedTaskException; AsyncTimer.UnhandledException += this.AsyncTimer_UnhandledException; Application.ThreadException += this.Application_ThreadException; AppDomain.CurrentDomain.UnhandledException += this.AppDomain_UnhandledException; } private void UnregisterHandlers() { TaskScheduler.UnobservedTaskException -= this.TaskScheduler_UnobservedTaskException; AsyncTimer.UnhandledException -= this.AsyncTimer_UnhandledException; Application.ThreadException -= this.Application_ThreadException; AppDomain.CurrentDomain.UnhandledException -= this.AppDomain_UnhandledException; } private void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e) { e.SetObserved(); this.OnUnhandledException(e.Exception.Flatten()); } private void AsyncTimer_UnhandledException(object sender, ThreadExceptionEventArgs e) => this.OnUnhandledException(e.Exception); private void Application_ThreadException(object sender, ThreadExceptionEventArgs e) => this.OnUnhandledException(e.Exception); private void AppDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) => this.OnUnhandledException((Exception)e.ExceptionObject); private void OnUnhandledException(Exception ex) { #if !DEBUG if (ErrorReportHandler.IsExceptionIgnorable(ex)) return; #endif if (MyCommon.ExceptionOut(ex)) Application.Exit(); } public void Dispose() { if (this.IsDisposed) return; this.IsDisposed = true; this.UnregisterHandlers(); } /// /// 無視しても問題のない既知の例外であれば true を返す /// public static bool IsExceptionIgnorable(Exception ex) { if (ex is AggregateException aggregated) return aggregated.InnerExceptions.All(x => IsExceptionIgnorable(x)); if (ex is WebException webEx) { // SSL/TLS のネゴシエーションに失敗した場合に発生する。なぜかキャッチできない例外 // https://osdn.net/ticket/browse.php?group_id=6526&tid=37432 if (webEx.Status == WebExceptionStatus.SecureChannelFailure) return true; } return false; } } }