Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / pas2js / 2020-05

Exception handling in callbacks/event handlers

1 message · 1 person ·

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Michael Van Canneyt

Hello,

We've implemented a small change in the event handling mechanism, with possibly far reaching consequences.

Previously, when an exception happened in a event handler of some browser class: an onclick or onchange, this exception would go unnoticed in pascal code. You would see it only in the console of the browser.

Even if you set the showUncaughtExceptions options of the rtl object, like so:

     rtl.showUncaughtExceptions=true;
     rtl.run();

then the exceptions would still not be shown.

This behaviour was similar to exceptions raised in threads in a native application: the exception was never shown in the main thread.

We have now introduced the 'safecall' modifier for an event handler: When you use this modifier, the rtl will change the small wrapper it generates for callbacks, so it catches any exceptions, and routes the exception through the rtl exception handler.

The 'safecall' modifier must only be specified on the event handler definition, the actual event handler does not need this flag, so your code does not need any changes.

That being the case, I have changed the definition of the basic event handler type in the web.pas unit:

TJSRawEventHandler = reference to Procedure(Event: TJSEvent); safecall;

That means that now, when you click a button and an exception is raised, the exception is handled like an exception in the 'main' program section.

Note that any javascript errors in an event handler will also be caught and handled this way.

At the same time the SysUtils unit now has - in addition to the existing 'ShowException' routine - several new hooks:

Var
   // Handler to show an exception (used when showexception is called)
   OnShowException : TShowExceptionHandler = nil;
// Set handlers for uncaught exceptions. These will call HookUncaughtExceptions
// They return the old exception handler, if there was any.
Function SetOnUnCaughtExceptionHandler(aValue : TUncaughtPascalExceptionHandler) : TUncaughtPascalExceptionHandler;
Function SetOnUnCaughtExceptionHandler(aValue : TUncaughtJSExceptionHandler) : TUncaughtJSExceptionHandler;
// Hook the rtl handler for uncaught exceptions. If any exception handlers were set, they will be called.
// If none were set, the exceptions will be displayed using ShowException.
Procedure HookUncaughtExceptions;

The 'HookUnCaughtException' will tap into the rtl exception handler routine: when the rtl catches an exception, the hook will try to display it, or you can route the exception to a routine of your choice.

Note that there are 2 routines:
One for pascal exceptions, one for Javascript exceptions. This is because a TJSObject is not a TObject.

Note that as long as you don't set

    rtl.showUncaughtExceptions=true;

Nothing changes: exceptions will still get caught by the rtl, but will be re-raised at once, which is fully backwards compatible.

To make it easier for you, the Lazarus IDE's File-New 'Web Browser Application' wizard has been extended with an option to set this flag for you when it generates a new project.

A demonstration program has been committed to the demos (errorhandler), so you can test this new feature.

Enjoy !

Michael.

Reply by email