- 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(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;
}
}

View file

@ -5,7 +5,7 @@
<UseWindowsForms>True</UseWindowsForms>
<ApplicationIcon>Resources\ini.ico</ApplicationIcon>
<IncludeAllContentForSelfExtract>true</IncludeAllContentForSelfExtract>
<Version>3.4.0.5</Version>
<Version>3.4.1.0</Version>
<PackageIcon>Resources\ini.ico</PackageIcon>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<Copyright>2021, pointfeev (https://github.com/pointfeev)</Copyright>
@ -36,7 +36,7 @@
<CheckForOverflowUnderflow>True</CheckForOverflowUnderflow>
</PropertyGroup>
<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="Newtonsoft.Json" Version="13.0.1" />
<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 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();
}

View file

@ -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();
}
}

View file

@ -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();
}
}

View file

@ -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");
}
}

View file

@ -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;
}
}

View file

@ -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;
}

View file

@ -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();
}
}

View file

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