Rhino crashes if Eto dialog stays open too long in a command

If I show an Eto.Forms.SaveFileDialog inside a command—even on the UI thread—and leave the dialog open for more than ~30 seconds, Rhino crashes. The same issue happens whether I use RhinoApp.InvokeOnUiThread or not.

public class CrashSaveDialogCommand : Command
{
    public override string EnglishName => "CrashSaveDialogTest";

    protected override Result RunCommand(RhinoDoc doc, RunMode mode)
    {
        var dialog = new Eto.Forms.SaveFileDialog
        {
            Title = "Save File",
            FileName = "test.txt",
        };

        // Rhino crashes if you leave this dialog open for ~30+ seconds
        var result = dialog.ShowDialog(RhinoEtoApp.MainWindow);

        RhinoApp.WriteLine($"Dialog result: {result}");
        return Result.Success;
    }
}

System Info

  • Rhino 8
  • Windows 11
  • .NET 7

Hey @Ryan_Johann1,

Thanks for giving us the code. I can’t replicate this with the same setup as you.

Does the submit crash dialog appear after the crash?
If so can you submit the crash along with your email? That would give a lot of insight.

– cs

Yes the crash dialog appears, i just sent the report using the same email address for this account.

RhinoCrashDump.3dm (40.3 KB)

1 Like

Can you try the same without ECheck.RhinoPlugin installed? You have an Embedded WebBrowser somewhere which is causing the crash and it might be from this plugin.

1 Like

I can’t, haha—that is my plugin. :sweat_smile:

I was originally calling the command from a WebView2 button click, but even when I ran the command in isolation (no webview interactions, just opening the Eto dialog), I still got the crash after ~30 seconds.

Is there any more info on how WebView2 might be conflicting with Eto dialogs, even if it’s not actively in use? Would love to understand what’s going on under the hood if you’ve seen this sort of thing before.

Ah! Ok so now we’re debugging :partying_face:

Are you doing this via RhinoApp.RunScript or another method?

This is the crash info I have:
(It’s a bit thin unfortunately)

0.
EmbeddedBrowserWebView.base::debug.BreakDebuggerAsyncSafe() in EmbeddedBrowserWebView 0xd
1.
EmbeddedBrowserWebView.`string'() in EmbeddedBrowserWebView 0x99
2.
EmbeddedBrowserWebView.embedded_browser_webview::internal::AppTaskRunner.MessageCallback() in EmbeddedBrowserWebView 0x53
1 Like

I’m not too familiar with WebView or WebView2, @curtisw may be able to shed some light on this.

Yep running it via RhinoApp.RunScript. Might be thin but better then what i had (nothing) haha

Hey @Ryan_Johann1,

You’re likely running into this, which essentially boils down to you should not be running an external modal message loop from an event generated via the web view (Eto or not).

This means that pretty much everything triggered from the WebView2 should be calling Eto.Forms.Application.Instance.AsyncInvoke() to perform whatever tasks you need, which would return control back to the WebView and run the script

Calling RhinoApp.InvokeOnUiThread won’t do what you need here, because you are likely already on the UI thread, but even if you’re not then it’d hang the WebView while the dialog is showing.

The call stack looks to me that the WebView2 is detecting that it is in this bad/hung state and trying to break in the debugger.

Hope this helps.
Curtis.

3 Likes

Thanks @curtisw, that explanation helped a lot. I confirmed that moving the dialog call into Eto.Forms.Application.Instance.AsyncInvoke() resolves the crash. My hero! :partying_face:

Appreciate the insight and the link to the threading model as well.

I’ll go through the rest of the plugin and start reviewing where else we may need to refactor things coming from WebView2. Since everything in our UI is routed through the WebView, there might be other spots where we’re unknowingly causing similar issues.

For example, I’ve got another more complex case where a WebView button triggers a RunScript call to let the user draw a polyline in the Rhino document. At that point, I’m also listening for the RhinoDoc.AddRhinoObject event. When that fires (after the user completes the polyline), I queue the event to be processed on the next RhinoApp.Idle, and in that callback, I handle processing the object, tagging it with metadata, and adding it to a conduit — all of which works well.

However, part of that same flow also attempts to create a new layer (if needed) and add the object to it, based on its spatial context (e.g. if it’s inside a bounding box I have in memory). That part seems to behave inconsistently — sometimes the object isn’t moved to the correct layer, or the layer isn’t created at all.

It’s a long shot, but I’m wondering if that inconsistency could also be related to WebView2 or how/when the event queue is handled. I’m not sure if there are known caveats when resolving document or layer operations from event handlers triggered downstream of WebView events — especially when combined with Rhino event subscriptions and idle time processing.

If you’ve seen anything like that or have suggestions on where I should look deeper, I’d really appreciate it!