Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 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; // &#237;&#229; &#241;&#238;&#226;&#239;&#224;&#228;&#224;&#254;&#242;
         end;//if not
         j:=i;
       end;//for i
       if j=Bitmap.Height - 1 then  // &#241;&#238;&#226;&#239;&#224;&#228;&#224;&#254;&#242;
       begin
         a:=0;
// &#207;&#240;&#238;&#226;&#229;&#240;&#234;&#224; , &#229;&#241;&#242;&#252; &#235;&#232; &#226; &#241;&#242;&#240;&#232;&#237;&#227;&#235;&#232;&#241;&#242;&#229; &#243;&#230;&#229; &#242;&#224;&#234;&#224;&#255; &#231;&#224;&#239;&#232;&#241;&#252;
         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
// &#197;&#241;&#235;&#232; &#231;&#224;&#239;&#232;&#241;&#232; &#237;&#229;&#242;, &#242;&#238; &#228;&#238;&#225;&#224;&#226;&#235;&#255;&#229;&#236; &#237;&#238;&#226;&#243;&#254; &#231;&#224;&#239;&#232;&#241;&#252; &#226; &#241;&#242;&#240;&#232;&#237;&#227;&#235;&#232;&#241;&#242;
       if a=SL.Count-1 then  // &#229;&#241;&#235;&#232;  &#224; &#240;&#224;&#226;&#237;&#224; &#234;&#238;&#235;&#232;&#247;&#229;&#241;&#242;&#226;&#243; &#231;&#224;&#239;&#232;&#241;&#229;&#233; &#226; &#241;&#242;&#240;&#232;&#237;&#227;&#235;&#232;&#241;&#242;&#229;
                             //&#231;&#237;&#224;&#247;&#232;&#242; &#242;&#224;&#234;&#238;&#227;&#238; &#232;&#236;&#229;&#237;&#232; &#226; &#241;&#242;&#240;&#232;&#237;&#227;&#235;&#232;&#241;&#242;&#229; &#237;&#229;&#242;
         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
end


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.


 
{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_RELEASE

procedure 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.058 c
15-1265554963
TUser
2010-02-07 18:02
2010.08.27
Соцопросик курильщиков


15-1263472383
xayam
2010-01-14 15:33
2010.08.27
DMSearch


15-1264749431
Делфиец
2010-01-29 10:17
2010.08.27
Помогите разобраться что это за ерунда


2-1265712324
Nilman
2010-02-09 13:45
2010.08.27
Поясните пожалуйста значение свойства TThread.FreeOnTerminate


15-1267539041
ocean
2010-03-02 17:10
2010.08.27
Как подешевле подключиться в Интернету





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский