Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Объект из динамически загружаемой bpl


Страницы:   1 2

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 ?


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо