Форум: "Начинающим";
Текущий архив: 2010.08.27;
Скачать: [xml.tar.bz2];
ВнизПроцедура вызывает AV Найти похожие ветки
← →
pavel_guzhanov © (2010-04-18 19:36) [0]Вот такой вот код процедуры:
procedure TMainForm.OnClickImage(sender:TObject);
var Name:String[10];
i, j, k, l,m,c, a, x, y, xa, ya:SmallInt;
BitMap, BitMapR : Graphics.TBitMap;
P, PR : PByteArray;
Image1, Image2: TImage;
SL:TStringList;
S:String;
begin
SL:=TStringList.Create;
Name:=TControl(Sender as TImage).Name;
y:=StrToInt(copy(name, 2, 2));
x:=StrToInt(copy(name, 4, 2));
m:=0;
c:=0;
try
if Pan[y, x]<>nil then
SL.Add(String(Pan[y, x].Name))
else
SL.Add("");
while m<=c do
begin
y:=StrToInt(copy(name, 2, 2));
x:=StrToInt(copy(name, 4, 2));
for k:=1 to 4 do
begin
case k of
1:begin
xa:=x+1;
ya:=y;
end;
2:begin
xa:=x;
ya:=y+1;
end;
3:begin
xa:=x-1;
ya:=y;
end;
4:begin
xa:=x;
ya:=y-1;
end;
end; //case
if (xa<1) or (ya<1) or (xa>18) or (ya>12) or (Pan[yA,xA]=nil) then
continue;
Image1:=Pan[y, x];
Image2:=Pan[ya, xa];
BitMap:=Image1.Picture.Bitmap;
BitMapR:=Image2.Picture.Bitmap;
for i:=0 to Bitmap.Height - 1 do
begin
P := Bitmap.ScanLine[i];
PR:=BitMapR.ScanLine[i];
if not CompareMem(p, pr, BitMap.Width) then
begin
j:=i;
Break;
end;//if not
j:=i;
end;//for i
if j=Bitmap.Height - 1 then
begin
a:=0;
for l:=0 to SL.Count-1 do
begin
if String(Pan[ya, xa].Name)=SL.Strings[l] then
begin
a:=l;
break;
end; //if string
a:=l;
end;// for l
if a=SL.Count-1 then
SL.Add(String(Pan[ya, xa].Name));
c:=SL.Count;
end; //if j
if (SL.Count>1) and (m<c) then
begin
name:=SL.Strings[m];
end;// if sl.count and
S:="";
for l:=0 to SL.Count-1 do
begin
S:=S+SL.Strings[l];
end; //for l
end; //for k
inc(m);
end; //while
for l:=0 to SL.Count-1 do
begin
if sl.Count>1 then
begin
y:=StrToInt(copy(SL.Strings[l], 2, 2));
x:=StrToInt(copy(SL.Strings[l], 4, 2));
pan[y,x].Free;
pan[y,x]:=nil;
end;// if sl.count
end; //for l
for i := 0 to 11 do
begin
for j:=0 to 17 do
begin
if pan[i+1, j+1]<>nil then
pan[i+1,j+1].Parent:=Panel1;
end; //for j
end; //for i
finally
SL.Destroy;
end;
end;
Все отрабатывает правильно. Но... При пошаговой отладке, после секции finally по клавише F7 попадаю на end; который закрывает процедуру. А после него вылетает AV. Подскажите пожалуйста, откуда AV и как с ним бороться?
← →
YurikGL © (2010-04-18 19:47) [1]может после end-а еще что то выполняется?
← →
Anatoly Podgoretsky © (2010-04-18 19:53) [2]> pavel_guzhanov (18.04.2010 19:36:00) [0]
Включи контроль диапазонов, а заодно и переполнения. Потом отпишись.
← →
Anatoly Podgoretsky © (2010-04-18 19:54) [3]> YurikGL (18.04.2010 19:47:01) [1]
Можешь не сомневаться, исполняется множество обработчиков.
← →
pavel_guzhanov © (2010-04-18 20:03) [4]
> Включи контроль диапазонов, а заодно и переполнения
Я конечно извиняюсь за глупый вопрос, но как их включить?
← →
YurikGL © (2010-04-18 20:23) [5]
> контроль диапазонов, а заодно и переполнения
идешь в самое начало кода, нажимаешь ctrl+o+o и потом читаешь тут
http://www.delphisources.ru/pages/faq/base/compiler_directives.html
или тут http://www.delphibasics.ru/1Compiler-directives.php
← →
Anatoly Podgoretsky © (2010-04-18 20:30) [6]> pavel_guzhanov (18.04.2010 20:03:04) [4]
Взгляни настройки проекта.
← →
pavel_guzhanov © (2010-04-18 20:47) [7]Включил. Легче не стало. Получаю следующую информацию:
Project ***.exe raised exception class EAccessViolation with message "Access violation at address 00403375 in module "***.exe". Read of address 00000028". Process stopped. Use Step or Run to continue.
После нажатия OK приложение не падает, а продолжает работать. При повторном выполнении процедуры такая же ошибка, только адреса отличаются.
← →
YurikGL © (2010-04-18 20:53) [8]
> pavel_guzhanov © (18.04.10 20:47) [7]
Судя по ошибке - обращение к несуществующему (несозданному) объекту....
← →
pavel_guzhanov © (2010-04-18 21:08) [9]а как определить, к какому объекту обращается? После завершающего end"а сразу вылетает AV.
← →
YurikGL © (2010-04-18 21:18) [10]
> pan[y,x].Free;
Оно потом нигде не используется? В какой-нибудь перерисовке...
← →
_Юрий © (2010-04-18 21:19) [11]Можно подключить FastMem в качестве менеджера памяти, и включить в его настройках подробный вывод информации.
← →
pavel_guzhanov © (2010-04-18 21:35) [12]
> Оно потом нигде не используется?
Используется. Но с проверкой на nil:
> for i := 0 to 11 do
> begin
> for j:=0 to 17 do
> begin
> if pan[i+1, j+1]<>nil then
> pan[i+1,j+1].Parent:=Panel1;
> end; //for j
> end; //for i
Больше нигде не используется.
← →
Anatoly Podgoretsky © (2010-04-18 21:45) [13]> pavel_guzhanov (18.04.2010 20:47:07) [7]
Не создан объект, ищи какой, можно попытаться найти строку с адресом 00403375
← →
Anatoly Podgoretsky © (2010-04-18 21:50) [14]
> Больше нигде не используется.
Верится с трудом, это же глобальная переменная или поле класса. Об объявление которой, ты скромно молчишь.
← →
Игорь Шевченко © (2010-04-18 21:53) [15]Delphi в момент исключения показывает стек вызовов, если кнопку Break нажать...
← →
Демо © (2010-04-18 21:55) [16]Подозрительны пара мест.
P := Bitmap.ScanLine[i];
PR:=BitMapR.ScanLine[i];
Здесь нет утечки памяти?
иpan[y,x].Free;
pan[y,x]:=nil;
А pan[y,x] больше нигде не используется?
Нет ли назначенной процедуры-обработчика на эти pan[x,y] ?
← →
Loginov Dmitry © (2010-04-19 00:22) [17]
> При пошаговой отладке, после секции finally по клавише F7
> попадаю на end; который закрывает процедуру. А после него
> вылетает AV. Подскажите пожалуйста, откуда AV и как с ним
> бороться?
>
Правильно делает, что попадает в finally, а ошибку выдает уже в самом конце.
В данном примере нужно просто выяснить на какой именно строке происходит AV.
Можно каждую строчку завернуть в TRY..EXCEPT и логгировать ошибки. Где-то должна вылезти.
> Подозрительны пара мест.
>
> P := Bitmap.ScanLine[i];
> PR:=BitMapR.ScanLine[i];
Хорошо, если Height у обоих одинаковый.
У меня больше подозрение вызывает такое место:if not CompareMem(P, PR, BitMap.Width) then
(но если пиксели действительно кодируются 1-м байтом, то шут с ними)
> finally
> SL.Destroy;
> end;
Чем Free не устраивает?
← →
Anatoly Podgoretsky © (2010-04-19 00:26) [18]> Loginov Dmitry (19.04.2010 00:22:17) [17]
Тем что работает без ошибок, а у Destroy есть такая возможность.
← →
jack128_ (2010-04-19 16:18) [19]
> Чем Free не устраивает?
а чем Destroy не устраивает? Или FreeAndNil ?
← →
_Юрий © (2010-04-19 19:10) [20]
> а чем Destroy не устраивает? Или FreeAndNil ?
FreeAndNil для данного случая вызывает две лишние операции (присвоение nil переменной, которая больше не используется, проверка на nil переменной, которая не может быть nil"ом в данном случае в принципе),
а Free - всего одну лишнюю операцию (проверка на nil того, что nil"ом быть не может)
Так что Free тут лучше, чем FreeAndNil
← →
pavel_guzhanov © (2010-04-19 20:17) [21]убрал try - finally - end. Все равно после SL.Destroy (на этой строке ставлю брекпоинт) по F7 перехожу на end, а после него AV.
Изменение SL.Destroy на SL.Free ничего не изменило.
← →
_Юрий © (2010-04-19 21:19) [22]Стек вызовов посмотреть было бы не лишним.
Что еще можно сделать - собрать с включенной галкой "Use Debug DCU"s"
Вероятно, информации о случившемся будет больше
← →
Loginov Dmitry © (2010-04-20 00:28) [23]
> а чем Destroy не устраивает?
F1: Do not call Destroy directly. Use the Free method.
← →
DVM © (2010-04-20 00:43) [24]
> Игорь Шевченко © (18.04.10 21:53) [15]
> Delphi в момент исключения показывает стек вызовов, если
> кнопку Break нажать...
Какой такой стек, когда есть прекрасный сервис по удаленной отладке программ http://delphimaster.ru/cgi-bin/forum.pl
← →
Германн © (2010-04-20 00:58) [25]
> Какой такой стек, когда есть прекрасный сервис по удаленной
> отладке программ http://delphimaster.ru/cgi-bin/forum.pl
Уж очень тормозной этот сервис!
← →
jack128_ (2010-04-20 10:29) [26]
> F1: Do not call Destroy directly. Use the Free method.
что то я в хелпе от 2007ой дельфи не могу найти эту фразу. Значит в этой версии - можно Destroy юзать??
← →
jack128_ (2010-04-20 10:30) [27]
> что то я в хелпе от 2007ой дельфи не могу найти эту фразу.
> Значит в этой версии - можно Destroy юзать??
а, нашел. Тогда ладно.
← →
pavel_guzhanov © (2010-04-24 17:06) [28]Включил дебаг DCU. Падает вот в этом куске файла System на выделенной строке:
@@haveVMT:
MOV EDI,[ESI].vmtDynamicTable
TEST EDI,EDI
JE @@parent
MOVZX ECX,word ptr [EDI]
PUSH ECX
ADD EDI,2
REPNE SCASW
JE @@found
POP ECX
Что сие обозначает, я не знаю :о(
← →
pavel_guzhanov © (2010-04-24 17:10) [29]это процедура
procedure GetDynaMethod;
{ function GetDynaMethod(vmt: TClass; selector: Smallint) : Pointer; }
asm
{ -> EAX vmt of class }
{ SI dynamic method index }
{ <- ESI pointer to routine }
{ ZF = 0 if found }
{ trashes: EAX, ECX }
PUSH EDI
XCHG EAX,ESI
JMP @@haveVMT
@@outerLoop:
MOV ESI,[ESI]
@@haveVMT:
MOV EDI,[ESI].vmtDynamicTable
TEST EDI,EDI
JE @@parent
MOVZX ECX,word ptr [EDI]
PUSH ECX
ADD EDI,2
REPNE SCASW
JE @@found
POP ECX
@@parent:
MOV ESI,[ESI].vmtParent
TEST ESI,ESI
JNE @@outerLoop
JMP @@exit
@@found:
POP EAX
ADD EAX,EAX
SUB EAX,ECX { this will always clear the Z-flag ! }
MOV ESI,[EDI+EAX*2-4]
@@exit:
POP EDI
end;
← →
sniknik © (2010-04-24 17:23) [30]> Подозрительны пара мест.
нашел еще ...procedure TMainForm.OnClickImage(sender:TObject);
странное название... похоже получено не "стандартно" кликом на имидж, "обозвано" специально... зачем? возможно делана одна отдельная процедура, чтобы присваивать обработчикам многих динамически созданных иммеджей (массиву, которым рулит эта самая процедура (???)).
если так, и если это те самые которые после внутри процедуры удаляются... то стоит ли удивляться AV?
← →
Anatoly Podgoretsky © (2010-04-24 18:47) [31]> pavel_guzhanov (24.04.2010 17:06:28) [28]
Ну и зачем тогда туда лезешь?
← →
Дмитрий Белькевич (2010-04-25 00:24) [32]
> После завершающего end"а сразу вылетает AV.
Если валится на end"ах, обычно это признак порушенного стёка. Например, неверным вызовом сторонних функций из длл.
← →
jack128_ (2010-04-25 23:52) [33]Павел, ты б к Юрий © [11] прислушал бы.
← →
pavel_guzhanov © (2010-04-26 20:17) [34]А можно ли перед удалением компонента из массива также сделать, чтобы за компонентом не осталось никаких процедур? Если можно, то как?
Пробую сделать так:TImage(pan[y,x]).OnClick:=nil;
pan[y,x].Free;
pan[y,x]:=nil;
но на первой строке опять получаю AV
← →
sniknik © (2010-04-26 20:42) [35]посмотри на TForm.Release; в генофонде. как думаешь зачем так сделали?
← →
sniknik © (2010-04-26 20:46) [36]> чтобы за компонентом не осталось никаких процедур?
причем здесь "не осталось"? дело не в том чтобы не осталось, а в том чтобы не выполнялся код у "призрака", а код никуда не денется если ты его объект из него же и "грохаешь".
← →
Leonid Troyanovsky © (2010-04-26 21:26) [37]
> sniknik © (26.04.10 20:42) [35]
> посмотри на TForm.Release; в генофонде. как думаешь зачем
> так сделали?
[Антидидактическое] От отчаяния? :)
--
Regards, LVT.
← →
Игорь Шевченко © (2010-04-26 21:30) [38]Паша, у тебя ошибка в другом месте. Которое ты не привел. А зря.
← →
Leonid Troyanovsky © (2010-04-26 21:37) [39]
> Игорь Шевченко © (26.04.10 21:30) [38]
> А зря.
Каждый волен заблуждаться в меру своих заблуждений.
У нас свободная страна ;)
--
Regards, LVT.
← →
pavel_guzhanov © (2010-04-26 21:41) [40]
> у тебя ошибка в другом месте
Вот код MainFormUnit.pas:unit MainFormUnit;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls, Math;
type
TMainForm = class(TForm)
Panel1: TPanel;
Button1: TButton;
procedure OnClickImage(sender:TObject);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
Pan:array [1..12, 1..18] of TImage;
end;
var
MainForm: TMainForm;
implementation
{$R *.dfm}
procedure TMainForm.Button1Click(Sender: TObject);
var New:TImage;
i, j: Integer;
x,y:String[2];
begin
for i := 0 to 11 do
begin
for j:=0 to 17 do
begin
pan[i+1,j+1].Free;
pan[i+1,j+1]:=nil;
end; //for j
end; //for i
try
Randomize;
for I := 0 to 11 do
begin
for j:=0 to 17 do
begin
new:=TImage.Create(Panel1);
New.Height:=25;
New.Width:=25;
New.Top:=i*25;
New.Left:=j*25;
if length(intToStr(j+1))<2 then
x:="0"+intToStr(j+1)
else
x:=intToStr(j+1);
if length(intToStr(i+1))<2 then
y:="0"+intToStr(i+1)
else
y:=intToStr(i+1);
New.Name:="B"+ y+x;
new.Stretch:=true;
TImage(New).OnClick:=OnClickImage;
case Random(5) of
0:New.Picture.LoadFromFile("0.bmp");
1:New.Picture.LoadFromFile("1.bmp");
2:New.Picture.LoadFromFile("2.bmp");
3:New.Picture.LoadFromFile("3.bmp");
4:New.Picture.LoadFromFile("4.bmp");
5:New.Picture.LoadFromFile("5.bmp");
end;
New.Canvas.Brush.Style:=bsDiagCross;
pan[i+1,j+1]:=new;
pan[i+1,j+1].Parent:=Panel1;
end;
end;
except
ShowMessage(pan[i,j].Name);
end;
end;
procedure TMainForm.OnClickImage(sender:TObject);
var Name:String[10];
i, j, k, l,m,c, a, x, y, xa, ya:SmallInt;
BitMap, BitMapR : Graphics.TBitMap;
P, PR : PByteArray;
Image1, Image2: TImage;
SL:TStringList;
S:String;
begin
SL:=TStringList.Create;
Name:=TControl(Sender as TImage).Name;
y:=StrToInt(copy(name, 2, 2));
x:=StrToInt(copy(name, 4, 2));
m:=0;
c:=0;
try
if Pan[y, x]<>nil then
SL.Add(String(Pan[y, x].Name))
else
SL.Add("");
while m<=c do
begin
y:=StrToInt(copy(name, 2, 2));
x:=StrToInt(copy(name, 4, 2));
for k:=1 to 4 do
begin
case k of
1:begin
xa:=x+1;
ya:=y;
end;
2:begin
xa:=x;
ya:=y+1;
end;
3:begin
xa:=x-1;
ya:=y;
end;
4:begin
xa:=x;
ya:=y-1;
end;
end; //case
if (xa<1) or (ya<1) or (xa>18) or (ya>12) or (Pan[yA,xA]=nil) then
continue;
Image1:=Pan[y, x];
Image2:=Pan[ya, xa];
BitMap:=Image1.Picture.Bitmap;
BitMapR:=Image2.Picture.Bitmap;
for i:=0 to Bitmap.Height - 1 do
begin
P := Bitmap.ScanLine[i];
PR:=BitMapR.ScanLine[i];
if not CompareMem(p, pr, BitMap.Width) then
begin
j:=i;
Break; // íå ñîâïàäàþò
end;//if not
j:=i;
end;//for i
if j=Bitmap.Height - 1 then // ñîâïàäàþò
begin
a:=0;
// Ïðîâåðêà , åñòü ëè â ñòðèíãëèñòå óæå òàêàÿ çàïèñü
for l:=0 to SL.Count-1 do
begin
if String(Pan[ya, xa].Name)=SL.Strings[l] then
begin
a:=l;
break;
end; //if string
a:=l;
end;// for l
// Åñëè çàïèñè íåò, òî äîáàâëÿåì íîâóþ çàïèñü â ñòðèíãëèñò
if a=SL.Count-1 then // åñëè à ðàâíà êîëè÷åñòâó çàïèñåé â ñòðèíãëèñòå
//çíà÷èò òàêîãî èìåíè â ñòðèíãëèñòå íåò
SL.Add(String(Pan[ya, xa].Name));
c:=SL.Count;
end; //if j
if (SL.Count>1) and (m<c) then
begin
name:=SL.Strings[m];
end;// if sl.count and
S:="";
for l:=0 to SL.Count-1 do
begin
S:=S+SL.Strings[l];
end; //for l
end; //for k
inc(m);
end; //while
for l:=0 to SL.Count-1 do
begin
if sl.Count>1 then
begin
y:=StrToInt(copy(SL.Strings[l], 2, 2));
x:=StrToInt(copy(SL.Strings[l], 4, 2));
TImage(pan[y,x]).OnClick:=nil;
pan[y,x].Free;
pan[y,x]:=nil;
end;// if sl.count
end; //for l
for i := 0 to 11 do
begin
for j:=0 to 17 do
begin
if pan[i+1, j+1]<>nil then
pan[i+1,j+1].Parent:=Panel1;
end; //for j
end; //for i
finally
SL.Free;
end;
end;
end.
Вот код Project1.dpr:program Project1;
uses
Forms,
MainFormUnit in "MainFormUnit.pas" {MainForm};
{$R *.res}
begin
Application.Initialize;
Application.CreateForm(TMainForm, MainForm);
Application.Run;
end.
Другого кода нет.
← →
Игорь Шевченко © (2010-04-26 22:42) [41]new:=TImage.Create(Panel1);
//Вот здесь надо Parent присвоить
New.Height:=25;
New.Width:=25;
New.Top:=i*25;
New.Left:=j*25;
а не здесь
pan[i+1,j+1].Parent:=Panel1;
> for i := 0 to 11 do
> begin
> for j:=0 to 17 do
> begin
> if pan[i+1, j+1]<>nil then
> pan[i+1,j+1].Parent:=Panel1;
> end; //for j
> end; //for i
А это нафиг ?
> if sl.Count>1 then
> begin
> y:=StrToInt(copy(SL.Strings[l], 2, 2));
> x:=StrToInt(copy(SL.Strings[l], 4, 2));
> TImage(pan[y,x]).OnClick:=nil;
> pan[y,x].Free;
> pan[y,x]:=nil;
> end;// if sl.count
ты здесь с координатами не ошибаешься ? в смысле х с у не путаешь ?
вообще плохой код. Ты его причеши, потом выложи. А может в процессе причесывания сам найдешь путаницу
← →
sniknik © (2010-04-26 23:13) [42]pavel_guzhanov © (26.04.10 21:41) [40]
>> у тебя ошибка в другом месте
не верь, главная в том про что говорил.
вот, для пробы, замени это
TImage(pan[y,x]).OnClick:=nil;
pan[y,x].Free;
pan[y,x]:=nil;
на
pan[y,x].Visible:= false;
AV исчезнет. нельзя так удалять, из обработчика свой объект.
← →
sniknik © (2010-04-26 23:28) [43]> замени это ... на
или на
if Sender <> pan[y,x] then begin
//TImage(pan[y,x]).OnClick:=nil;
pan[y,x].Free;
pan[y,x]:= nil;
end;
чтобы были удаления, но не было AV (сразу очевидно какое к нему приводит)
← →
Игорь Шевченко © (2010-04-27 00:31) [44]
> AV исчезнет. нельзя так удалять, из обработчика свой объект.unit main;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
FButton: TButton;
procedure ButtonClick(Sender: TObject);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.ButtonClick(Sender: TObject);
begin
Sender.Free;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
FButton := TButton.Create(Self);
FButton.Parent := Self;
FButton.Top := 20;
FButton.Left := 20;
FButton.Caption := "Click me";
FButton.OnClick := ButtonClick;
end;
end.
← →
DVM © (2010-04-27 00:36) [45]
> Игорь Шевченко © (27.04.10 00:31) [44]
>
Стоит положить кнопку не на форму, а на панель, как этот метод перестанет работать.
← →
Игорь Шевченко © (2010-04-27 00:48) [46]DVM © (27.04.10 00:36) [45]
unit main;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls;
type
TForm1 = class(TForm)
Panel1: TPanel;
procedure FormCreate(Sender: TObject);
private
FButton: TButton;
procedure ButtonClick(Sender: TObject);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.ButtonClick(Sender: TObject);
begin
Sender.Free;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
FButton := TButton.Create(Panel1);
FButton.Parent := Panel1;
FButton.Top := 20;
FButton.Left := 20;
FButton.Caption := "Click me";
FButton.OnClick := ButtonClick;
end;
end.
← →
sniknik © (2010-04-27 00:50) [47]Игорь Шевченко © (27.04.10 00:31) [44]
AV
D7, XP
> Стоит положить кнопку не на форму, а на панель, как этот метод перестанет работать.
в таком виде тоже не работает.
← →
sniknik © (2010-04-27 00:54) [48]может в следующих версиях дельфи и сделали удаление через событие (реальное в основном цикле выборки, по типу Release у форм), но в D7 это не так.
версию нужно уточнять.
← →
Игорь Шевченко © (2010-04-27 01:02) [49]sniknik © (27.04.10 00:50) [47]
Turbo Delphi 2006, Windows XP SP3
А что там уточнять ?procedure TForm1.ButtonClick(Sender: TObject);
mov eax,edx
call TObject.Free
ret
end;destructor TWinControl.Destroy;
var
I: Integer;
Instance: TControl;
begin
Destroying;
if FDockSite then
begin
FDockSite := False;
RegisterDockSite(Self, False);
end;
FDockManager := nil;
FDockClients.Free;
if Parent <> nil then RemoveFocus(True);
if FHandle <> 0 then DestroyWindowHandle;
I := ControlCount;
while I <> 0 do
begin
Instance := Controls[I - 1];
Remove(Instance);
Instance.Destroy;
I := ControlCount;
end;
FBrush.Free;
if FObjectInstance <> nil then Classes.FreeObjectInstance(FObjectInstance);
FPadding.Free;
inherited Destroy;
end;destructor TControl.Destroy;
begin
Application.ControlDestroyed(Self);
if (FHostDockSite <> nil) and not (csDestroying in FHostDockSite.ComponentState) then
begin
FHostDockSite.RemoveFreeNotification(Self);
FHostDockSite.Perform(CM_UNDOCKCLIENT, 0, Integer(Self));
SetParent(nil);
Dock(NullDockSite, BoundsRect);
FHostDockSite := nil;
end else
SetParent(nil);
FActionLink.Free;
FActionLink := nil;
FConstraints.Free;
FFont.Free;
StrDispose(FText);
FMargins.Free;
inherited Destroy;
end;destructor TComponent.Destroy;
begin
Destroying;
if FFreeNotifies <> nil then
begin
while Assigned(FFreeNotifies) and (FFreeNotifies.Count > 0) do
TComponent(FFreeNotifies[FFreeNotifies.Count - 1]).Notification(Self, opRemove);
FreeAndNil(FFreeNotifies);
end;
DestroyComponents;
if FOwner <> nil then FOwner.RemoveComponent(Self);
inherited Destroy;
end;
Где что не так ?
← →
sniknik © (2010-04-27 01:20) [50]> А что там уточнять ?
версию дельфи нужно уточнять, когда говоришь "а у меня так работает".
> Где что не так ?
Turbo Delphi 2006, Windows XP SP3
> Процедура вызывает AV [D7, XP]
проверь свой пример на D7.
← →
Игорь Шевченко © (2010-04-27 01:23) [51]sniknik © (27.04.10 01:20) [50]
> проверь свой пример на D7.
Подари - проверю.
Я привел код деструкторов, сравни со своим, если есть отличия, давай посмотрим.
Кроме всего прочего, ты в D7 можешь узнать (и выложить в форум) именно то место, где происходит AV (и почему).
← →
sniknik © (2010-04-27 01:32) [52]> Я привел код деструкторов
а я высказывал подозрения в различиях во Free
> может в следующих версиях дельфи и сделали удаление через событие (реальное в основном цикле выборки, по типу Release у форм), но в D7 это не так.
вот ответь сам на заданный автору вопрос
> посмотри на TForm.Release; в генофонде. как думаешь зачем так сделали?
еще как вариант цикл выборки сообщений, возможно, каким то боком.
так зачем сравнивать деструкторы?
> где происходит AV (и почему).
вот чего я точно не хочу делать, так это выяснять почему только для того чтобы что то доказать тебе, то что это не работает в D7. хочешь проверь, хочешь прими как данность, хочешь не верь. мне пофигу.
← →
Германн © (2010-04-27 02:02) [53]
> Игорь Шевченко © (27.04.10 01:23) [51]
>
> sniknik © (27.04.10 01:20) [50]
>
>
> > проверь свой пример на D7.
>
>
> Подари - проверю.
Так зачем тогда на форме ввода вопроса на ДМ создана возможность указания версии Дельфи?
Игорь, это перебор, имхо.
← →
Игорь Шевченко © (2010-04-27 10:36) [54]sniknik © (27.04.10 01:32) [52]
> а я высказывал подозрения
Ты следователь ? Или у тебя Delphi тоже полевого, облегченного образца, без исходников ?
Раз у тебя происходит AV в моем примере, ну так покажи, в каком оно месте происходит. Проще ж некуда.
← →
Игорь Шевченко © (2010-04-27 10:58) [55]На Delphi 2010 под Win7 64 мой код тоже не вызывает AV. Других версий Delphi у меня нету. Если у кого будет желание, протрассируйте код на младших версиях и выложите результат.
Проект простprogram KillComponentfromEventHandler;
uses
Forms,
main in "main.pas" {Form1};
{$R *.res}
begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.object Form1: TForm1
Left = 0
Top = 0
Caption = "Form1"
ClientHeight = 293
ClientWidth = 426
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = "Tahoma"
Font.Style = []
OldCreateOrder = False
OnCreate = FormCreate
PixelsPerInch = 96
TextHeight = 13
object Panel1: TPanel
Left = 60
Top = 40
Width = 301
Height = 185
Caption = "Panel1"
TabOrder = 0
end
endunit main;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls;
type
TForm1 = class(TForm)
Panel1: TPanel;
procedure FormCreate(Sender: TObject);
private
FButton: TButton;
procedure ButtonClick(Sender: TObject);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.ButtonClick(Sender: TObject);
begin
Sender.Free;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
FButton := TButton.Create(Panel1);
FButton.Parent := Panel1;
FButton.Top := 20;
FButton.Left := 20;
FButton.Caption := "Click me";
FButton.OnClick := ButtonClick;
end;
end.
← →
{RASkov} © (2010-04-27 11:18) [56]> [55] Игорь Шевченко © (27.04.10 10:58)
[D7] [WinXP Pro]
Результат:
---------------------------
Debugger Exception Notification
---------------------------
Project KillComponentfromEventHandler.exe raised exception class EAccessViolation with message "Access violation at address 004032B8 in module "KillComponentfromEventHandler.exe". Read of address 0014D000". Process stopped. Use Step or Run to continue.
---------------------------
OK Help
---------------------------
← →
sniknik © (2010-04-27 12:10) [57]> Ты следователь ? Или у тебя Delphi тоже полевого, облегченного образца, без исходников ?
я человек обладающий здравым смыслом, и логикой (возможно немного извращенной...)
смотреть в исходники в "указанную тобой сторону" не вижу смысла, говорил то я про другое, подозрения(/догадки в изменении работы) высказывал тоже про другое. + ведешь себя так будто тебе должны доказывать, причем "доказательства" предлагаешь искать "там где светлее", т.е. там где ты их решил искать, невзирая на мои слова.
имхо, дело безнадежное.
> Раз у тебя происходит AV в моем примере, ну так покажи, в каком оно месте происходит. Проще ж некуда.
раз у тебя не происходит AV от Free в своих обработчиках, покажи его реализацию, ну и реализацию Release у форм, т.е. то где возможны отличия. проще ж некуда.
← →
Игорь Шевченко © (2010-04-27 12:33) [58]sniknik © (27.04.10 12:10) [57]
> раз у тебя не происходит AV от Free в своих обработчиках,
> покажи его реализацию
в посте [49] я показал. Чего-то недостаточно ?
{RASkov} © (27.04.10 11:18) [56]
Ну и ? Место-то где ? Или ты полагаешь, что во всех версиях Delphi модули располгаются по одинаковым адресам ? Я тебя разочарую - это не так.
← →
12 © (2010-04-27 14:21) [59]
> Игорь Шевченко © (27.04.10 10:58) [55]
D7 XP
AV
ставлю галку CPU, нажимаю ОК, yажимаю F7
TWinControl.MainWndProc
call FreeDeviceContexts
← →
Leonid Troyanovsky © (2010-04-27 18:53) [60]
> Игорь Шевченко © (27.04.10 00:48) [46]
---------------------------
Debugger Exception Notification
---------------------------
Project Project2.exe raised exception class EAccessViolation with message "Access violation at address 0040367D in module "Project2.exe". Read of address 00000018". Process stopped. Use Step or Run to continue.
---------------------------
OK Help
---------------------------
XP SP3 & D6
Лень искать в чьем оно модуле, бо подход крив по определению.
И обсуждалось подобное не раз, чудес не было, только "свезло/не свезло".
В любом случае, в любой, IMHO, версии достаточно добавить после Sender.Free;
ShowMessage(""); // это ж никак не обращение к полям фантома?
и AV неизбежен.
Ну не должен нормальный код содержать подобные кунштюки.
Ведь знаешь ;)
--
Regards, LVT.
← →
sniknik © (2010-04-27 19:31) [61]> в посте [49] я показал. Чего-то недостаточно ?
сам ищи там где светлее, а я, если буду, только там где "потерял"... - реализация Free/ Release у форм. хоть весь оставшийся генофонд сюда скопипасть.
← →
Leonid Troyanovsky © (2010-04-27 19:39) [62]
> sniknik © (27.04.10 19:31) [61]
> "потерял"... - реализация Free/ Release у форм. хоть весь
По-взрослому, Releasе - тоже костыль.
Но, подзащитный лишь пару раз с ним согрешил :)
--
Regards, LVT.
← →
Игорь Шевченко © (2010-04-27 20:24) [63]Leonid Troyanovsky © (27.04.10 18:53) [60]
> В любом случае, в любой, IMHO, версии достаточно добавить
> после Sender.Free;
> ShowMessage(""); // это ж никак не обращение к полям фантома?
>
> и AV неизбежен.
Подвело тебя твое ИМНОprocedure TForm1.ButtonClick(Sender: TObject);
begin
Sender.Free;
ShowMessage("");
end;
работает. Turbo Delphi 2006
> Ну не должен нормальный код содержать подобные кунштюки.
>
> Ведь знаешь ;)
Марксизм не догма, а руководство к действию.
Ведь знаешь ? :)
Я вот в упор не вижу причины, по которой в обработчике события надо обращатся после выполнения собственно обработчика к полям/методам инициатора события.
Сам метод обработчика живет в неудаляемом классе, так что аналогия с Release здесь никаким боком не подходит. И кстати, Release, как ни странно, тоже вызывает Free в обработчике события. Правда, события от сообщения.
← →
Игорь Шевченко © (2010-04-27 20:30) [64]sniknik © (27.04.10 19:31) [61]
> сам ищи там где светлее, а я, если буду, только там где
> "потерял"...
А у меня нету AV, мне нечего искать. Понял ?
← →
Leonid Troyanovsky © (2010-04-27 21:34) [65]
> Игорь Шевченко © (27.04.10 20:24) [63]
> работает. Turbo Delphi 2006
Свезло.
--
Regards, LVT.
← →
Игорь Шевченко © (2010-04-27 21:41) [66]Leonid Troyanovsky © (27.04.10 21:34) [65]
Есть у меня стойкое ощущение, что часть догм перестала ими быть.
Нес па ?
Могу конечно и ошибаться, но факт - вещь упрямая.
← →
Leonid Troyanovsky © (2010-04-27 21:53) [67]
> Игорь Шевченко © (27.04.10 20:24) [63]
С необходимыми и достаточными условиями?
And все версии?
А накуа ж это сомнительное удовольствие?
--
Regards, LVT.
← →
Leonid Troyanovsky © (2010-04-27 22:04) [68]
> Игорь Шевченко © (27.04.10 21:41) [66]
> Могу конечно и ошибаться, но факт - вещь упрямая.
Завтра испытаю на Turbo Delphi 2006, доложусь.
Хотя, это и не снимает ответственности с других.
Будет/не будет - код, один хрен, коряв.
И что ж за нужда в оном? :)
--
Regards, LVT.
← →
Игорь Шевченко © (2010-04-27 22:25) [69]Leonid Troyanovsky © (27.04.10 22:04) [68]
> Будет/не будет - код, один хрен, коряв.
нужда в корявом коде может быть одна - проверить факт, а не верить на слово.
Я тебе даже полностью версию выпишу, чтобы можно было сравнить - я на свою установку накатываю все апдейты.
"Borland® Delphi® for Microsoft® Windows™ Version 10.0.2558.35231 Update 2 Copyright © 2005 Borland® Software Corporation. All Rights Reserved."
> С необходимыми и достаточными условиями?
> And все версии?
На двух версиях, которыми располагаю, проверил. Результат опубликовал :)
← →
Leonid Troyanovsky © (2010-04-27 22:38) [70]
> Игорь Шевченко © (27.04.10 22:25) [69]
> "Borland® Delphi® for Microsoft® Windows™ Version 10.0.2558.
> 35231 Update 2 Copyright © 2005 Borland® Software Corporation.
Здесь похвастать не чем, бо, не следил, не участвовал,
не .. привлекался :)
> На двух версиях, которыми располагаю, проверил. Результат
> опубликовал :)
Результат любопытный и заслуживает, IMHO, текущего обсуждения.
Будет над чем поразмышлять :)
--
Regards, LVT.
← →
sniknik © (2010-04-27 23:15) [71]> Будет над чем поразмышлять :)
procedure GetDynaMethod;
{ function GetDynaMethod(vmt: TClass; selector: Smallint) : Pointer; }
asm
{ -> EAX vmt of class }
{ SI dynamic method index }
{ <- ESI pointer to routine }
{ ZF = 0 if found }
{ trashes: EAX, ECX }
PUSH EDI
XCHG EAX,ESI
JMP @@haveVMT
@@outerLoop:
MOV ESI,[ESI]
@@haveVMT:
MOV EDI,[ESI].vmtDynamicTable
TEST EDI,EDI
JE @@parent
MOVZX ECX,word ptr [EDI]
PUSH ECX
ADD EDI,2
REPNE SCASW //ошибка здесь. на событии "обратного отщелкивания" мыши после клика
JE @@found
POP ECX
@@parent:
MOV ESI,[ESI].vmtParent
TEST ESI,ESI
JNE @@outerLoop
JMP @@exit
@@found:
POP EAX
ADD EAX,EAX
SUB EAX,ECX { this will always clear the Z-flag ! }
MOV ESI,[EDI+EAX*2-4]
@@exit:
POP EDI
end;
← →
sniknik © (2010-04-27 23:18) [72]в смысле ошибка то конечно не там, она раньше, в попутанных адресах от несуществующего объекта, но валится именно на этой команде (вылезает за "свою" память как понимаю).
← →
Игорь Шевченко © (2010-04-27 23:45) [73]Помогло воспроизвести ошибку только включение в проект FastMM с указанием Full Debug mode, при котором при освобождении объекта заведомо портится занимаемая им память.
Так что код действительно "как повезет" и не рекомендуется к использованию.
← →
sniknik © (2010-04-27 23:52) [74]догма...
← →
Игорь Шевченко © (2010-04-28 00:00) [75]sniknik © (27.04.10 23:52) [74]
Для обработчика OnClick - да, догма, потому что он срабатывает на нажатие мыши. За что тебе спасибо :)
Для потенциально любого обрабтчика - отнюдь не догма.
← →
Игорь Шевченко © (2010-04-28 00:09) [76]Соответственно, при
> procedure TForm1.ButtonClick(Sender: TObject);
> begin
> //Sender.Free;
> end;
>
> procedure TForm1.ButtonMouseUpFree(Sender: TObject; Button:
> TMouseButton;
> Shift: TShiftState; X, Y: Integer);
> begin
> Sender.Free;
> end;
>
> procedure TForm1.FormCreate(Sender: TObject);
> begin
> FButton := TButton.Create(Panel1);
> FButton.Parent := Panel1;
> FButton.Top := 20;
> FButton.Left := 20;
> FButton.Caption := "Click me";
> FButton.OnClick := ButtonClick;
> FButton.OnMouseUp := ButtonMouseUpFree;
> end;
Даже использование FastMM не вызывает ошибки
← →
sniknik © (2010-04-28 00:22) [77]> Для потенциально любого обрабтчика - отнюдь не догма.
для форм, с их обычным обилием, и в них же выполняющимися действиями, обработчиками Release вместо Free - узаконенная в доке догма.
а вообще, для потенциального большинства, т.к. мало найдется событий ничего не наследующих (и не выполняющих потому неизвестно что, не в данный момент так в перспективе), и вообще независимых, без последствий, типа отработал и все, и никуда не лезет, никого не вызывает, и ни к чему не обращается (не в данный момент так в перспективе).
← →
Игорь Шевченко © (2010-04-28 00:48) [78]sniknik © (28.04.10 00:22) [77]
> для форм, с их обычным обилием, и в них же выполняющимися
> действиями, обработчиками Release вместо Free - узаконенная
> в доке догма.
Цитата из справки:
"Use Release to destroy the form and free its associated memory.
Any event handlers for the form or its children should use Release instead of Free.Failing to do so can cause a memory access error"
для уничтожения формы внутри ее самой и только для этого.
Какое отношение Release имеет к обработчикам событий компонент, я честно не понимаю.
← →
Игорь Шевченко © (2010-04-28 00:49) [79]sniknik © (28.04.10 00:22) [77]
> типа отработал и все, и никуда не лезет, никого не вызывает,
> и ни к чему не обращается (не в данный момент так в перспективе).
>
На перспективу лчуше вообще ничего не писать. Надежнее будет.
← →
sniknik © (2010-04-28 00:57) [80]> Какое отношение Release имеет к обработчикам событий компонент, я честно не понимаю.
только одно отношение, это аналог, когда "убивают" себя из своего же обработчика. с формой такая ситуация происходит чаще, вот и позаботились.
и также это путь к обходу сабжа, ничего не мешает сделать тоже самое для имеджа например.
← →
sniknik © (2010-04-28 01:01) [81]> только одно отношение
+ все компоненты формы "помрут" вместе с ней, т.что и из обработчика компонент лежащих на форме делать Free форме противопоказано.
← →
Игорь Шевченко © (2010-04-28 01:09) [82]
> только одно отношение, это аналог, когда "убивают" себя
> из своего же обработчика
Free в release тоже вызывается из обработчика сообщения. Сообщения CM_RELEASEprocedure TCustomForm.Release;
begin
PostMessage(Handle, CM_RELEASE, 0, 0);
end;
procedure TCustomForm.CMRelease;
begin
Free;
end;
из OnClick почему нельзя убивать - выяснили, Click срабатывает на MouseDown, а кроме него еще есть MouseUp к тому же контролу, уже в очереди.
← →
sniknik © (2010-04-28 01:20) [83]> Free в release тоже вызывается из обработчика сообщения. Сообщения CM_RELEASE
ну и что? он же по событию вызовется в общей очереди между обработчиками, после отработавших и до возможных... после "убийства" формы отправленных в "никуда" (событие на не существующий хендл к AV не приводят, только к невыполнению события).
вызов Free это не баг, и не приводит к багу, если только он не сделан в неправильном месте (до обращений к обьекту).
> из OnClick почему нельзя убивать
лучше считай откуда можно... меньше получится.
← →
Германн © (2010-04-28 02:00) [84]
> лучше считай откуда можно... меньше получится.
+1
Опередил.
> И обсуждалось подобное не раз, чудес не было, только "свезло/не
> свезло".
(c) LVT
← →
Игорь Шевченко © (2010-04-28 10:33) [85]sniknik © (28.04.10 01:20) [83]
> он же по событию вызовется в общей очереди между обработчиками,
> после отработавших и до возможных
переведи. Это обычный обработчик сообщения, тот же самый динамический метод, как и в WM_MOUSEUP
> вызов Free это не баг, и не приводит к багу
Вызов Free это не баг, но может привести к багу.
> лучше считай откуда можно... меньше получится.
Я начну считать, тебе мало не покажется
← →
sniknik © (2010-04-28 12:55) [86]> переведи.
по русски написано.
> Это обычный обработчик сообщения, тот же самый динамический метод, как и в WM_MOUSEUP
а ты не путай, при сабжевом глюке событие не вызывается вызывается метод.
> Вызов Free это не баг, но может привести к багу.
ВСЕ может привести к багу.
← →
Игорь Шевченко © (2010-04-28 13:03) [87]
> а ты не путай, при сабжевом глюке событие не вызывается
> вызывается метод.
в чем разница ?
← →
oxffff © (2010-04-28 15:01) [88]Читаю с середины второй день подряд.
И не могу понять в чем суть обсуждения?
Если во вложенном методе будет разрушен объект и это не приведет к проблемам, то ничего плохого нет.
А плохое это не только использование разрушенногого объекта, но и использование частично деинициализированного объекта.
Но ведь Tobject.Free по факту ссылается на выходе на разрушенный объект и работает же.
Это вопрос логики.
← →
sniknik © (2010-04-28 15:49) [89]> в чем разница ?
для тебя ни в чем... а глюк в одном случае считай происками шайтана, нормальную работу в другом замыслом создателя...
плевать в общем, считай чем хочешь.
← →
Игорь Шевченко © (2010-04-28 16:36) [90]sniknik © (28.04.10 15:49) [89]
не плюйся, вылетит, не поймаешь
← →
12 © (2010-04-28 16:44) [91]грустно смотреть
← →
pavel_guzhanov © (2010-04-29 08:49) [92]Всем спасибо. По крайней мере я понял причину, по которой получается AV.
Буду думать, как сделать по-другому :о)
← →
sniknik © (2010-04-29 10:03) [93]> Буду думать, как сделать по-другому :о)
чего тут думать? еще в [35] было указание на то как борлад подобное "обходит", посмотреть код в генофонде (несколько строк всего), да модифицировать "под себя".
а в [42] прямой пример замены ничего не меняющей ни в отображении и в логике, только проверки станут другими, не на nil а на видитмость.
← →
Плохиш © (2010-04-29 10:20) [94]
> 12 © (28.04.10 16:44) [91]
>
> грустно смотреть
Просто весеннее обострение ;-)
Страницы: 1 2 3 вся ветка
Форум: "Начинающим";
Текущий архив: 2010.08.27;
Скачать: [xml.tar.bz2];
Память: 0.78 MB
Время: 0.065 c