From 79e7bc73ede29dfd2d63d34505f951909b428cab Mon Sep 17 00:00:00 2001 From: pointfeev Date: Fri, 25 Mar 2022 14:21:03 -0400 Subject: [PATCH] v3.4.1.0 - Added fatal exception handling - Vastly improved exception output formatting - Other minor visual changes and refactoring --- CreamInstaller/Components/CustomForm.cs | 4 +-- CreamInstaller/CreamInstaller.csproj | 4 +-- CreamInstaller/Forms/DialogForm.cs | 15 ++++++--- CreamInstaller/Forms/InstallForm.cs | 2 +- CreamInstaller/Forms/MainForm.cs | 2 +- CreamInstaller/Forms/SelectForm.cs | 4 +-- CreamInstaller/Paradox/ParadoxLauncher.cs | 8 ++--- CreamInstaller/Program.cs | 5 ++- CreamInstaller/Utility/ExceptionHandler.cs | 35 ++++++++++++++++----- CreamInstaller/Utility/HttpClientManager.cs | 2 +- 10 files changed, 54 insertions(+), 27 deletions(-) diff --git a/CreamInstaller/Components/CustomForm.cs b/CreamInstaller/Components/CustomForm.cs index 273de14..57ddb43 100644 --- a/CreamInstaller/Components/CustomForm.cs +++ b/CreamInstaller/Components/CustomForm.cs @@ -6,14 +6,14 @@ internal class CustomForm : Form { internal CustomForm() : base() => Icon = Properties.Resources.Icon; - internal CustomForm(IWin32Window owner) : this() => Owner = owner as Form; + internal CustomForm(IWin32Window owner) : this() => Owner = (owner as Form) ?? ActiveForm; protected override CreateParams CreateParams // Double buffering for all controls { get { CreateParams handleParam = base.CreateParams; - handleParam.ExStyle |= 0x02000000; // WS_EX_COMPOSITED + handleParam.ExStyle |= 0x02; // WS_EX_COMPOSITED return handleParam; } } diff --git a/CreamInstaller/CreamInstaller.csproj b/CreamInstaller/CreamInstaller.csproj index 5b89a59..a77f8d8 100644 --- a/CreamInstaller/CreamInstaller.csproj +++ b/CreamInstaller/CreamInstaller.csproj @@ -5,7 +5,7 @@ True Resources\ini.ico true - 3.4.0.5 + 3.4.1.0 Resources\ini.ico LICENSE 2021, pointfeev (https://github.com/pointfeev) @@ -36,7 +36,7 @@ True - + diff --git a/CreamInstaller/Forms/DialogForm.cs b/CreamInstaller/Forms/DialogForm.cs index 4ce0447..6767087 100644 --- a/CreamInstaller/Forms/DialogForm.cs +++ b/CreamInstaller/Forms/DialogForm.cs @@ -10,10 +10,8 @@ internal partial class DialogForm : CustomForm { internal DialogForm(IWin32Window owner) : base(owner) => InitializeComponent(); - internal DialogResult Show(Icon descriptionIcon, string descriptionText, string acceptButtonText, string cancelButtonText = null, Icon customFormIcon = null) + internal DialogResult Show(Icon descriptionIcon, string descriptionText, string acceptButtonText, string cancelButtonText = null, string customFormText = null, Icon customFormIcon = null) { - if (customFormIcon is not null) - Icon = customFormIcon; if (descriptionIcon is null) descriptionIcon = Icon; icon.Image = descriptionIcon.ToBitmap(); @@ -25,8 +23,15 @@ internal partial class DialogForm : CustomForm cancelButton.Visible = false; } else cancelButton.Text = cancelButtonText; - OnResize(null, null); - Resize += OnResize; + if (customFormText is not null) + Text = customFormText; + else + { + OnResize(null, null); + Resize += OnResize; + } + if (customFormIcon is not null) + Icon = customFormIcon; return ShowDialog(); } diff --git a/CreamInstaller/Forms/InstallForm.cs b/CreamInstaller/Forms/InstallForm.cs index 2258d89..d980c29 100644 --- a/CreamInstaller/Forms/InstallForm.cs +++ b/CreamInstaller/Forms/InstallForm.cs @@ -400,7 +400,7 @@ internal partial class InstallForm : CustomForm } catch (Exception e) { - if (ExceptionHandler.OutputException(e)) goto retry; + if (e.HandleException(form: this)) goto retry; Close(); } } diff --git a/CreamInstaller/Forms/MainForm.cs b/CreamInstaller/Forms/MainForm.cs index e0f5864..20e8f31 100644 --- a/CreamInstaller/Forms/MainForm.cs +++ b/CreamInstaller/Forms/MainForm.cs @@ -144,7 +144,7 @@ internal partial class MainForm : CustomForm } catch (Exception e) { - if (ExceptionHandler.OutputException(e)) goto retry; + if (e.HandleException(form: this)) goto retry; Close(); } } diff --git a/CreamInstaller/Forms/SelectForm.cs b/CreamInstaller/Forms/SelectForm.cs index 5fd6030..77a31da 100644 --- a/CreamInstaller/Forms/SelectForm.cs +++ b/CreamInstaller/Forms/SelectForm.cs @@ -706,7 +706,7 @@ internal partial class SelectForm : CustomForm } catch (Exception e) { - if (ExceptionHandler.OutputException(e)) goto retry; + if (e.HandleException(form: this)) goto retry; Close(); } } @@ -786,6 +786,6 @@ internal partial class SelectForm : CustomForm "\n\nBlocked game names:" + blockedGames + "\n\nBlocked game sub-directories:" + blockedDirectories + "\n\nBlocked game sub-directory exceptions (not blocked):" + blockedDirectoryExceptions, - "OK"); + "OK", customFormText: "Block Protected Games"); } } diff --git a/CreamInstaller/Paradox/ParadoxLauncher.cs b/CreamInstaller/Paradox/ParadoxLauncher.cs index 4dcc078..165f736 100644 --- a/CreamInstaller/Paradox/ParadoxLauncher.cs +++ b/CreamInstaller/Paradox/ParadoxLauncher.cs @@ -55,7 +55,7 @@ internal static class ParadoxLauncher return dialogForm.Show(SystemIcons.Warning, $"WARNING: There are no installed games with DLC that can be added to the Paradox Launcher!" + "\n\nInstalling CreamAPI/ScreamAPI for the Paradox Launcher is pointless, since no DLC will be added to the configuration!", - "Ignore", "Cancel") != DialogResult.OK; + "Ignore", "Cancel", customFormText: "Paradox Launcher") != DialogResult.OK; } } return false; @@ -131,12 +131,12 @@ internal static class ParadoxLauncher } if (neededRepair) { - if (form is not InstallForm) dialogForm.Show(form.Icon, "Paradox Launcher successfully repaired!", "OK"); + if (form is not InstallForm) dialogForm.Show(form.Icon, "Paradox Launcher successfully repaired!", "OK", customFormText: "Paradox Launcher"); return 1; } else { - if (form is not InstallForm) dialogForm.Show(SystemIcons.Information, "Paradox Launcher does not need to be repaired.", "OK"); + if (form is not InstallForm) dialogForm.Show(SystemIcons.Information, "Paradox Launcher does not need to be repaired.", "OK", customFormText: "Paradox Launcher"); return 0; } } @@ -144,7 +144,7 @@ internal static class ParadoxLauncher { if (form is not InstallForm) dialogForm.Show(SystemIcons.Error, "Paradox Launcher repair failed!" + "\n\nAn original Steamworks/Epic Online Services SDK file could not be found." - + "\nYou must reinstall Paradox Launcher to fix this issue.", "OK"); + + "\nYou must reinstall Paradox Launcher to fix this issue.", "OK", customFormText: "Paradox Launcher"); return -1; } } diff --git a/CreamInstaller/Program.cs b/CreamInstaller/Program.cs index 95150f6..19de3ab 100644 --- a/CreamInstaller/Program.cs +++ b/CreamInstaller/Program.cs @@ -87,6 +87,9 @@ internal static class Program Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.ApplicationExit += new(OnApplicationExit); + Application.ThreadException += new((s, e) => e.Exception?.HandleFatalException()); + Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException); + AppDomain.CurrentDomain.UnhandledException += new((s, e) => (e.ExceptionObject as Exception)?.HandleFatalException()); retry: try { @@ -96,7 +99,7 @@ internal static class Program } catch (Exception e) { - if (ExceptionHandler.OutputException(e)) goto retry; + if (e.HandleException()) goto retry; Application.Exit(); return; } diff --git a/CreamInstaller/Utility/ExceptionHandler.cs b/CreamInstaller/Utility/ExceptionHandler.cs index 6f923fe..ce8bc2a 100644 --- a/CreamInstaller/Utility/ExceptionHandler.cs +++ b/CreamInstaller/Utility/ExceptionHandler.cs @@ -1,15 +1,15 @@ using System; +using System.Drawing; using System.Windows.Forms; namespace CreamInstaller.Utility; internal static class ExceptionHandler { - internal static bool OutputException(Exception e) + internal static bool HandleException(this Exception e, Form form = null, string caption = "CreamInstaller encountered an exception", string acceptButtonText = "Retry", string cancelButtonText = "Cancel") { - while (e.InnerException is not null) + while (e.InnerException is not null) // we usually don't need the outer exceptions e = e.InnerException; - string output = ""; string[] stackTrace = e.StackTrace?.Split('\n'); if (stackTrace is not null && stackTrace.Length > 0) @@ -18,8 +18,19 @@ internal static class ExceptionHandler for (int i = 0; i < Math.Min(stackTrace.Length, 3); i++) { string line = stackTrace[i]; - if (line is not null) - output += "\n " + line[line.IndexOf("at")..]; + int atNum = line.IndexOf("at "); + int inNum = line.IndexOf("in "); + int ciNum = line.LastIndexOf(@"CreamInstaller\"); + int lineNum = line.LastIndexOf(":line "); + if (line is not null && atNum != -1) + output += "\n " + (inNum != -1 ? line[atNum..(inNum - 1)] : line[atNum..]) + + (inNum != -1 ? ("\n " + + (ciNum != -1 ? ("in " + + (lineNum != -1 ? line[ciNum..lineNum] + + "\n on " + line[(lineNum + 1)..] + : line[ciNum..])) + : line[inNum..])) + : null); } } string[] messageLines = e.Message?.Split('\n'); @@ -27,16 +38,24 @@ internal static class ExceptionHandler { if (output.Length > 0) output += "\n\n"; - output += "MESSAGE\n"; for (int i = 0; i < messageLines.Length; i++) { string line = messageLines[i]; if (line is not null) - output += "\n " + messageLines[i]; + output += "\n " + line; } } - return MessageBox.Show(output, caption: "CreamInstaller encountered an exception", buttons: MessageBoxButtons.RetryCancel, icon: MessageBoxIcon.Error) == DialogResult.Retry; + using DialogForm dialogForm = new(form ?? Form.ActiveForm); + return dialogForm.Show(SystemIcons.Error, output, acceptButtonText, cancelButtonText, customFormText: caption) == DialogResult.OK; + } + + internal static void HandleFatalException(this Exception e) + { + bool? restart = e?.HandleException(caption: "CreamInstaller encountered a fatal exception", acceptButtonText: "Restart"); + if (restart.HasValue && restart.Value) + Application.Restart(); + Application.Exit(); } } diff --git a/CreamInstaller/Utility/HttpClientManager.cs b/CreamInstaller/Utility/HttpClientManager.cs index 0a9e6c8..3ec3b36 100644 --- a/CreamInstaller/Utility/HttpClientManager.cs +++ b/CreamInstaller/Utility/HttpClientManager.cs @@ -55,5 +55,5 @@ internal static class HttpClientManager } } - internal static void Dispose() => HttpClient.Dispose(); + internal static void Dispose() => HttpClient?.Dispose(); }