Форум: "Основная";
Текущий архив: 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=Exceptionfunction TObject.ClassType: TClass;
begin
Pointer(Result) := PPointer(Self)^;
end;
if E is Exception thenfunction _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