- Added fatal exception handling
- Vastly improved exception output formatting
- Other minor visual changes and refactoring
This commit is contained in:
pointfeev 2022-03-25 14:21:03 -04:00
parent 31621d8677
commit 79e7bc73ed
10 changed files with 54 additions and 27 deletions

View file

@ -6,14 +6,14 @@ internal class CustomForm : Form
{ {
internal CustomForm() : base() => Icon = Properties.Resources.Icon; 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 protected override CreateParams CreateParams // Double buffering for all controls
{ {
get get
{ {
CreateParams handleParam = base.CreateParams; CreateParams handleParam = base.CreateParams;
handleParam.ExStyle |= 0x02000000; // WS_EX_COMPOSITED handleParam.ExStyle |= 0x02; // WS_EX_COMPOSITED
return handleParam; return handleParam;
} }
} }

View file

@ -5,7 +5,7 @@
<UseWindowsForms>True</UseWindowsForms> <UseWindowsForms>True</UseWindowsForms>
<ApplicationIcon>Resources\ini.ico</ApplicationIcon> <ApplicationIcon>Resources\ini.ico</ApplicationIcon>
<IncludeAllContentForSelfExtract>true</IncludeAllContentForSelfExtract> <IncludeAllContentForSelfExtract>true</IncludeAllContentForSelfExtract>
<Version>3.4.0.5</Version> <Version>3.4.1.0</Version>
<PackageIcon>Resources\ini.ico</PackageIcon> <PackageIcon>Resources\ini.ico</PackageIcon>
<PackageLicenseFile>LICENSE</PackageLicenseFile> <PackageLicenseFile>LICENSE</PackageLicenseFile>
<Copyright>2021, pointfeev (https://github.com/pointfeev)</Copyright> <Copyright>2021, pointfeev (https://github.com/pointfeev)</Copyright>
@ -36,7 +36,7 @@
<CheckForOverflowUnderflow>True</CheckForOverflowUnderflow> <CheckForOverflowUnderflow>True</CheckForOverflowUnderflow>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Gameloop.Vdf" Version="0.6.2" /> <PackageReference Include="Gameloop.Vdf" Version="0.6.1" />
<PackageReference Include="HtmlAgilityPack" Version="1.11.42" /> <PackageReference Include="HtmlAgilityPack" Version="1.11.42" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="Onova" Version="2.6.2" /> <PackageReference Include="Onova" Version="2.6.2" />

View file

@ -10,10 +10,8 @@ internal partial class DialogForm : CustomForm
{ {
internal DialogForm(IWin32Window owner) : base(owner) => InitializeComponent(); 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) if (descriptionIcon is null)
descriptionIcon = Icon; descriptionIcon = Icon;
icon.Image = descriptionIcon.ToBitmap(); icon.Image = descriptionIcon.ToBitmap();
@ -25,8 +23,15 @@ internal partial class DialogForm : CustomForm
cancelButton.Visible = false; cancelButton.Visible = false;
} }
else cancelButton.Text = cancelButtonText; else cancelButton.Text = cancelButtonText;
OnResize(null, null); if (customFormText is not null)
Resize += OnResize; Text = customFormText;
else
{
OnResize(null, null);
Resize += OnResize;
}
if (customFormIcon is not null)
Icon = customFormIcon;
return ShowDialog(); return ShowDialog();
} }

View file

@ -400,7 +400,7 @@ internal partial class InstallForm : CustomForm
} }
catch (Exception e) catch (Exception e)
{ {
if (ExceptionHandler.OutputException(e)) goto retry; if (e.HandleException(form: this)) goto retry;
Close(); Close();
} }
} }

View file

@ -144,7 +144,7 @@ internal partial class MainForm : CustomForm
} }
catch (Exception e) catch (Exception e)
{ {
if (ExceptionHandler.OutputException(e)) goto retry; if (e.HandleException(form: this)) goto retry;
Close(); Close();
} }
} }

View file

@ -706,7 +706,7 @@ internal partial class SelectForm : CustomForm
} }
catch (Exception e) catch (Exception e)
{ {
if (ExceptionHandler.OutputException(e)) goto retry; if (e.HandleException(form: this)) goto retry;
Close(); Close();
} }
} }
@ -786,6 +786,6 @@ internal partial class SelectForm : CustomForm
"\n\nBlocked game names:" + blockedGames + "\n\nBlocked game names:" + blockedGames +
"\n\nBlocked game sub-directories:" + blockedDirectories + "\n\nBlocked game sub-directories:" + blockedDirectories +
"\n\nBlocked game sub-directory exceptions (not blocked):" + blockedDirectoryExceptions, "\n\nBlocked game sub-directory exceptions (not blocked):" + blockedDirectoryExceptions,
"OK"); "OK", customFormText: "Block Protected Games");
} }
} }

View file

@ -55,7 +55,7 @@ internal static class ParadoxLauncher
return dialogForm.Show(SystemIcons.Warning, return dialogForm.Show(SystemIcons.Warning,
$"WARNING: There are no installed games with DLC that can be added to the Paradox Launcher!" + $"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!", "\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; return false;
@ -131,12 +131,12 @@ internal static class ParadoxLauncher
} }
if (neededRepair) 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; return 1;
} }
else 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; return 0;
} }
} }
@ -144,7 +144,7 @@ internal static class ParadoxLauncher
{ {
if (form is not InstallForm) dialogForm.Show(SystemIcons.Error, "Paradox Launcher repair failed!" 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." + "\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; return -1;
} }
} }

View file

@ -87,6 +87,9 @@ internal static class Program
Application.EnableVisualStyles(); Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false); Application.SetCompatibleTextRenderingDefault(false);
Application.ApplicationExit += new(OnApplicationExit); 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: retry:
try try
{ {
@ -96,7 +99,7 @@ internal static class Program
} }
catch (Exception e) catch (Exception e)
{ {
if (ExceptionHandler.OutputException(e)) goto retry; if (e.HandleException()) goto retry;
Application.Exit(); Application.Exit();
return; return;
} }

View file

@ -1,15 +1,15 @@
using System; using System;
using System.Drawing;
using System.Windows.Forms; using System.Windows.Forms;
namespace CreamInstaller.Utility; namespace CreamInstaller.Utility;
internal static class ExceptionHandler 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; e = e.InnerException;
string output = ""; string output = "";
string[] stackTrace = e.StackTrace?.Split('\n'); string[] stackTrace = e.StackTrace?.Split('\n');
if (stackTrace is not null && stackTrace.Length > 0) 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++) for (int i = 0; i < Math.Min(stackTrace.Length, 3); i++)
{ {
string line = stackTrace[i]; string line = stackTrace[i];
if (line is not null) int atNum = line.IndexOf("at ");
output += "\n " + line[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'); string[] messageLines = e.Message?.Split('\n');
@ -27,16 +38,24 @@ internal static class ExceptionHandler
{ {
if (output.Length > 0) if (output.Length > 0)
output += "\n\n"; output += "\n\n";
output += "MESSAGE\n"; output += "MESSAGE\n";
for (int i = 0; i < messageLines.Length; i++) for (int i = 0; i < messageLines.Length; i++)
{ {
string line = messageLines[i]; string line = messageLines[i];
if (line is not null) 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();
} }
} }

View file

@ -55,5 +55,5 @@ internal static class HttpClientManager
} }
} }
internal static void Dispose() => HttpClient.Dispose(); internal static void Dispose() => HttpClient?.Dispose();
} }