Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2011.10.30;
Скачать: [xml.tar.bz2];

Вниз

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

 
Slym ©   (2010-03-26 12:42) [0]

наткнулся на грабли:
hpkg:=LoadPackage("package.bpl");
try
 packageObj.SomeProc;//raised exception TSomeCustomPackageException  

finally
 UnLoadPackage(hpkg);
end;
//тут AV

оказывается ругается на TSomeCustomPackageException который в другом "подчиненном" пакете и загружается неявно при загрузке моего пакета
как проверить что пакет неявно чтото наплодил? чтоб все это грохнуть и закрыть пакет?


 
Игорь Шевченко ©   (2010-03-26 12:46) [1]


> как проверить что пакет неявно чтото наплодил?


Пакеты перепроектировать


 
Сергей М. ©   (2010-03-26 13:06) [2]


> как проверить что пакет неявно чтото наплодил?


Вестимо как - использовав встроенный отладчик.


 
Slym ©   (2010-03-26 13:56) [3]

Игорь Шевченко ©   (26.03.10 12:46) [1]
что тут перепроектировать?
хост приложение о коммуникациях ничего не знает
загрузил пакет...
(тут неавная подгрузка IndyProtocols)
выполнил функцию из пакета
(тут исключение EIdSocketError)
закрыл все что явно открыл
выгрузил
(но эксепшн EIdSocketError остался) AV

проблему решил отловом нестандартных исключений и "переформатированием" в стандартные
except
on
 if E.ClassType=Exception then
   raise
 else
   raise Exception.Create(e.Message);
end;


 
Игорь Шевченко ©   (2010-03-26 15:13) [4]


>  if E.ClassType=Exception then


Гы


 
Сергей М. ©   (2010-03-26 15:29) [5]


> Slym ©   (26.03.10 13:56) [3]


Ну ты и загнул с классом исключения)
Курам ведь насмех !)

Игорь вон чуть не упалпацтул" )

А ведь ты вроде и не новичок, чтобы такие смешные ляпы допускать ...


 
Loginov Dmitry ©   (2010-03-27 12:18) [6]


> finally
>  UnLoadPackage(hpkg);
> end;
> //тут AV


А зачем его выгружать? Раз разгрузил - и пусть висит.
Естественно на Finally при нестандартном исключении будет AV, ибо происходит обработка объекта исключения с уже выгруженными из памяти методами.


 
Slym ©   (2010-03-28 12:49) [7]

Игорь Шевченко ©   (26.03.10 15:13) [4]
это в 5 утра писалось, 6 часов убил на локализацию плавающего AV
Сергей М. ©   (26.03.10 15:29) [5]
Ну ты и загнул с классом исключения)

предложи способ отделить известное исключение от неизвестного, находящегося в выгружаемом модуле вот тут:
procedure RaiseException(E:Exception);
begin
 Log(E.Message);
 //if E.ClassName="Exception" then //???
 //if E is Exception then //не канает т.к. все исключения наследованы от Exception
 //if E.ClassType=Exception then
 //неизвестный мне вариант
   raise E
 else
   raise Exception.Create(e.Message);
end;

а кому то и смешно но пока работает :)

Loginov Dmitry ©   (27.03.10 12:18) [6]
выгрузить необходимо


 
Игорь Шевченко ©   (2010-03-28 14:01) [8]


> предложи способ отделить известное исключение от неизвестного,
>  находящегося в выгружаемом модуле вот тут:


if E is известное_исключение then


 
Loginov Dmitry ©   (2010-03-28 15:13) [9]

if E.ClassName = "EIdSocketError" then
 raise Exception.Create(E.Message)
else
 raise;


Не проще ли подключить к EXE и к BPL одни и те же BPL-пакеты с Indy ?


 
Slym ©   (2010-03-28 17:12) [10]

Игорь Шевченко ©   (28.03.10 14:01) [8]
мне на данном этапе известен только базовый Exception
а все остальные в т.ч. и "неизвестные" исключения пролезут в фильтр E is Exception
if E is Exception then //не канает т.к. все исключения наследованы от Exception


 
Slym ©   (2010-03-28 17:17) [11]

Loginov Dmitry ©   (28.03.10 15:13) [9]
метода доступа может смениться, положат длугой БПЛ и нафик не нужны BPL-пакеты Indy
тоже касаемо bpl БД - БД сменится и нафик adortl
приложение скомпилировано с rtl,vcl,dbrtl,ModuleManager - в котором и реализована плагин начинка


 
Игорь Шевченко ©   (2010-03-28 17:18) [12]


> мне на данном этапе известен только базовый Exception


и


> предложи способ отделить известное исключение от неизвестного,
>  


Как-то не вяжется, не правда ли ?


 
Slym ©   (2010-03-28 17:47) [13]

Игорь Шевченко ©   (28.03.10 17:18) [12]
все вяжется:
Exception - известен
type ESomeException=class(Exception) - неизвестен


 
Игорь Шевченко ©   (2010-03-28 18:03) [14]

Slym ©   (28.03.10 17:47) [13]


