Calling a Delphi side function from a script that raises an exception raises a generic EDelphi exception on the script side. This hides the exception class of the actual Delphi side exception. I tried to investigate the implementation of the EDelphi Ijaddajadda interface but am lacking skills to see a way to extract the Delphi side class or at least the class name. The truth has to be out there...
Example, script side
Try
MyDelphiSideFunction; // May raise EOutOfmemory
Except on E:Exception do
PrintLn(E.ClassName);
End;
This always prints "EDelphi", no matter the actual Delphi side exception class (EOutOfmemory in this example).
How to get the "real" class or class name from E?
You cannot directly get the exception class type as the DWScript exception handler doesn't store that information anywhere and the Delphi side type wouldn't make sense inside the script anyway. You can however easily get the class name from the EDelphi
script side exception object via the EDelphi.ExceptionClass
property. Like this:
try
var x := 1/0;
except
on E: EDelphi do
WriteLn('Error: ' + E.Message + ' (' + E.ExceptionClass + ')');
on E: Exception do
WriteLn('Error: ' + E.Message);
else
WriteLn('Unknown exception type');
end;
Error: Floating point division by zero (EZeroDivide)
You can see the DWScript source code that transforms a Delphi side exception to a script side EDelphi
exception here:
https://github.com/EricGrange/DWScript/blob/2d61c8a95fb4a2aab328f3cc84bb9f243c927286/Source/dwsExprs.pas#L2244
I simply searched the source on Github (the search on the main Bitbucket repo sucks) for "EDelphi": https://github.com/search?q=repo%3AEricGrange%2FDWScript%20EDelphi&type=code
This gave me this piece of code:
// A Delphi exception. Transform it to a EDelphi-dws exception
exceptObj:=CreateEDelphiObj(mainException.ClassName, mainException.Message);
I then looked at the CreateEDelphiObj
method:
function TdwsProgramExecution.CreateEDelphiObj(const ClassName : String;
const Message : String) : IScriptObj;
begin
Result := IScriptObj(IUnknown(
ProgramInfo.Vars[SYS_EDELPHI].Method[SYS_TOBJECT_CREATE].Call([ClassName, Message]).Value));
(Result.ExternalObject as TdwsExceptionContext).ReplaceTop(LastScriptError); // temporary constructor expression
end;
This looks like a call to a script side constructor, passing the ClassName
and Message
strings as parameters. That's fine, but what happens to the ClassName
value?
Again, looking at the search result I noticed the Delphi side implementation of the EDelphi
constructor:
procedure TDelphiExceptionCreateMethod.Execute(info : TProgramInfo; var ExternalObject: TObject);
begin
inherited;
Info.ValueAsVariant[SYS_EDELPHI_EXCEPTIONCLASS_FIELD]:=Info.ValueAsVariant['Cls']
end;
So the constructor calls the inherited constructor and then stores the ClassName
value in the FExceptionClass
(the value of the SYS_EDELPHI_EXCEPTIONCLASS_FIELD
constant) field.
At this point I could guess that the property would be called ExceptionClass
so I used my DWScriptStudio IDE/debugger to write the example and verify the result.