MadExcept not blocking message queue when displaying message

delphi package - automated exception handling
Post Reply
duncan
Posts: 3
Joined: Thu Aug 02, 2018 5:14 am

MadExcept not blocking message queue when displaying message

Post by duncan »

We have what appears to be a significant issue with mad except exception handling, timing, and the processing of the windows message queue.

In our application, if a control/component throws an exception (DevExpress throwing a EcxEditValidationError for example) the exception gets trapped by vcl code and passed to Application.HandleException (refer TWinControl.MainWndProc).
It appears that MadExcept then jumps in and passes control over to a seperate thread which then displays a message box.

It seems that there is a fatal flaw (at least of our application) in that between control being passed to the madexcept thread and the message box being displayed by the madexcept thread the windows message loop is processed on the main thread. This means that user input is accepted between the exception being thrown and the message being displayed. This causes all sorts of grief (eg message box appearing behind a modal dialog).

The question we have is: can the message loop not be processed (or at least user input etc accepted) in this scenario and/or can the message box be displayed by the main window thread?
madshi
Site Admin
Posts: 10753
Joined: Sun Mar 21, 2004 5:25 pm

Re: MadExcept not blocking message queue when displaying mes

Post by madshi »

If the exception box were to be displayed by the main thread, the message loop would still run, so I'm not sure how that would help?

You can set "madExcept.HandleMessagesInMainThread := false" in your initialization somewhere. Of course this will result in your GUI seemingly being non-responsive.
duncan
Posts: 3
Joined: Thu Aug 02, 2018 5:14 am

Re: MadExcept not blocking message queue when displaying mes

Post by duncan »

Thanks, we will look at this.

This should help because it will prevent the main message loop processing before the dialog being displayed. The problem is the message processing occurring in the main thread between the exception processing being passed over to the background thread and the dialog being displayed. This 'gap' means the use is able to take additional actions in the application (potentially causing the issue to repeat, or triggering a modal message box) before the dialog is displayed to explain there has been an issue. If a modal message box has been displayed this can result in a windowing deadlock (madexcept dialog is not enabled but it is display over the modal dialog displayed due to user action between issue and exception dialog being displayed).
A pause in UI responsiveness is better than the use being able to do additional 'bad' things.
slemmnord
Posts: 46
Joined: Fri Jan 17, 2014 1:04 am

Re: MadExcept not blocking message queue when displaying mes

Post by slemmnord »

I have also run into this problem. I also checked all my older version copies of ME and this seems to be the case even in version 3.

In addition to the user having the opportunity to take action, it is also possible some posted and waiting window messages get handled before the error dialog gets displayed. This can be a recipe for disaster.

Mathias, could ME be altered such that exceptions raised in main thread would go thru registered exception handlers in epQuickFiltering phase (or some new phase) before getting passed to ME thread?

I am handling most exceptions in such handler. The handler checks exception class and translates some SQL errors to user-friendly texts. Then displays an error box and sets Handled to true. However currently even before epQuickFiltering messages are getting pumped.
madshi
Site Admin
Posts: 10753
Joined: Sun Mar 21, 2004 5:25 pm

Re: MadExcept not blocking message queue when displaying mes

Post by madshi »

The thread which raised an exception might no longer be viable for much further processing (e.g. it might have run out of stack space or something like that). Because of that I'm moving processing of the exception to a private thread ASAP.

How would it help to perform some processing in the main thread, before going to a private thread?

If you don't like that madExcept handles messages in the main thread, you can set "madExcept.HandleMessagesInMainThread := false" in your initialization. Of course this will result in your GUI seemingly being non-responsive.
slemmnord
Posts: 46
Joined: Fri Jan 17, 2014 1:04 am

Re: MadExcept not blocking message queue when displaying mes

Post by slemmnord »

It would help by allowing to avoid the problem of processing messages before showing error message for some "normal" errors (such as user input too long or unique key violation errors from db or whatever) where stack trace and other info is not required.

