Simon Brown Posted April 24, 2009 Share Posted April 24, 2009 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 Quote Link to comment Share on other sites More sharing options...
pyrochild Posted April 24, 2009 Share Posted April 24, 2009 What are you using to register your handler? try/catch? AppDomain.UNhandledException? Quote http://i.imgur.com/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 More sharing options...
Simon Brown Posted April 24, 2009 Author Share Posted April 24, 2009 Application.ThreadException Quote Link to comment Share on other sites More sharing options...
pyrochild Posted April 24, 2009 Share Posted April 24, 2009 Perusing via Reflector, I see: Application.ThreadException += new ThreadExceptionEventHandler(this.Application_ThreadException); but no: Application.ThreadException -= new ThreadExceptionEventHandler(this.Application_ThreadException); Quote http://i.imgur.com/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 More sharing options...
Simon Brown Posted April 24, 2009 Author Share Posted April 24, 2009 After CBM, PDN no longer uses the CB handler, but it now uses the .NET one. Quote Link to comment Share on other sites More sharing options...
pyrochild Posted April 24, 2009 Share Posted April 24, 2009 Odd. Can you save the existing handler and reassign it when you're done? Quote http://i.imgur.com/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 More sharing options...
Simon Brown Posted April 24, 2009 Author Share Posted April 24, 2009 I can't save it. Error 1 The event 'System.Windows.Forms.Application.ThreadException' can only appear on the left hand side of += or -= C:\Users\Simon Brown\Documents\Visual Studio 2008\Projects\CustomBrushesMini\CustomBrushes\CBDraw.cs 30 40 CustomBrushes Quote Link to comment Share on other sites More sharing options...
pyrochild Posted April 24, 2009 Share Posted April 24, 2009 can you grab the event via reflection? Quote http://i.imgur.com/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 More sharing options...
Simon Brown Posted April 24, 2009 Author Share Posted April 24, 2009 I'm not sure how and Google doesn't return much. Besides, this seems cumbersome. Quote Link to comment Share on other sites More sharing options...
pyrochild Posted April 24, 2009 Share Posted April 24, 2009 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. Quote http://i.imgur.com/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 More sharing options...
Simon Brown Posted April 25, 2009 Author Share Posted April 25, 2009 I guess if I can't add the event I could add it to the form closing event and have the application do a double-crash handling - although that may be slightly confusing for the user. Quote Link to comment Share on other sites More sharing options...
Rick Brewster Posted April 27, 2009 Share Posted April 27, 2009 You just have to remove your handler. You aren't allowed to save/push/pop events like the way you're trying to do. Events are owned by their container. Quote The Paint.NET Blog: https://blog.getpaint.net/ Donations are always appreciated! https://www.getpaint.net/donate.html Link to comment Share on other sites More sharing options...
pyrochild Posted April 27, 2009 Share Posted April 27, 2009 Is Paint.NET's plugin error handler being extended to include dialog-errors a future possibility, then? Quote http://i.imgur.com/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 More sharing options...
Rick Brewster Posted April 27, 2009 Share Posted April 27, 2009 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. Quote The Paint.NET Blog: https://blog.getpaint.net/ Donations are always appreciated! https://www.getpaint.net/donate.html Link to comment Share on other sites More sharing options...
david.atwell Posted April 27, 2009 Share Posted April 27, 2009 You first. :-P Quote  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 More sharing options...
BoltBait Posted April 27, 2009 Share Posted April 27, 2009 People in other cubes near me are wondering why I'm laughing so much this morning. Quote Download: BoltBait's Plugin Pack | CodeLab | and a Free Computer Dominos Game Link to comment Share on other sites More sharing options...
pyrochild Posted April 27, 2009 Share Posted April 27, 2009 @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. Quote http://i.imgur.com/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 More sharing options...
Simon Brown Posted April 30, 2009 Author Share Posted April 30, 2009 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)); } } Quote Link to comment Share on other sites More sharing options...
Rick Brewster Posted April 30, 2009 Share Posted April 30, 2009 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!) Quote The Paint.NET Blog: https://blog.getpaint.net/ Donations are always appreciated! https://www.getpaint.net/donate.html Link to comment Share on other sites More sharing options...
Simon Brown Posted April 30, 2009 Author Share Posted April 30, 2009 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? Quote Link to comment Share on other sites More sharing options...
Rick Brewster Posted April 30, 2009 Share Posted April 30, 2009 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! Quote The Paint.NET Blog: https://blog.getpaint.net/ Donations are always appreciated! https://www.getpaint.net/donate.html Link to comment Share on other sites More sharing options...
Simon Brown Posted April 30, 2009 Author Share Posted April 30, 2009 Given that CBM only communicates with PDN when being run and closed (apart from subtle communication), I could probably use temp files for communication without sacrificing performance. Quote Link to comment Share on other sites More sharing options...
Simon Brown Posted April 30, 2009 Author Share Posted April 30, 2009 After attempting it, I now see your point. :oops: Quote Link to comment Share on other sites More sharing options...
pyrochild Posted April 30, 2009 Share Posted April 30, 2009 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? Quote http://i.imgur.com/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 More sharing options...
Rick Brewster Posted May 1, 2009 Share Posted May 1, 2009 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. Quote The Paint.NET Blog: https://blog.getpaint.net/ Donations are always appreciated! https://www.getpaint.net/donate.html Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.