Вызов боковой функции Delphi из сценария, который вызывает исключение, вызывает общее исключение EDelphi на стороне сценария. Это скрывает класс фактического исключения на стороне Delphi. Я пытался изучить реализацию интерфейса EDelphi Ijaddajadda, но мне не хватает навыков, чтобы увидеть способ извлечь побочный класс Delphi или хотя бы имя класса. Правда должна быть где-то рядом...
Пример, сторона сценария
Try
MyDelphiSideFunction; // May raise EOutOfmemory
Except on E:Exception do
PrintLn(E.ClassName);
End;
При этом всегда печатается «EDelphi», независимо от фактического класса исключений на стороне Delphi (в этом примере EOutOfmemory).
Как получить «настоящий» класс или имя класса из E?


Вы не можете напрямую получить тип класса исключения, поскольку обработчик исключений DWScript нигде не хранит эту информацию, а тип на стороне Delphi в любом случае не будет иметь смысла внутри сценария. Однако вы можете легко получить имя класса из объекта исключения на стороне сценария EDelphi через свойство EDelphi.ExceptionClass. Так:
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)
Вы можете увидеть исходный код DWScript, который преобразует исключение на стороне Delphi в исключение на стороне сценария EDelphi здесь:
https://github.com/EricGrange/DWScript/blob/2d61c8a95fb4a2aab328f3cc84bb9f243c927286/Source/dwsExprs.pas#L2244
Я просто поискал в исходнике на Github (поиск в основном репозитории Bitbucket отстой) по запросу «EDelphi»: https://github.com/search?q=repo%3AEricGrange%2FDWScript%20EDelphi&type=code
Это дало мне этот фрагмент кода:
// A Delphi exception. Transform it to a EDelphi-dws exception
exceptObj:=CreateEDelphiObj(mainException.ClassName, mainException.Message);
Затем я посмотрел на метод CreateEDelphiObj:
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;
Это похоже на вызов конструктора на стороне скрипта с передачей строк ClassName и Message в качестве параметров. Это нормально, но что происходит со значением ClassName?
Опять же, глядя на результат поиска, я заметил реализацию конструктора EDelphi на стороне Delphi:
procedure TDelphiExceptionCreateMethod.Execute(info : TProgramInfo; var ExternalObject: TObject);
begin
inherited;
Info.ValueAsVariant[SYS_EDELPHI_EXCEPTIONCLASS_FIELD]:=Info.ValueAsVariant['Cls']
end;
Таким образом, конструктор вызывает унаследованный конструктор, а затем сохраняет значение ClassName в поле FExceptionClass (значение константы SYS_EDELPHI_EXCEPTIONCLASS_FIELD).
На этом этапе я мог догадаться, что свойство будет называться ExceptionClass, поэтому я использовал свою DWScriptStudio IDE/отладчик, чтобы написать пример и проверить результат.
Я обновил свой ответ, чтобы объяснить, как я нашел свойство ExceptionClass. Что касается INF и исключения, это может быть разница в том, как настроены наши маски исключений, или это может быть следующее: stackoverflow.com/questions/47611635/…
Прекрасное объяснение @AndersMelander. Очень ценю! И ваша DWScript Studio также представляет собой замечательную работу, которую я сейчас рассматриваю. Мне интересно, насколько сложно будет отказаться от этого дорогостоящего DevExpress.
Большинство элементов управления DevExpress имеют соответствующие эквивалентные элементы управления VCL, но некоторые их не имеют (например, TcxTreeList). Ленту можно легко заменить чем-то другим, поскольку вся логика пользовательского интерфейса делегируется действиям. Думаю, самой сложной частью будет система стыковки. Стыковочная система VCL... в лучшем случае проблематична.
Большое спасибо @AndersMelander, это именно то, что я искал. Но где же вы нашли свойство ExceptionClass? Я часами просматривал исходники DWS в поисках чего-то подобного. И даже полный поиск ExceptionClass по всем источникам DWS не дал мне значимого намека. Не могли бы вы меня просветить? Интересный факт: DWS вполне доволен var x := 1/0, разрешая INF. Можно ли это изменить, чтобы вместо этого вызвать исключение?