Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix(Revit) : CNX-8387 ca1031 don't catch general exceptions #3106

Merged
merged 18 commits into from
Jan 10, 2024
100 changes: 69 additions & 31 deletions ConnectorRevit/ConnectorRevit/Entry/App.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using Autodesk.Revit.ApplicationServices;
using Autodesk.Revit.UI;
using ConnectorRevit;
using RevitSharedResources.Extensions.SpeckleExtensions;
using RevitSharedResources.Models;
using Speckle.BatchUploader.Sdk;
using Speckle.BatchUploader.OperationDriver;
Expand All @@ -22,8 +23,12 @@ public class App : IExternalApplication

public static UIControlledApplication UICtrlApp { get; set; }

private bool _initialized;

public Result OnStartup(UIControlledApplication application)
{
InitializeConnector();

//Always initialize RevitTask ahead of time within Revit API context
APIContext.Initialize(application);

Expand All @@ -35,7 +40,17 @@ public Result OnStartup(UIControlledApplication application)
{
application.CreateRibbonTab(tabName);
}
catch { }
catch (Autodesk.Revit.Exceptions.ArgumentException)
{
// exception occurs when the speckle tab has already been created.
// this happens when both the dui2 and the dui3 connectors are installed. Can be safely ignored.
}
catch (Autodesk.Revit.Exceptions.InvalidOperationException ex)
{
SpeckleLog.Logger.Warning(ex, "User has too many Revit add-on tabs installed");
NotifyUserOfErrorStartingConnector(ex);
return Result.Failed;
}

var specklePanel = application.CreateRibbonPanel(tabName, "Speckle 2");

Expand Down Expand Up @@ -124,18 +139,10 @@ Autodesk.Revit.DB.Events.ApplicationInitializedEventArgs e
{
try
{
// We need to hook into the AssemblyResolve event before doing anything else
// or we'll run into unresolved issues loading dependencies
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(OnAssemblyResolve);
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
System.Windows.Forms.Application.ThreadException += Application_ThreadException;
InitializeConnector();

AppInstance = new UIApplication(sender as Application);

Setup.Init(ConnectorBindingsRevit.HostAppNameVersion, ConnectorBindingsRevit.HostAppName);

//DUI2 - pre build app, so that it's faster to open up
SpeckleRevitCommand.InitAvalonia();
var bindings = new ConnectorBindingsRevit(AppInstance);
bindings.RegisterAppEvents();
SpeckleRevitCommand.Bindings = bindings;
Expand All @@ -154,28 +161,15 @@ Autodesk.Revit.DB.Events.ApplicationInitializedEventArgs e

//AppInstance.ViewActivated += new EventHandler<ViewActivatedEventArgs>(Application_ViewActivated);
}
catch (Exception ex)
catch (KitException ex)
{
SpeckleLog.Logger.Warning(ex, "Error loading kit on startup");
NotifyUserOfErrorStartingConnector(ex);
}
catch (Exception ex) when (!ex.IsFatal())
{
SpeckleLog.Logger.Fatal(ex, "Failed to load Speckle app");
var td = new TaskDialog("Error loading Speckle");
if (ex is KitException)
{
td.MainContent = ex.Message;
}
else
{
td.MainContent =
$"Oh no! Something went wrong while loading Speckle, please report it on the forum:\n\n{ex.Message}";
}

td.AddCommandLink(TaskDialogCommandLinkId.CommandLink1, "Ask for help on our Community Forum");

TaskDialogResult tResult = td.Show();

if (TaskDialogResult.CommandLink1 == tResult)
{
Process.Start("https://speckle.community/");
}
NotifyUserOfErrorStartingConnector(ex);
}
}

Expand Down Expand Up @@ -225,7 +219,10 @@ private ImageSource LoadPngImgSource(string sourceName, string path)
ImageSource m_source = m_decoder.Frames[0];
return (m_source);
}
catch { }
catch (Exception ex) when (!ex.IsFatal())
{
SpeckleLog.Logger.LogDefaultError(ex);
}

return null;
}
Expand All @@ -245,4 +242,45 @@ static Assembly OnAssemblyResolve(object sender, ResolveEventArgs args)

return a;
}

