Jump to content

Crashing autonomy problem


Recommended Posts

My plugin implements a custom crash handling system and that works fine with it. However, i've noticed that when the user then uses PDN having run my plugin it uses the plugin's crash handler instead of PDN's! :shock: I could store the original crash handler before I set it and then set it back before my plugin closes but I first want to check whether there is a better way of fixing this problem.

TIA

KaHuc.png
Link to comment
Share on other sites

Perusing via Reflector, I see:

Application.ThreadException += new ThreadExceptionEventHandler(this.Application_ThreadException);

but no:

Application.ThreadException -= new ThreadExceptionEventHandler(this.Application_ThreadException);

xZYt6wl.png

ambigram signature by Kemaru

[i write plugins and stuff]

If you like a post, upvote it!

Link to comment
Share on other sites

Ok, so you can get the delegates of events from classes compiled in C# or VB.NET, but obviously the Application class was not. I don't see a way to do it. It's possible to get Paint.NET's Startup class's method that it sets as the event handler, but that involves some nasty reflection and would result in your plugin getting pulled for sure.

Short of wrapping all potential error-spots in try blocks, I don't see a reasonable method. Maybe Rick will have better ideas.

xZYt6wl.png

ambigram signature by Kemaru

[i write plugins and stuff]

If you like a post, upvote it!

Link to comment
Share on other sites

I don't know. WinForms does some really weird things to the normal flow of try/catch, due to its heavy reliance on P/Invoking the underlying Win32 UI systems (exceptions don't propogate correctly through a managed->native->managed transition). I'm not sure it's possible. App Domains are another possibility, although WinForms like those even less so really you'd need out-of-process isolation.

For now your best bet is to NOT hook into a static event like that. It's just going to cause more trouble. You're better off writing code that doesn't crash.

The Paint.NET Blog: https://blog.getpaint.net/

Donations are always appreciated! https://www.getpaint.net/donate.html

forumSig_bmwE60.jpg

Link to comment
Share on other sites

You first. :-P

 

The Doctor: There was a goblin, or a trickster, or a warrior... A nameless, terrible thing, soaked in the blood of a billion galaxies. The most feared being in all the cosmos. And nothing could stop it, or hold it, or reason with it. One day it would just drop out of the sky and tear down your world.
Amy: But how did it end up in there?
The Doctor: You know fairy tales. A good wizard tricked it.
River Song: I hate good wizards in fairy tales; they always turn out to be him.

Link to comment
Share on other sites

@Simon:

try this. for CreateConfigDialog, return a dummy form that, in the Shown event, checks if it's Modal property is true (was displayed via ShowDialog), then wraps a call to the real form's ShowDialog in a try/catch block. obviously, this dummy form should hide itself.

xZYt6wl.png

ambigram signature by Kemaru

[i write plugins and stuff]

If you like a post, upvote it!

Link to comment
Share on other sites

Sadly it doesn't work:

private void BaseDialog_Load(object sender, EventArgs e)
       {
           try
           {
               cbDraw = new CBDraw();
               cbDraw.EffectSourceSurface = new Surface(EffectSourceSurface.Size);
               cbDraw.EffectSourceSurface.CopySurface(EffectSourceSurface);

               cbDraw.EffectTokenChanged += new EventHandler(cbDraw_EffectTokenChanged);
               cbDraw.FormClosed += new FormClosedEventHandler(cbDraw_FormClosed);
               cbDraw.ShowDialog();
           }
           catch(Exception exp)
           {
               MessageBox.Show("Caught");
               //Application_ThreadException(this, new ThreadExceptionEventArgs(exp));
           }
       }

KaHuc.png
Link to comment
Share on other sites

I was trying to post to tell you that, but that was when the forum wasn't taking new posts :)

The problem is that ShowDialog() starts a new message loop, which has to P/Invoke into things like GetMessage() and DispatchMessage(), which then calls back into your code for handling messages ("your" code includes WinForms boiler plate message handler stuff). So you have a managed -> native -> managed transition, and the exceptions don't propogate over that native "fence" correctly. Because the native code has no idea, nor cares, that it's actually calling into managed code for the DispatchMessage -> WndProc callback.

Yeah. Win32 message pumping. It's weird

The only way to really handle this properly is the bounce the plugin out-of-process and simple catch all exceptions that come up over there. I really want this for a future release, as this would be a huge benefit for a lot of things. (Like, say, running the Open dialog or font enumeration out-of-proc so they can't take down the whole Paint.NET app!)

The Paint.NET Blog: https://blog.getpaint.net/

Donations are always appreciated! https://www.getpaint.net/donate.html

forumSig_bmwE60.jpg

Link to comment
Share on other sites

The only way to really handle this properly is the bounce the plugin out-of-process and simple catch all exceptions that come up over there. I really want this for a future release, as this would be a huge benefit for a lot of things. (Like, say, running the Open dialog or font enumeration out-of-proc so they can't take down the whole Paint.NET app!)

So in other words I can fix the problem by placing the meat of CBM in a seperate EXE and use a plugin to communicate with it?

KaHuc.png
Link to comment
Share on other sites

My guess is that an implementation of that for just your plugin would be fragile and complicated, at best. You'd need to set up the remoting, handle exceptions, make sure the process is shut down correctly, use shared memory for Surface instances, etc. And then if I start bouncing plugins out-of-process anyway, you'll have a redundant system. You'd also have the problem of yet-another-installation-file for n00bs to forget about, and even worse versioning problems as a result.

Good learning experience though! :)

The Paint.NET Blog: https://blog.getpaint.net/

Donations are always appreciated! https://www.getpaint.net/donate.html

forumSig_bmwE60.jpg

Link to comment
Share on other sites

My guess is that an implementation of that for just your plugin would be fragile and complicated, at best. You'd need to set up the remoting, handle exceptions, make sure the process is shut down correctly, use shared memory for Surface instances, etc. And then if I start bouncing plugins out-of-process anyway, you'll have a redundant system. You'd also have the problem of yet-another-installation-file for n00bs to forget about, and even worse versioning problems as a result.

Good learning experience though! :)

Sounds like fun! Am I a masochist?

xZYt6wl.png

ambigram signature by Kemaru

[i write plugins and stuff]

If you like a post, upvote it!

Link to comment
Share on other sites

Actually, a robust and fully featured out-of-proc remoting system is a pretty advanced system to tackle. I think I finally have all the pieces in place to tackle it for the next post-3.5 release of Paint.NET. It'll involve .NET remoting, shared memory via p/invokes (or maybe .NET 4 has some of that built-in), asynchronous and out of process callbacks, maybe even some code generation so that some of the sense of "that code isn't actually here" can be hidden away when appropriate.

A lot of the trouble stems from the fact that you need 2-way communication. Launching something out of process isn't so hard. Process.Start() can get you half way there. Getting that code to communicate back to you with something other than a text-mode protocol (pipes, for instances) is another matter. I want to be able to just say, "Create an instance of class C which implements interface I ... but do that out of process. And give me a reference to an 'I' that I can pretend is local." (much of this is actually done with .NET Remoting already -- but for special types like Surface, you want to specialize and use, e.g. shared memory -- absolutely cannot copy that stuff by value) AND that object I'm creating should have a reference back to me, or rather to some interface that provides them with host services.

The Paint.NET Blog: https://blog.getpaint.net/

Donations are always appreciated! https://www.getpaint.net/donate.html

forumSig_bmwE60.jpg

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...