Joe White's Blog Life, .NET, and cats

Paint exceptions and error dialogs #.NET #Delphi

In Delphi, every window message handler is automatically wrapped in a try..except. Exceptions are always handled, by showing the error text in a dialog box and letting the program continue execution (though you can globally override that behavior, or, obviously, add your own try..except if you need it). This global handler is good, except for paint exceptions. If your paint code raises an exception, you're screwed, because the error dialog (usually, at least) pops up right on top of the control. When you close the error dialog, the control gets invalidated, it gets another paint message, and... boom, you immediately get another error dialog. Close that one, another immediately pops up. So there's no way to close the application, other than killing it from the debugger or from Task Manager.

WinForms improves this a bit, by not catching paint exceptions. Any exception during painting will automatically terminate your program. Extremely crude, but effective enough; it's actually a step forward from the infinite-dialog scenario. But WinForms doesn't catch exceptions anywhere else, either — and that's downright brain-damaged. If I click a button, and that button's Click event handler does something that throws an InvalidOperationException, then my entire application exits. Say what??

In Delphi, we don't have to think about exception handling; it just works (except in paint code, which doesn't cause problems very often). In WinForms, we always have to think about exception handling. Much more work for us, for very little gain. Not a good thing.

So, in our app at work, we've been adding try..catch handlers in all (we hope) of the UI code. Including, as it turns out, the paint code, which was a bad idea on our part. Infinite dialogs this morning. Whee.

But I found a nice tidy way to exit the program, without summarily killing it. The whole problem is when closing the dialog forces the control to repaint. If closing the dialog doesn't force the control to repaint, then all is well. So you just need to open Task Manager, set it to stay on top, and size it so that it completely covers the problem control (but not the parent window's Close button). Then you can switch the focus back to the app, and keep hitting Enter to dismiss the dialogs. The control is covered by Task Manager, so it never gets another Paint event, so it doesn't throw any more exceptions. Once all the error dialogs are gone, you can close the window without hassle.

(And no, we don't have an exception handler on our WinForms paint code anymore. What we do have is a comment saying "DON'T CATCH EXCEPTIONS IN HERE!".)