> Exception - известен


А что, бывают исключения, которые не Exception ?


 
Slym ©   (2010-03-28 18:08) [15]

Игорь Шевченко ©   (28.03.10 18:03) [14]
бывают исключения определенные в динамически загружаемых/выгружаемых модулях и "статические" определенные в статически загруженной rtl
загружен модуль - ESomeException есть
выгружен модуль - ESomeException нет, и raise E (ESomeException) приведет к AV


 
Игорь Шевченко ©   (2010-03-28 18:44) [16]

Slym ©   (28.03.10 18:08) [15]

Что подтверждает истинность поста [1]

А вообще Exception-ы передавать за границы динамически загружаемых DLL/пакетов - дурной тон


 
Игорь Шевченко ©   (2010-03-28 18:47) [17]

или так

foo := LoadPackage ("foo");
try
 try
    package_foo.bar_proc;
 except
    on E: PackageFooException do
      raise EAlwaysKnownException(...
 end;
finally
 UnloadPackage(foo);
end;


 
Slym ©   (2010-03-28 18:59) [18]

Игорь Шевченко ©   (28.03.10 18:47) [17]
в итоге так и сделано, только вот тип PackageFooException - неизвестен и приходится if E.ClassType=Exception then


 
Игорь Шевченко ©   (2010-03-28 19:25) [19]


> if E.ClassType=Exception


это нонсенс. Вместо этой строчки можешь смело написать
if True then


 
Chirockie   (2010-03-28 20:33) [20]

это нонсенс.

Меня всегда интересовало, почему в классе TThread поле FatalException имеет тип TObject?

:о)

raise TObject.Create; // Ку-ку

В общем, иногда я параноидально пишу:

...
except
 on E: Exception do ...;
else // Ку-ку
end;


 
Slym ©   (2010-03-28 20:45) [21]

Игорь Шевченко ©   (28.03.10 19:25) [19]
if E.ClassType=Exception

как раз
if E is Exception then - и есть if True then


 
Игорь Шевченко ©   (2010-03-28 21:17) [22]

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 возвращает :)


 
Игорь Шевченко ©   (2010-03-28 21:21) [23]

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 не сработает.


 
Chirockie   (2010-03-28 21:59) [24]

>Очевидно потому

Не вижу ничего очевидного. Согласно приведенного описания, FatalException: Exception можно было бы использовать с тем же успехом. А причина, видимо, все же, в том, что объект исключения не обязан быть типа Exception. Так, кажется, очевиднее.

И что касаемо ReleaseExceptionObject()...

procedure ReleaseExceptionObject;
begin  
end;

(C) Borland Delphi 6


>функция AcquireExceptionObject вообще Pointer возвращает

Похоже, потому, что функция эта из модуля System, в котором о class Exception ничего не известно. Хотя, могли бы вернуть TObject. Не понятно.


 
Игорь Шевченко ©   (2010-03-28 22:21) [25]

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 22:34) [26]

>Зря. Стоит посмотреть, как используется поле FFatalException в TThread и почему оно TObject, а не, скажем, Pointer.

Тут все путем.

Вопрос в другом: Почему AcquireExceptionObject() возвращает pointer? И почему ReleaseExceptionObject() ничего не делает?

И еще, что характерно,  

TRaiseFrame = packed record
   NextRaise: PRaiseFrame;
   ExceptAddr: Pointer;
   ExceptObject: TObject; // Именно его возвращает (и обнуляет) AcquireExceptionObject()
   ExceptionRecord: PExceptionRecord;
 end;


 
Игорь Шевченко ©   (2010-03-28 22:56) [27]

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;


 
Игорь Шевченко ©   (2010-03-28 23:06) [28]

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;


так и вовсе не скомпилируется


 
Chirockie   (2010-03-28 23:11) [29]

Как это ничего не делает, очень даже делает

Увы, в 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;


Куда смотрит Отдел по борьбе с хищениями объектов исключений?


 
Chirockie   (2010-03-28 23:14) [30]

а конструкция автора так и вовсе не скомпилируется

Сразу видно, что автор пользуется неким Абстрактным Языком Описания Обработки Исключений.

:о)


 
Игорь Шевченко ©   (2010-03-28 23:47) [31]

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-29 09:28) [32]

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-29 17:31) [33]

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



Страницы: 1 вся ветка

Форум: "Основная";
Текущий архив: 2011.10.30;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.55 MB
Время: 0.004 c
2-1309973446
Pcrepair
2011-07-06 21:30
2011.10.30
МЫШЬ drag-drop в аналоге RAdmin


15-1309840625
dxc
2011-07-05 08:37
2011.10.30
биллиардный шар


15-1303845129
plr
2011-04-26 23:12
2011.10.30
user-defined characters в ESC/P принтерах


15-1309984198
Юрий
2011-07-07 00:29
2011.10.30
С днем рождения ! 7 июля 2011 четверг


15-1309527475
Chatnick
2011-07-01 17:37
2011.10.30
Ассоциация ICO-файла с программой.





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский