1

I wanted to use a crash reporter in my own Revit addin but AppDomain.CurrentDomain.UnhandledException is never called. It seems Revit itself manages the unhandled expections and shows its own crash dialog. What should I do to catch all unhandled exceptions in revit addin before Revit cathes them?

I already tried the following lines of code but it does not work: it never enters the handler method:

public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
    {
        AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
    }

    private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
    {
        throw new NotImplementedException();
    }

Thanks for any help

a.toraby
  • 3,232
  • 5
  • 41
  • 73

3 Answers3

1

I think there is no way to do this in Revit main thread.

But if you will run your addin in separate thread exceptions from that thread will not be handled by Revit, and UnhandledExceptions event will be fired (most likely Revit will crash as well).

If your addin is on wpf you can launch it in separate thread like this, and even handle exceptions from that thread.

namespace ClassLibrary2
{
    [Transaction(TransactionMode.Manual)]
    public class Startup : IExternalCommand
    {
        public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
        {
            try
            {
                App.ThisApp.ShowFormSeparateThread();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
            return Result.Succeeded;
        }
    }
}

_

    public void ShowFormSeparateThread()
    {
        if ( !(_uiThread is null) && _uiThread.IsAlive )
            return;

        _uiThread = new Thread(() =>
        {
            SynchronizationContext.SetSynchronizationContext(
                new DispatcherSynchronizationContext(Dispatcher.CurrentDispatcher));
            
            Dispatcher.CurrentDispatcher.UnhandledException += (sender, args) =>
            {
                MessageBox.Show("Err" + args.Exception.Message);
                args.Handled = true;
            };
            _mMyForm = new MainWindow();
            _mMyForm.DataContext = new MainViewModel();
            _mMyForm.Closed += (s, e) => Dispatcher.CurrentDispatcher.InvokeShutdown();
            _mMyForm.Show();
            Dispatcher.Run();
        });
        
        _uiThread.SetApartmentState(ApartmentState.STA);
        _uiThread.IsBackground = true;
        
        _uiThread.Start();
        
    }

If you want you can get information about ALL exception in Revit even thrown by someone else addins, just use

 AppDomain.CurrentDomain.FirstChanceException += (sender, args) =>
 {
     //your code here
 }; 
Kliment Nechaev
  • 480
  • 1
  • 6
  • 13
0

Any particular reason you didn't want to handle this logic in a try-catch block as opposed to subscribing to events?

In this case, by the way, I believe you're subscribing to the application window's event handlers - Revit will never let it get that far up the chain which is why it's not entering the handler method you've created.

prestonsmith
  • 758
  • 1
  • 9
  • 29
0

Are you trying to create a generic crash reporter that catches exceptions unrelated to your add-in? I don't think this is possible with a Revit Add-In. If that is what you are trying to do I would look into parsing the active journal file for specific "error" keywords". This will have a lot more information about the internal failures of Revit.

If you are trying to create a crash reporter for your own add-in then I would just make sure you surround code in your methods called by Revit with a Try/Catch block that logs/reports any exceptions thrown.

[Transaction(TransactionMode.ReadOnly)]
public class MyCommand: IExternalCommand 
{
    public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements) {
    try 
    {
        //do stuff
    } catch (Exception exp) {
        CrashReporter.LogException(exp);
        throw;
    }
}

Then apply the same to any other entry points into your add-in such as IExternalApplication.StartUp(), IExternalApplication.ShutDown() etc..

Eric Anastas
  • 21,675
  • 38
  • 142
  • 236