In epQuickFiltering, some "normal" errors can be set as handled. However stTrySyncCallAlways is required because i want to display message box for such errors. And due to requirement to sync again (because error is now in ME thread), messages must get pumped. So some phase before epQuickFiltering, before exception is moved, could solve such problem (for the most part anyway) and it would avoid lots of un-necessary processing by ME resulting in more responsive UI.

I already tried setting HandleMessagesInMainThread to False but then my global exception handler could not sync to main thread and thus can not display any message to user.

If doing what i propose is unfeasible then i can of course learn to live with it and try to work around it. However i think then at least there should be mention about this caveat in bold text somewhere in ME documentation because this changes default and expected behavior in a major way. According to my searches in this forum an elsewhere, i'm not the first, second or even third person who has run into this problem.
madshi
Site Admin
Posts: 10753
Joined: Sun Mar 21, 2004 5:25 pm

Re: MadExcept not blocking message queue when displaying mes

Post by madshi »

I'm perfectly willing to implement something if it really helps multiple users. Just trying to wrap my head around what makes sense here.

I guess I could add another "phase" to the callback system which is called by the crashing thread before moving exception processing to the private madExcept thread. The big worry I have with this approach is that if a user actually accesses certain "exceptIntf" methods (e.g. exceptIntf.BugReport), madExcept has to actually block and calculate the full bug report at that point in time already, which would destroy the whole logic of doing the majority of the processing in a private thread. But used carefully, maybe it could be useful. You'd have to be sensitive about which "excepIntf" methods/properties to access in the context of such a very early exception handler.

Thoughts?
slemmnord
Posts: 46
Joined: Fri Jan 17, 2014 1:04 am

Re: MadExcept not blocking message queue when displaying mes

Post by slemmnord »

For me, getting the exception object itself would be enough as i only look at the exception class, class name and message. Something like this: TGlobalExceptEvent = procedure(const ExceptObject: Exception; var Handled: Boolean);

In such handler (for GUI apps) i would put as first line:
if GetCurrentThreadId <> MainThreadID then Exit;
And then proceed with checking and possibly showing message and then setting handled to True.

This could be thought of as replacement for Application.HandleException that ME patches and does not call the original. Prior to installing ME, this calls Application.OnHandleException event which is generally used for central exception handling.

Alternatively, I think having a clear statement that only exceptIntf.ExceptObject, exceptIntf.ExceptClass and exceptIntf.ExceptMessage are available in such phase could be considered too. But doing so without somehow blocking access to off-limit properties would most likely end up as lots of extra work for you answering users why someones GlobalExceptionHandler blew up. Which seems like a bad idea.

Looking at IMEException, perhaps IMEException.Source, IMEException.Package and IMEException.ExceptAddr could also be possible to provide and useful?
madshi
Site Admin
Posts: 10753
Joined: Sun Mar 21, 2004 5:25 pm

Re: MadExcept not blocking message queue when displaying mes

Post by madshi »

Argh, I just double checked my code, and the creation of the "exceptIntf" object is already done in the private thread.

This will need some proper thinking through. Maybe I can move the creation of the object into the crashing thread, but I'm kind of afraid of adding potential instability. madExcept has been rock solid for years, I don't want to add instability now. Maybe I'll have to create a simpler callback, as a replacement for TApplication.OnException, without the "exceptIntf", but just with the ExceptClass and ExceptMessage.

I'll think about it some more, and hopefully implement something in the next build.
slemmnord
Posts: 46
Joined: Fri Jan 17, 2014 1:04 am

Re: MadExcept not blocking message queue when displaying mes

Post by slemmnord »

madshi wrote:Maybe I'll have to create a simpler callback, as a replacement for TApplication.OnException, without the "exceptIntf", but just with the ExceptClass and ExceptMessage.
That would be perfectly fine as well.
madshi wrote:I'll think about it some more, and hopefully implement something in the next build.
Thank you and good luck! :)
Post Reply