From ba3e5b10c6237b5e2a624672e7473f897d9d6093 Mon Sep 17 00:00:00 2001 From: alcexhim Date: Tue, 30 Sep 2014 15:56:03 -0400 Subject: [PATCH] Added crash handling in various locations for a more user-friendly experience --- .../UniversalEditor.Bootstrapper/Program.cs | 24 +- .../Dialogs/CrashDialog.Designer.cs | 213 ++++++++++++++++++ .../Dialogs/CrashDialog.cs | 33 +++ .../Dialogs/CrashDialog.resx | 120 ++++++++++ ...ace.WindowsForms.DesktopApplication.csproj | 13 +- .../WindowsFormsEngine.cs | 13 ++ .../UniversalEditor.UserInterface/Engine.cs | 26 ++- 7 files changed, 436 insertions(+), 6 deletions(-) create mode 100644 CSharp/Engines/WindowsForms/Engines/UniversalEditor.UserInterface.WindowsForms.DesktopApplication/Dialogs/CrashDialog.Designer.cs create mode 100644 CSharp/Engines/WindowsForms/Engines/UniversalEditor.UserInterface.WindowsForms.DesktopApplication/Dialogs/CrashDialog.cs create mode 100644 CSharp/Engines/WindowsForms/Engines/UniversalEditor.UserInterface.WindowsForms.DesktopApplication/Dialogs/CrashDialog.resx diff --git a/CSharp/Applications/UniversalEditor.Bootstrapper/Program.cs b/CSharp/Applications/UniversalEditor.Bootstrapper/Program.cs index fb4afe4c..bd4a52be 100644 --- a/CSharp/Applications/UniversalEditor.Bootstrapper/Program.cs +++ b/CSharp/Applications/UniversalEditor.Bootstrapper/Program.cs @@ -14,11 +14,31 @@ namespace UniversalEditor.Bootstrapper [STAThread] static void Main() { - if (!Engine.Execute()) + try { - MessageBox.Show("No engines are available to launch this application.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + // why do we do this? because, if the class was static, it tries to load the 'Engine' type + // from another library immediately... if it can't be found, it crashes. this way, if it + // can't be found, we can still catch it since it's loaded on-demand rather than + // immediately. + (new BootstrapperInstance()).Main(); + } + catch + { + MessageBox.Show("The file 'UniversalEditor.UserInterface.dll' is required for this software to run, but is either missing or corrupted. Please re-install the software and try again.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } } + + private class BootstrapperInstance + { + public void Main() + { + if (!Engine.Execute()) + { + MessageBox.Show("No engines are available to launch this application.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } + } + } } } diff --git a/CSharp/Engines/WindowsForms/Engines/UniversalEditor.UserInterface.WindowsForms.DesktopApplication/Dialogs/CrashDialog.Designer.cs b/CSharp/Engines/WindowsForms/Engines/UniversalEditor.UserInterface.WindowsForms.DesktopApplication/Dialogs/CrashDialog.Designer.cs new file mode 100644 index 00000000..b241a310 --- /dev/null +++ b/CSharp/Engines/WindowsForms/Engines/UniversalEditor.UserInterface.WindowsForms.DesktopApplication/Dialogs/CrashDialog.Designer.cs @@ -0,0 +1,213 @@ +namespace UniversalEditor.UserInterface.WindowsForms.Dialogs +{ + partial class CrashDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.cmdIgnore = new System.Windows.Forms.Button(); + this.cmdExit = new System.Windows.Forms.Button(); + this.label1 = new System.Windows.Forms.Label(); + this.txtType = new System.Windows.Forms.TextBox(); + this.txtSource = new System.Windows.Forms.TextBox(); + this.txtMessage = new System.Windows.Forms.TextBox(); + this.txtStackTrace = new System.Windows.Forms.TextBox(); + this.label2 = new System.Windows.Forms.Label(); + this.label3 = new System.Windows.Forms.Label(); + this.label4 = new System.Windows.Forms.Label(); + this.label5 = new System.Windows.Forms.Label(); + this.SuspendLayout(); + // + // cmdIgnore + // + this.cmdIgnore.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.cmdIgnore.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.cmdIgnore.Location = new System.Drawing.Point(240, 267); + this.cmdIgnore.Name = "cmdIgnore"; + this.cmdIgnore.Size = new System.Drawing.Size(75, 23); + this.cmdIgnore.TabIndex = 0; + this.cmdIgnore.Text = "&Ignore"; + this.cmdIgnore.UseVisualStyleBackColor = true; + // + // cmdExit + // + this.cmdExit.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.cmdExit.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.cmdExit.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.cmdExit.Location = new System.Drawing.Point(321, 267); + this.cmdExit.Name = "cmdExit"; + this.cmdExit.Size = new System.Drawing.Size(75, 23); + this.cmdExit.TabIndex = 0; + this.cmdExit.Text = "E&xit"; + this.cmdExit.UseVisualStyleBackColor = true; + // + // label1 + // + this.label1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.label1.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.label1.Location = new System.Drawing.Point(12, 9); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(384, 36); + this.label1.TabIndex = 1; + this.label1.Text = "The application has encountered a problem and may not be able to continue functio" + + "ning properly."; + // + // txtType + // + this.txtType.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.txtType.Location = new System.Drawing.Point(93, 59); + this.txtType.Name = "txtType"; + this.txtType.ReadOnly = true; + this.txtType.Size = new System.Drawing.Size(303, 20); + this.txtType.TabIndex = 2; + // + // txtSource + // + this.txtSource.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.txtSource.Location = new System.Drawing.Point(93, 85); + this.txtSource.Name = "txtSource"; + this.txtSource.ReadOnly = true; + this.txtSource.Size = new System.Drawing.Size(303, 20); + this.txtSource.TabIndex = 2; + // + // txtMessage + // + this.txtMessage.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.txtMessage.Location = new System.Drawing.Point(93, 111); + this.txtMessage.Multiline = true; + this.txtMessage.Name = "txtMessage"; + this.txtMessage.ReadOnly = true; + this.txtMessage.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; + this.txtMessage.Size = new System.Drawing.Size(303, 57); + this.txtMessage.TabIndex = 2; + // + // txtStackTrace + // + this.txtStackTrace.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.txtStackTrace.Location = new System.Drawing.Point(93, 174); + this.txtStackTrace.Multiline = true; + this.txtStackTrace.Name = "txtStackTrace"; + this.txtStackTrace.ReadOnly = true; + this.txtStackTrace.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; + this.txtStackTrace.Size = new System.Drawing.Size(303, 87); + this.txtStackTrace.TabIndex = 2; + // + // label2 + // + this.label2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.label2.AutoSize = true; + this.label2.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.label2.Location = new System.Drawing.Point(22, 62); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(34, 13); + this.label2.TabIndex = 1; + this.label2.Text = "Type:"; + // + // label3 + // + this.label3.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.label3.AutoSize = true; + this.label3.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.label3.Location = new System.Drawing.Point(22, 88); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(44, 13); + this.label3.TabIndex = 1; + this.label3.Text = "Source:"; + // + // label4 + // + this.label4.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.label4.AutoSize = true; + this.label4.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.label4.Location = new System.Drawing.Point(22, 114); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(53, 13); + this.label4.TabIndex = 1; + this.label4.Text = "&Message:"; + // + // label5 + // + this.label5.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.label5.AutoSize = true; + this.label5.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.label5.Location = new System.Drawing.Point(22, 177); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(65, 13); + this.label5.TabIndex = 1; + this.label5.Text = "&Stack trace:"; + // + // CrashDialog + // + this.AcceptButton = this.cmdIgnore; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(408, 302); + this.Controls.Add(this.txtStackTrace); + this.Controls.Add(this.txtMessage); + this.Controls.Add(this.txtSource); + this.Controls.Add(this.txtType); + this.Controls.Add(this.label5); + this.Controls.Add(this.label4); + this.Controls.Add(this.label3); + this.Controls.Add(this.label2); + this.Controls.Add(this.label1); + this.Controls.Add(this.cmdExit); + this.Controls.Add(this.cmdIgnore); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "CrashDialog"; + this.Text = "Error"; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Button cmdIgnore; + private System.Windows.Forms.Button cmdExit; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.TextBox txtType; + private System.Windows.Forms.TextBox txtSource; + private System.Windows.Forms.TextBox txtMessage; + private System.Windows.Forms.TextBox txtStackTrace; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.Label label5; + } +} \ No newline at end of file diff --git a/CSharp/Engines/WindowsForms/Engines/UniversalEditor.UserInterface.WindowsForms.DesktopApplication/Dialogs/CrashDialog.cs b/CSharp/Engines/WindowsForms/Engines/UniversalEditor.UserInterface.WindowsForms.DesktopApplication/Dialogs/CrashDialog.cs new file mode 100644 index 00000000..fc450312 --- /dev/null +++ b/CSharp/Engines/WindowsForms/Engines/UniversalEditor.UserInterface.WindowsForms.DesktopApplication/Dialogs/CrashDialog.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Windows.Forms; + +namespace UniversalEditor.UserInterface.WindowsForms.Dialogs +{ + public partial class CrashDialog : Form + { + public CrashDialog() + { + InitializeComponent(); + Font = SystemFonts.MenuFont; + } + + private Exception mvarException = null; + public Exception Exception { get { return mvarException; } set { mvarException = value; } } + + protected override void OnShown(EventArgs e) + { + base.OnShown(e); + + txtType.Text = mvarException.GetType().FullName; + txtMessage.Text = mvarException.Message; + txtSource.Text = mvarException.Source; + txtStackTrace.Text = mvarException.StackTrace; + } + } +} diff --git a/CSharp/Engines/WindowsForms/Engines/UniversalEditor.UserInterface.WindowsForms.DesktopApplication/Dialogs/CrashDialog.resx b/CSharp/Engines/WindowsForms/Engines/UniversalEditor.UserInterface.WindowsForms.DesktopApplication/Dialogs/CrashDialog.resx new file mode 100644 index 00000000..7080a7d1 --- /dev/null +++ b/CSharp/Engines/WindowsForms/Engines/UniversalEditor.UserInterface.WindowsForms.DesktopApplication/Dialogs/CrashDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/CSharp/Engines/WindowsForms/Engines/UniversalEditor.UserInterface.WindowsForms.DesktopApplication/UniversalEditor.UserInterface.WindowsForms.DesktopApplication.csproj b/CSharp/Engines/WindowsForms/Engines/UniversalEditor.UserInterface.WindowsForms.DesktopApplication/UniversalEditor.UserInterface.WindowsForms.DesktopApplication.csproj index 79522b95..194c0ee5 100644 --- a/CSharp/Engines/WindowsForms/Engines/UniversalEditor.UserInterface.WindowsForms.DesktopApplication/UniversalEditor.UserInterface.WindowsForms.DesktopApplication.csproj +++ b/CSharp/Engines/WindowsForms/Engines/UniversalEditor.UserInterface.WindowsForms.DesktopApplication/UniversalEditor.UserInterface.WindowsForms.DesktopApplication.csproj @@ -8,7 +8,7 @@ Library Properties UniversalEditor.UserInterface.WindowsForms - UniversalEditor.UserInterface.WindowsForms.DesktopApplication + UniversalEditor.Engines.WindowsForms v3.5 512 @@ -43,8 +43,10 @@ + + @@ -53,6 +55,12 @@ OutputWindow.cs + + Form + + + CrashDialog.cs + Form @@ -220,6 +228,9 @@ AboutDialog.cs + + CrashDialog.cs + ObjectModelBrowserPopup.cs diff --git a/CSharp/Engines/WindowsForms/Engines/UniversalEditor.UserInterface.WindowsForms.DesktopApplication/WindowsFormsEngine.cs b/CSharp/Engines/WindowsForms/Engines/UniversalEditor.UserInterface.WindowsForms.DesktopApplication/WindowsFormsEngine.cs index 3608def5..c49a0411 100644 --- a/CSharp/Engines/WindowsForms/Engines/UniversalEditor.UserInterface.WindowsForms.DesktopApplication/WindowsFormsEngine.cs +++ b/CSharp/Engines/WindowsForms/Engines/UniversalEditor.UserInterface.WindowsForms.DesktopApplication/WindowsFormsEngine.cs @@ -216,11 +216,17 @@ namespace UniversalEditor.UserInterface.WindowsForms row1.Items.Add("textEditor", "Text Editor"); PieMenuManager.Groups.Add(row1); + Application.ThreadException += Application_ThreadException; Application.Run(); Glue.Common.Methods.SendApplicationEvent(new Glue.ApplicationEventEventArgs(Glue.Common.Constants.EventNames.ApplicationStop)); } + private void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e) + { + ShowCrashDialog(e.Exception); + } + private static System.Drawing.Color ParseColor(string htmlCode) { int iR = 0, iG = 0, iB = 0; @@ -411,5 +417,12 @@ namespace UniversalEditor.UserInterface.WindowsForms } return true; } + + protected override void ShowCrashDialog(Exception ex) + { + Dialogs.CrashDialog dlg = new Dialogs.CrashDialog(); + dlg.Exception = ex; + dlg.ShowDialog(); + } } } diff --git a/CSharp/Libraries/UniversalEditor.UserInterface/Engine.cs b/CSharp/Libraries/UniversalEditor.UserInterface/Engine.cs index 10120226..4eba781d 100644 --- a/CSharp/Libraries/UniversalEditor.UserInterface/Engine.cs +++ b/CSharp/Libraries/UniversalEditor.UserInterface/Engine.cs @@ -294,22 +294,42 @@ namespace UniversalEditor.UserInterface public static bool Execute() { - Engine[] engines = GetAvailableEngines(); + Engine[] engines = null; + try + { + engines = GetAvailableEngines(); + } + catch + { + return false; + } + if (engines.Length < 1) { return false; } else if (engines.Length == 1) { - engines[0].StartApplication(); + mvarCurrentEngine = engines[0]; } else { - engines[0].StartApplication(); + mvarCurrentEngine = engines[0]; + } + + try + { + mvarCurrentEngine.StartApplication(); + } + catch (Exception ex) + { + mvarCurrentEngine.ShowCrashDialog(ex); } return true; } + protected abstract void ShowCrashDialog(Exception ex); + protected abstract void MainLoop(); private Command.CommandCollection mvarCommands = new Command.CommandCollection();