using System; using System.IO; using System.Windows.Forms; #if !DEBUG using System.Diagnostics.CodeAnalysis; using System.Threading; #endif namespace NHSE.WinForms; internal static class Program { /// /// Directory where the executable is located. /// public static readonly string WorkingDirectory = Path.GetDirectoryName(Environment.ProcessPath) ?? ""; /// /// Settings file name. /// private const string ConfigFileName = "settings.json"; /// /// Full path to the settings file. /// private static string PathConfig => Path.Combine(WorkingDirectory, ConfigFileName); /// /// Application settings, loaded at startup. /// public static ApplicationSettings Settings { get; } /// /// Static constructor to load settings as early as possible. /// static Program() { #if !DEBUG Application.ThreadException += UIThreadException; Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException); AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; #endif Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Settings = ApplicationSettings.Load(PathConfig); Application.SetColorMode(Settings.DarkMode); } /// /// The main entry point for the application. /// [STAThread] private static void Main() => Application.Run(new Main()); public static void SaveSettings() => Settings.Save(PathConfig); #if !DEBUG private static void Error(string msg) => MessageBox.Show(msg, "NHSE Error", MessageBoxButtons.OK, MessageBoxIcon.Stop); private static void UIThreadException(object sender, ThreadExceptionEventArgs t) { DialogResult result; try { var e = t.Exception; string errorMessage = GetErrorMessage(e); Error(errorMessage); result = DialogResult.OK; } catch (Exception reportingException) { HandleReportingException(t.Exception, reportingException); result = DialogResult.Abort; } if (result == DialogResult.Abort) Application.Exit(); } private static string GetErrorMessage(Exception e) { Console.WriteLine(e); return e.StackTrace ?? e.Message; } private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) { var ex = e.ExceptionObject as Exception; try { if (IsCoreMissing(ex)) { Error("You have installed NHSE incorrectly. Please ensure you have unzipped all files before running."); } else if (ex is not null) { Error(GetErrorMessage(ex)); } else { Error("A fatal non-UI error has occurred in NHSE, and the details could not be displayed. Please report this to the author."); } } catch (Exception reportingException) { HandleReportingException(ex, reportingException); } } private static void HandleReportingException(Exception? ex, Exception reportingException) { try { EmergencyErrorLog(ex, reportingException); } catch { // Ignore. } if (reportingException is FileNotFoundException x && x.FileName?.StartsWith("NHSE.Core") == true) { Error("Could not locate NHSE.Core.dll. Make sure you're running NHSE together with its code library. Usually caused when all files are not extracted."); return; } try { Error("A fatal non-UI error has occurred in NHSE, and there was a problem displaying the details. Please report this to the author."); } finally { Application.Exit(); } } private static bool EmergencyErrorLog(Exception? originalException, Exception errorHandlingException) { try { var message = (originalException?.ToString() ?? "null first exception") + Environment.NewLine + errorHandlingException; File.WriteAllText($"NHSE_Error_Report {DateTime.Now:yyyyMMddHHmmss}.txt", message); } catch (Exception ex) { Console.WriteLine(errorHandlingException); Console.WriteLine(ex); return false; } return true; } private static bool IsCoreMissing([NotNullWhen(true)] Exception? ex) { return ex is FileNotFoundException { FileName: { } n } && n.Contains("NHSE.Core"); } #endif }