internal static void NotifyUserOfErrorStartingConnector(Exception ex)
{
using var td = new TaskDialog("Error loading Speckle");

td.MainContent =
ex is KitException
? ex.Message
: $"Oh no! Something went wrong while loading Speckle, please report it on the forum:\n\n{ex.Message}";

td.AddCommandLink(TaskDialogCommandLinkId.CommandLink1, "Ask for help on our Community Forum");

TaskDialogResult tResult = td.Show();

if (TaskDialogResult.CommandLink1 == tResult)
{
Process.Start("https://speckle.community/");
}
}

private void InitializeConnector()
{
if (_initialized)
{
return;
}

// We need to hook into the AssemblyResolve event before doing anything else
// or we'll run into unresolved issues loading dependencies
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(OnAssemblyResolve);
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
System.Windows.Forms.Application.ThreadException += Application_ThreadException;

// initialize the speckle logger
Setup.Init(ConnectorBindingsRevit.HostAppNameVersion, ConnectorBindingsRevit.HostAppName);

//DUI2 - pre build app, so that it's faster to open up
SpeckleRevitCommand.InitAvalonia();

_initialized = true;
}
}
155 changes: 55 additions & 100 deletions ConnectorRevit/ConnectorRevit/Entry/SpeckleRevitCommand.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
using System.Threading;
Expand All @@ -12,7 +11,6 @@
using DesktopUI2.ViewModels;
using DesktopUI2.Views;
using Speckle.ConnectorRevit.UI;
using Speckle.Core.Logging;

namespace Speckle.ConnectorRevit.Entry;

