![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Объект из динамически загружаемой bpl
Slym © (2010-03-26 12:42:00)наткнулся на грабли:
hpkg:=LoadPackage('package.bpl');
try
packageObj.SomeProc;//raised exception TSomeCustomPackageException
finally
UnLoadPackage(hpkg);
end;
//тут AV
оказывается ругается на TSomeCustomPackageException который в другом "подчиненном" пакете и загружается неявно при загрузке моего пакета
как проверить что пакет неявно чтото наплодил? чтоб все это грохнуть и закрыть пакет?
Игорь Шевченко (2010-03-29 17:31:00) [1]Chirockie (29.03.10 09:28) [32]
> PC_MAPPED_EXCEPTIONS определена для Kylix/Linux, а в Delphi/Windows
> она не определена. То есть, процедура ReleaseExceptionObject()
> не делает ничего.
Точно. Спасибо за науку.
ну слава тому, кого нет, нашлось, почему:
"In Win32, AcquireExceptionObject removes the object from the exception
handling system and turns all responsibility for it over to you.
ReleaseExceptionObject is therefore not necessary, so it is an empty
implementation in Win32. It exists only to provide a compatible function
call target for source code compatibility with Linux."
http://qc.embarcadero.com/wc/qcmain.aspx?d=5815
Chirockie (2010-03-29 09:28:00) [2]PC_MAPPED_EXCEPTIONS определена для Kylix/Linux, а в Delphi/Windows она не определена. То есть, процедура ReleaseExceptionObject() не делает ничего.
То есть, комментарий "For this purpose, we have added the AcquireExceptionObject and ReleaseExceptionObject functions. These functions maintain a reference count on the most current exception object, allowing applications to legitimately obtain references"не соответствует действительности. Как в плане того, что ReleaseExceptionObject - не функция (предположим, опечатка или обобщение), так и в плане того, что эта процедура не "maintain a reference count". И, что характерно, AcquireExceptionObject тоже не "maintain a reference count". В контексте Delphi/Windows, конечно.
Ну, или это какой-то очень тайный и печальный Compiler magic. Надеюсь, что это не так.
Игорь Шевченко (2010-03-28 23:47:00) [3]Chirockie (28.03.10 23:11) [29]
Не могу знать про Delphi 6, под рукой есть только 2006 и 2010, код там, похоже одинаковый:
{$IFDEF PC_MAPPED_EXCEPTIONS}
function AcquireExceptionObject: Pointer;
asm
CALL CurrentException
OR EAX, EAX
JE @@Error
INC [EAX].TRaisedException.RefCount
MOV EAX, [EAX].TRaisedException.ExceptObject
RET
@@Error:
RET // windows version doesn't generate an error, and Halt0 calls this always
{ This happens if there is no exception pending }
// JMP _Run0Error
end;
procedure ReleaseExceptionObject;
asm
CALL CurrentException
OR EAX, EAX
JE @@Error
CMP [EAX].TRaisedException.RefCount, 0
JE @@Error
DEC [EAX].TRaisedException.RefCount
RET
@@Error:
{
This happens if there is no exception pending, or
if the reference count on a pending exception is
zero.
}
JMP _Run0Error
end;
{$ELSE !PC_MAPPED_EXCEPTIONS} {not PC_MAPPED_EXCEPTIONS}
function AcquireExceptionObject: Pointer;
type
ExceptionAcquiredProc = procedure (Obj: Pointer);
var
RaiseFrame: PRaiseFrame;
begin
RaiseFrame := RaiseListPtr;
if RaiseFrame <> nil then
begin
Result := RaiseFrame^.ExceptObject;
RaiseFrame^.ExceptObject := nil;
if Assigned(ExceptionAcquired) then
ExceptionAcquiredProc(ExceptionAcquired)(Result);
end
else
Result := nil;
end;
procedure ReleaseExceptionObject;
begin
end;
{$ENDIF !PC_MAPPED_EXCEPTIONS}
Chirockie (2010-03-28 23:14:00) [4]а конструкция автора так и вовсе не скомпилируется
Сразу видно, что автор пользуется неким Абстрактным Языком Описания Обработки Исключений.
:о)
Chirockie (2010-03-28 23:11:00) [5]Как это ничего не делает, очень даже делает
Увы, в Delphi 6 он не делает ничего.
function AcquireExceptionObject: Pointer;
begin
if RaiseListPtr <> nil then
begin
Result := PRaiseFrame(RaiseListPtr)^.ExceptObject;
PRaiseFrame(RaiseListPtr)^.ExceptObject := nil;
end
else
Result := nil;
end;
procedure ReleaseExceptionObject;
begin
end;
Куда смотрит Отдел по борьбе с хищениями объектов исключений?
Игорь Шевченко (2010-03-28 23:06:00) [6]Chirockie (28.03.10 20:33) [20]
Возвращаясь к изначальной точке дискусии:
да, в секции except может встретиться любой класс, не обязательно exception и конструкция if ExceptObject is Exception не равна конструкции if true
например,
try
raise TForm.Create(Self);
except
on E: TForm do
ShowMessage('TForm raised');
end;
а конструкция автора
except
on
if E.ClassType=Exception then
raise
else
raise Exception.Create(e.Message);
end;
так и вовсе не скомпилируется
Игорь Шевченко (2010-03-28 22:56:00) [7]Chirockie (28.03.10 22:34) [26]
> Почему AcquireExceptionObject() возвращает pointer?
Не знаю
> И почему ReleaseExceptionObject() ничего не делает?
Как это ничего не делает, очень даже делает:
procedure ReleaseExceptionObject;
asm
CALL CurrentException
OR EAX, EAX
JE @@Error
CMP [EAX].TRaisedException.RefCount, 0
JE @@Error
DEC [EAX].TRaisedException.RefCount
RET
@@Error:
{
This happens if there is no exception pending, or
if the reference count on a pending exception is
zero.
}
JMP _Run0Error
end;
Chirockie (2010-03-28 22:34:00) [8]>Зря. Стоит посмотреть, как используется поле FFatalException в TThread и почему оно TObject, а не, скажем, Pointer.
Тут все путем.
Вопрос в другом: Почему AcquireExceptionObject() возвращает pointer? И почему ReleaseExceptionObject() ничего не делает?
И еще, что характерно,
TRaiseFrame = packed record
NextRaise: PRaiseFrame;
ExceptAddr: Pointer;
ExceptObject: TObject;// Именно его возвращает (и обнуляет) AcquireExceptionObject()
ExceptionRecord: PExceptionRecord;
end;
Игорь Шевченко (2010-03-28 22:21:00) [9]Chirockie (28.03.10 21:59) [24]
> Не вижу ничего очевидного
Зря. Стоит посмотреть, как используется поле FFatalException в TThread и почему оно TObject, а не, скажем, Pointer.
> А причина, видимо, все же, в том, что объект исключения
> не обязан быть типа Exception.
Не обязан. Следующий код безукоризненно работает.
unit main;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
btnRaiseTObject: TButton;
btnRaiseForm: TButton;
procedure btnRaiseTObjectClick(Sender: TObject);
procedure btnRaiseFormClick(Sender: TObject);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.btnRaiseFormClick(Sender: TObject);
begin
raise TForm.Create(Self);
end;
procedure TForm1.btnRaiseTObjectClick(Sender: TObject);
begin
raise TObject.Create;
end;
end.
Chirockie (2010-03-28 21:59:00) [10]>Очевидно потому
Не вижу ничего очевидного. Согласно приведенного описания, FatalException: Exception можно было бы использовать с тем же успехом. А причина, видимо, все же, в том, что объект исключения не обязан быть типа Exception. Так, кажется, очевиднее.
И что касаемо ReleaseExceptionObject()...
procedure ReleaseExceptionObject;
begin
end;
(C) Borland Delphi 6
>функция AcquireExceptionObject вообще Pointer возвращает
Похоже, потому, что функция эта из модуля System, в котором о class Exception ничего не известно. Хотя, могли бы вернуть TObject. Не понятно.
Игорь Шевченко (2010-03-28 21:21:00) [11]Slym © (28.03.10 20:45) [21]
if E.ClassType=Exception
function TObject.ClassType: TClass;
begin
Pointer(Result) := PPointer(Self)^;
end;
if E is Exception then
function _IsClass(Child: TObject; Parent: TClass): Boolean;
begin
Result := (Child <> nil) and Child.InheritsFrom(Parent);
end;
class function TObject.InheritsFrom(AClass: TClass): Boolean;
var
ClassPtr: TClass;
begin
ClassPtr := Self;
while (ClassPtr <> nil) and (ClassPtr <> AClass) do
ClassPtr := PPointer(Integer(ClassPtr) + vmtParent)^;
Result := ClassPtr = AClass;
end;
Ты точно уверен, что тебе нужен первый вариант ? То есть, если твой загружаемый пакет возбудил не в точности Exception, проверка на ClassType не сработает.
Игорь Шевченко (2010-03-28 21:17:00) [12]Chirockie (28.03.10 20:33) [20]
> Меня всегда интересовало, почему в классе TThread поле FatalException
> имеет тип TObject?
Очевидно потому:
" When an exception is thrown, the exception object that is thrown is destroyed
automatically when the except clause which handles the exception is exited.
There are some cases in which an application may wish to acquire the thrown
object and keep it alive after the except clause is exited. For this purpose,
we have added the AcquireExceptionObject and ReleaseExceptionObject functions.
These functions maintain a reference count on the most current exception object,
allowing applications to legitimately obtain references. If the reference count
for an exception that is being thrown is positive when the except clause is exited,
then the thrown object is not destroyed by the RTL, but assumed to be in control
of the application. It is then the application's responsibility to destroy the
thrown object. If the reference count is zero, then the RTL will destroy the
thrown object when the except clause is exited."
функция AcquireExceptionObject вообще Pointer возвращает :)
Slym (2010-03-28 20:45:00) [13]Игорь Шевченко © (28.03.10 19:25) [19]
if E.ClassType=Exception
как раз
if E is Exception then - и есть if True then
Chirockie (2010-03-28 20:33:00) [14]это нонсенс.
Меня всегда интересовало, почему в классе TThread поле FatalException имеет тип TObject?
:о)
raise TObject.Create; // Ку-ку
В общем, иногда я параноидально пишу:
...
except
on E: Exception do ...;
else // Ку-ку
end;
Игорь Шевченко (2010-03-28 19:25:00) [15]
> if E.ClassType=Exception
это нонсенс. Вместо этой строчки можешь смело написать
if True then
Slym (2010-03-28 18:59:00) [16]Игорь Шевченко © (28.03.10 18:47) [17]
в итоге так и сделано, только вот тип PackageFooException - неизвестен и приходится if E.ClassType=Exception then
Игорь Шевченко (2010-03-28 18:47:00) [17]или так
foo := LoadPackage ('foo');
try
try
package_foo.bar_proc;
except
on E: PackageFooException do
raise EAlwaysKnownException(...
end;
finally
UnloadPackage(foo);
end;
Игорь Шевченко (2010-03-28 18:44:00) [18]Slym © (28.03.10 18:08) [15]
Что подтверждает истинность поста [1]
А вообще Exception-ы передавать за границы динамически загружаемых DLL/пакетов - дурной тон
Slym (2010-03-28 18:08:00) [19]Игорь Шевченко © (28.03.10 18:03) [14]
бывают исключения определенные в динамически загружаемых/выгружаемых модулях и "статические" определенные в статически загруженной rtl
загружен модуль - ESomeException есть
выгружен модуль - ESomeException нет, и raise E (ESomeException) приведет к AV
Игорь Шевченко (2010-03-28 18:03:00) [20]Slym © (28.03.10 17:47) [13]
> Exception - известен
А что, бывают исключения, которые не Exception ?