* Allow to hook uncaught exceptions

This commit is contained in:
michael 2020-05-16 11:53:21 +00:00
parent ec3efe0ad5
commit 8e45a4dd32
2 changed files with 112 additions and 14 deletions

View File

@ -796,7 +796,7 @@ type
{ TJSError } { TJSError }
TJSError = Class external name 'Error' TJSError = Class external name 'Error' (TJSObject)
private private
FMessage: String; external name 'message'; FMessage: String; external name 'message';
{$ifdef NodeJS} {$ifdef NodeJS}

View File

@ -314,16 +314,30 @@ type
TOnGetEnvironmentVariable = function(Const EnvVar: String): String; TOnGetEnvironmentVariable = function(Const EnvVar: String): String;
TOnGetEnvironmentString = function(Index: Integer): String; TOnGetEnvironmentString = function(Index: Integer): String;
TOnGetEnvironmentVariableCount = function: Integer; TOnGetEnvironmentVariableCount = function: Integer;
TShowExceptionHandler = Procedure (Const Msg : String);
TUncaughtPascalExceptionHandler = Procedure(aObject : TObject);
TUncaughtJSExceptionHandler = Procedure(aObject : TJSObject);
var var
OnGetEnvironmentVariable: TOnGetEnvironmentVariable; OnGetEnvironmentVariable: TOnGetEnvironmentVariable;
OnGetEnvironmentString: TOnGetEnvironmentString; OnGetEnvironmentString: TOnGetEnvironmentString;
OnGetEnvironmentVariableCount: TOnGetEnvironmentVariableCount; OnGetEnvironmentVariableCount: TOnGetEnvironmentVariableCount;
// Handler to show an exception (used when showexception is called)
OnShowException : TShowExceptionHandler = nil;
// Set handlers for uncaught exceptions. These will call HookUncaughtExceptions
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 was set, the exceptions will be displayed using ShowException.
Procedure HookUncaughtExceptions;
function GetEnvironmentVariable(Const EnvVar: String): String; function GetEnvironmentVariable(Const EnvVar: String): String;
function GetEnvironmentVariableCount: Integer; function GetEnvironmentVariableCount: Integer;
function GetEnvironmentString(Index: Integer): String; function GetEnvironmentString(Index: Integer): String;
procedure ShowException(ExceptObject: TObject; ExceptAddr: Pointer);
procedure ShowException(ExceptObject: TObject; ExceptAddr: Pointer = Nil);
Procedure Abort; Procedure Abort;
{***************************************************************************** {*****************************************************************************
@ -1131,28 +1145,111 @@ Type
implementation implementation
procedure ShowException(ExceptObject: TObject; ExceptAddr: Pointer); { ---------------------------------------------------------------------
Exception handling
---------------------------------------------------------------------}
Resourcestring
SAbortError = 'Operation aborted';
SApplicationException = 'Application raised an exception: ';
SErrUnknownExceptionType = 'Caught unknown exception type : ';
procedure DoShowException(S : String);
begin
if Assigned(OnShowException) then
OnShowException(S)
else
begin
{$IFDEF BROWSER}
asm
window.alert(S);
end;
{$ENDIF}
{$IFDEF NODEJS}
Writeln(S);
{$ENDIF}
end;
end;
procedure ShowException(ExceptObject: TObject; ExceptAddr: Pointer = Nil);
Var Var
S : String; S : String;
begin begin
S:='Application raised an exception '+ExceptObject.ClassName; S:=SApplicationException+ExceptObject.ClassName;
if ExceptObject is Exception then if ExceptObject is Exception then
S:=S+' : '+Exception(ExceptObject).Message; S:=S+' : '+Exception(ExceptObject).Message;
{$IFDEF BROWSER} DoShowException(S);
asm
window.alert(S);
end;
{$ENDIF}
{$IFDEF NODEJS}
Writeln(S);
{$ENDIF}
if ExceptAddr=nil then; if ExceptAddr=nil then;
end; end;
Const Type
SAbortError = 'Operation aborted'; TRTLExceptionHandler = procedure (aError : JSValue);
Var
rtlExceptionHandler : TRTLExceptionHandler; External name 'rtl.onUncaughtException';
rtlShowUncaughtExceptions : Boolean; External name 'rtl.showUncaughtExceptions';
OnPascalException : TUncaughtPascalExceptionHandler;
OnJSException : TUncaughtJSExceptionHandler;
Procedure RTLExceptionHook(aError : JSValue);
Var
S : String;
begin
if isClassInstance(aError) then
begin
if Assigned(OnPascalException) then
OnPascalException(TObject(aError))
else
ShowException(TObject(aError),Nil);
end
else if isObject(aError) then
begin
if Assigned(OnJSException) then
OnJSException(TJSObject(aError))
else
begin
if TJSObject(aError).hasOwnProperty('message') then
S:=SErrUnknownExceptionType+String(TJSObject(aError).Properties['message'])
else
S:=SErrUnknownExceptionType+TJSObject(aError).toString;
DoShowException(S);
end
end
else
begin
S:=SErrUnknownExceptionType+String(aError);
DoShowException(S);
end;
end;
Function SetOnUnCaughtExceptionHandler(aValue : TUncaughtPascalExceptionHandler) : TUncaughtPascalExceptionHandler;
begin
Result:=OnPascalException;
OnPascalException:=aValue;
HookUncaughtExceptions;
end;
Function SetOnUnCaughtExceptionHandler(aValue : TUncaughtJSExceptionHandler) : TUncaughtJSExceptionHandler;
begin
Result:=OnJSException;
OnJSException:=aValue;
HookUncaughtExceptions;
end;
Procedure HookUncaughtExceptions;
begin
rtlExceptionHandler:=@RTLExceptionHook;
rtlShowUncaughtExceptions:=True;
end;
procedure Abort; procedure Abort;
begin begin
@ -1161,6 +1258,7 @@ end;
Type Type
TCharSet = Set of Char; TCharSet = Set of Char;
Function CharInSet(Ch: Char;Const CSet : TCharSet) : Boolean; Function CharInSet(Ch: Char;Const CSet : TCharSet) : Boolean;
begin begin