Expand Down Expand Up @@ -56,16 +54,9 @@ public Result Execute(ExternalCommandData commandData, ref string message, Eleme
{
if (UseDockablePanel)
{
try
{
RegisterPane();
var panel = App.AppInstance.GetDockablePane(PanelId);
panel.Show();
}
catch (Exception ex)
{
SpeckleLog.Logger.Error(ex, "Failed to show dockable panel");
}
RegisterPane();
var panel = App.AppInstance.GetDockablePane(PanelId);
panel.Show();
}
else
{
Expand All @@ -77,113 +68,77 @@ public Result Execute(ExternalCommandData commandData, ref string message, Eleme

internal static void RegisterPane()
{
try
if (!UseDockablePanel)
{
if (!UseDockablePanel)
{
return;
}

var registered = DockablePane.PaneIsRegistered(PanelId);
var created = DockablePane.PaneExists(PanelId);

if (registered && created)
{
_panel.Init();
return;
}

if (!registered)
{
//Register dockable panel
var viewModel = new MainViewModel(Bindings);
_panel = new Panel { DataContext = viewModel };
App.AppInstance.RegisterDockablePane(PanelId, "Speckle", _panel);
_panel.Init();
}
created = DockablePane.PaneExists(PanelId);
return;
}

//if revit was launched double-clicking on a Revit file, we're screwed
//could maybe show the old window?
if (!created && App.AppInstance.Application.Documents.Size > 0)
{
TaskDialog mainDialog = new("Dockable Panel Issue");
mainDialog.MainInstruction = "Dockable Panel Issue";
mainDialog.MainContent =
"Revit cannot properly register Dockable Panels when launched by double-clicking a Revit file. "
+ "Please close and re-open Revit without launching a file OR open/create a new project to trigger the Speckle panel registration.";
var registered = DockablePane.PaneIsRegistered(PanelId);
var created = DockablePane.PaneExists(PanelId);

// Set footer text. Footer text is usually used to link to the help document.
mainDialog.FooterText =
"<a href=\"https://github.com/specklesystems/speckle-sharp/issues/1469 \">" + "Click here for more info</a>";
if (registered && created)
{
_panel.Init();
return;
}

mainDialog.Show();
}
if (!registered)
{
//Register dockable panel
var viewModel = new MainViewModel(Bindings);
_panel = new Panel { DataContext = viewModel };
App.AppInstance.RegisterDockablePane(PanelId, "Speckle", _panel);
_panel.Init();
}
catch (Exception ex)
created = DockablePane.PaneExists(PanelId);

//if revit was launched double-clicking on a Revit file, we're screwed
//could maybe show the old window?
if (!created && App.AppInstance.Application.Documents.Size > 0)
{
SpeckleLog.Logger.Fatal(ex, "Failed to load Speckle command for host app");
var td = new TaskDialog("Error");
td.MainContent =
$"Oh no! Something went wrong while loading Speckle, please report it on the forum:\n{ex.Message}";
td.AddCommandLink(TaskDialogCommandLinkId.CommandLink1, "Report issue on our Community Forum");
TaskDialog mainDialog = new("Dockable Panel Issue");
mainDialog.MainInstruction = "Dockable Panel Issue";
mainDialog.MainContent =
"Revit cannot properly register Dockable Panels when launched by double-clicking a Revit file. "
+ "Please close and re-open Revit without launching a file OR open/create a new project to trigger the Speckle panel registration.";

TaskDialogResult tResult = td.Show();
// Set footer text. Footer text is usually used to link to the help document.
mainDialog.FooterText =
"<a href=\"https://github.com/specklesystems/speckle-sharp/issues/1469 \">" + "Click here for more info</a>";

if (TaskDialogResult.CommandLink1 == tResult)
{
Process.Start("https://speckle.community/");
}
mainDialog.Show();
}
}

public static void CreateOrFocusSpeckle(bool showWindow = true)
{
try
if (MainWindow == null)
{
if (MainWindow == null)
{
var viewModel = new MainViewModel(Bindings);
MainWindow = new MainWindow { DataContext = viewModel };

//massive hack: we start the avalonia main loop and stop it immediately (since it's thread blocking)
//to avoid an annoying error when closing revit
var cts = new CancellationTokenSource();
cts.CancelAfter(100);
AvaloniaApp.Run(cts.Token);
}

if (showWindow)
{
MainWindow.Show();
MainWindow.Activate();

//required to gracefully quit avalonia and the skia processes
//can also be used to manually do so
//https://github.com/AvaloniaUI/Avalonia/wiki/Application-lifetimes


if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
var parentHwnd = App.AppInstance.MainWindowHandle;
var hwnd = MainWindow.PlatformImpl.Handle.Handle;
SetWindowLongPtr(hwnd, GWL_HWNDPARENT, parentHwnd);
}
}
var viewModel = new MainViewModel(Bindings);
MainWindow = new MainWindow { DataContext = viewModel };

//massive hack: we start the avalonia main loop and stop it immediately (since it's thread blocking)
//to avoid an annoying error when closing revit
var cts = new CancellationTokenSource();
cts.CancelAfter(100);
AvaloniaApp.Run(cts.Token);
}
catch (Exception ex)

if (showWindow)
{
SpeckleLog.Logger.Fatal(ex, "Failed to create main window");
var td = new TaskDialog("Error");
td.MainContent =
$"Oh no! Something went wrong while loading Speckle, please report it on the forum:\n{ex.Message}";
td.AddCommandLink(TaskDialogCommandLinkId.CommandLink1, "Report issue on our Community Forum");
MainWindow.Show();
MainWindow.Activate();

//required to gracefully quit avalonia and the skia processes
//can also be used to manually do so
//https://github.com/AvaloniaUI/Avalonia/wiki/Application-lifetimes

TaskDialogResult tResult = td.Show();

if (TaskDialogResult.CommandLink1 == tResult)
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
Process.Start("https://speckle.community/");
var parentHwnd = App.AppInstance.MainWindowHandle;
var hwnd = MainWindow.PlatformImpl.Handle.Handle;
SetWindowLongPtr(hwnd, GWL_HWNDPARENT, parentHwnd);
}
}
}
Expand Down
5 changes: 4 additions & 1 deletion ConnectorRevit/ConnectorRevit/Storage/StreamStateManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.ExtensibleStorage;
using DesktopUI2.Models;
using RevitSharedResources.Extensions.SpeckleExtensions;
using Speckle.Core.Logging;
using Speckle.Newtonsoft.Json;

namespace Speckle.ConnectorRevit.Storage;
Expand Down Expand Up @@ -36,8 +38,9 @@ public static List<StreamState> ReadState(Document doc)

return states;
}
catch (Exception e)
catch (Exception ex) when (!ex.IsFatal())
{
SpeckleLog.Logger.LogDefaultError(ex);
return new List<StreamState>();
}
}
Expand Down
Loading