From 02f6e884d70269ce10dc016d740f07b99fbf495a Mon Sep 17 00:00:00 2001 From: Andy McFadden Date: Sat, 20 Jul 2019 17:27:39 -0700 Subject: [PATCH] Fix startup issues - MakeDist now copies CommonWPF.dll. - Spent a bunch of time tracking down a null-pointer deref that only happened when you didn't start with a config file. Fixed. - The NPE was causing the program to exit without any sort of useful diagnostic, so I added an uncaught exception handler that writes the crash to a text file in the current directory. - Added a trace listener definition to App.config that writes log messages to a file, but it can't generally be enabled at runtime because you can't write files from inside the sandbox. So it's there but commented out. - Made the initial size of the main window a little wider. --- CommonUtil/Misc.cs | 36 +++++++++++++++++++++++ MakeDist/FileCopier.cs | 6 ++-- SourceGen/App.config | 12 ++++++++ SourceGen/RuntimeData/Help/tutorials.html | 4 +-- SourceGen/WpfGui/MainWindow.xaml | 2 +- SourceGen/WpfGui/MainWindow.xaml.cs | 4 +++ SourceGen/WpfGui/NewProject.xaml.cs | 11 ++++--- 7 files changed, 66 insertions(+), 9 deletions(-) diff --git a/CommonUtil/Misc.cs b/CommonUtil/Misc.cs index 71625fe..d441a6a 100644 --- a/CommonUtil/Misc.cs +++ b/CommonUtil/Misc.cs @@ -14,6 +14,8 @@ * limitations under the License. */ using System; +using System.Diagnostics; +using System.IO; using System.Linq; namespace CommonUtil { @@ -28,5 +30,39 @@ namespace CommonUtil { Console.WriteLine(" " + ns); } } + + /// + /// Writes an unhandled exception trace to a crash file. + /// + /// + /// Usage: + /// AppDomain.CurrentDomain.UnhandledException += + /// new UnhandledExceptionEventHandler(CommonUtil.Misc.CrashReporter); + /// + /// Thanks: https://stackoverflow.com/a/21308327/294248 + /// + public static void CrashReporter(object sender, UnhandledExceptionEventArgs e) { + const string CRASH_PATH = @"CrashLog.txt"; + + Exception ex = (Exception)e.ExceptionObject; + Debug.WriteLine("CRASHING (term=" + e.IsTerminating + "): " + ex); + + try { + using (StreamWriter writer = new StreamWriter(CRASH_PATH, true)) { + writer.WriteLine("*** " + DateTime.Now.ToLocalTime() + " ***"); + while (ex != null) { + writer.WriteLine(ex.GetType().FullName + ": " + ex.Message); + writer.WriteLine("Trace:"); + writer.WriteLine(ex.StackTrace); + writer.WriteLine(string.Empty); + + ex = ex.InnerException; + } + } + } catch { + // damn it + Debug.WriteLine("Crashed while crashing"); + } + } } } diff --git a/MakeDist/FileCopier.cs b/MakeDist/FileCopier.cs index f212a89..1a58264 100644 --- a/MakeDist/FileCopier.cs +++ b/MakeDist/FileCopier.cs @@ -62,8 +62,10 @@ namespace MakeDist { SourceFileSpec.List, false, new string[] { "Asm65.dll" }), new CopySpec("CommonUtil/bin/{BUILD_TYPE}/netstandard2.0/", ".", SourceFileSpec.List, false, new string[] { "CommonUtil.dll" }), - new CopySpec("CommonWinForms/bin/{BUILD_TYPE}/", ".", - SourceFileSpec.List, false, new string[] { "CommonWinForms.dll" }), + //new CopySpec("CommonWinForms/bin/{BUILD_TYPE}/", ".", + // SourceFileSpec.List, false, new string[] { "CommonWinForms.dll" }), + new CopySpec("CommonWPF/bin/{BUILD_TYPE}/", ".", + SourceFileSpec.List, false, new string[] { "CommonWPF.dll" }), new CopySpec("PluginCommon/bin/{BUILD_TYPE}/netstandard2.0/", ".", SourceFileSpec.List, false, new string[] { "PluginCommon.dll" }), new CopySpec("SourceGen/bin/{BUILD_TYPE}/", ".", diff --git a/SourceGen/App.config b/SourceGen/App.config index b50c74f..9e14e6c 100644 --- a/SourceGen/App.config +++ b/SourceGen/App.config @@ -3,4 +3,16 @@ + + + + \ No newline at end of file diff --git a/SourceGen/RuntimeData/Help/tutorials.html b/SourceGen/RuntimeData/Help/tutorials.html index 4d51886..971e2eb 100644 --- a/SourceGen/RuntimeData/Help/tutorials.html +++ b/SourceGen/RuntimeData/Help/tutorials.html @@ -27,8 +27,8 @@ manual is recommended.

Tutorial #1: Basic Features

Start by launching SourceGen. The initial screen has a large -center area with some links, and some mostly-empty windows on the sides. -The links are shortcuts for menu items in the File menu.

+center area with some buttons, and some mostly-empty windows on the sides. +The buttons are shortcuts for menu items in the File menu.

Create the project

diff --git a/SourceGen/WpfGui/MainWindow.xaml b/SourceGen/WpfGui/MainWindow.xaml index 6977586..3c06c27 100644 --- a/SourceGen/WpfGui/MainWindow.xaml +++ b/SourceGen/WpfGui/MainWindow.xaml @@ -23,7 +23,7 @@ limitations under the License. mc:Ignorable="d" Title="6502bench SourceGen" Icon="/SourceGen;component/Res/SourceGenIcon.ico" - Width="1000" Height="700" MinWidth="800" MinHeight="500" + Width="1200" Height="700" MinWidth="800" MinHeight="500" SourceInitialized="Window_SourceInitialized" Loaded="Window_Loaded" LocationChanged="Window_LocationChanged" diff --git a/SourceGen/WpfGui/MainWindow.xaml.cs b/SourceGen/WpfGui/MainWindow.xaml.cs index 1bd8104..f8ab083 100644 --- a/SourceGen/WpfGui/MainWindow.xaml.cs +++ b/SourceGen/WpfGui/MainWindow.xaml.cs @@ -159,8 +159,12 @@ namespace SourceGen.WpfGui { public MainWindow() { + Debug.WriteLine("START at " + DateTime.Now.ToLocalTime()); InitializeComponent(); + AppDomain.CurrentDomain.UnhandledException += + new UnhandledExceptionEventHandler(CommonUtil.Misc.CrashReporter); + listViewSetSelectedItems = codeListView.GetType().GetMethod("SetSelectedItems", BindingFlags.NonPublic | BindingFlags.Instance); Debug.Assert(listViewSetSelectedItems != null); diff --git a/SourceGen/WpfGui/NewProject.xaml.cs b/SourceGen/WpfGui/NewProject.xaml.cs index d0a0905..627e913 100644 --- a/SourceGen/WpfGui/NewProject.xaml.cs +++ b/SourceGen/WpfGui/NewProject.xaml.cs @@ -57,8 +57,10 @@ namespace SourceGen.WpfGui { "[nothing!selected]"); TreeViewItem selItem = PopulateNodes(prevSelSystem); - selItem.IsSelected = true; - selItem.BringIntoView(); + if (selItem != null) { + selItem.IsSelected = true; + selItem.BringIntoView(); + } targetSystemTree.Focus(); @@ -70,7 +72,8 @@ namespace SourceGen.WpfGui { /// /// TreeView to add items to /// Name of previously-selected system. - /// The node that matches prevSelSystem, or null if not found. + /// The node that matches prevSelSystem, or the first leaf node if no node + /// matches, or null if no leaf nodes are found. private TreeViewItem PopulateNodes(string prevSelSystem) { TreeViewItem selItem = null; @@ -105,7 +108,7 @@ namespace SourceGen.WpfGui { newItem.Tag = sd; groupItem.Items.Add(newItem); - if (isValid && sd.Name == prevSelSystem) { + if ((isValid && sd.Name == prevSelSystem) || selItem == null) { selItem = newItem; } }