Форум по Delphi программированию

Delphi Sources



Вернуться   Форум по Delphi программированию > Все о Delphi > Компоненты и классы
Ник
Пароль
Регистрация <<         Правила форума         >> FAQ Пользователи Календарь Поиск Сообщения за сегодня Все разделы прочитаны

Ответ
 
Опции темы Поиск в этой теме Опции просмотра
  #1  
Старый 12.04.2017, 19:28
MProg MProg вне форума
Прохожий
 
Регистрация: 12.04.2017
Сообщения: 8
Версия Delphi: Delphi 7
Репутация: 10
По умолчанию Принудительное удаление объекта изнутри

Собственно есть код:

Код:
unit Unit1;

interface

uses SysUtils, Forms, Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    FB:TButton;
    procedure FBClick(Sender: TObject);
    { Private declarations }
  public
    { Public declarations }
  end;

  TMButton = class(TButton)
   procedure Click; override;
  end;

var
  Form1: TForm1;
  MB:TMButton;
implementation

{$R *.dfm}

procedure CreateTMButton();
begin
  MB:=TMButton.Create(Form1);
  MB.Width:=Form1.ClientWidth;
  MB.Height:=Form1.ClientHeight-20;
  MB.Caption:='Class';
  MB.Parent:=Form1;
end;

procedure TMButton.Click;
begin
  inherited;
  //showmessage(inttostr(Integer(MB)));
  FreeAndNil(MB);
  //CreateTMButton();
  //showmessage(inttostr(Integer(MB)));
  //Showmessage('MButtonClick');

end;

procedure TForm1.FBClick(Sender: TObject);
begin
 FreeAndNil(MB);
 //CreateTMButton();
 //Showmessage('FBClick');
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
 CreateTMButton();
 FB:=TButton.Create(Form1);
 FB.Top:=Form1.ClientHeight-20;
 FB.Height:=20;
 FB.Width:=Form1.ClientWidth;
 FB.Caption:='Form';
 FB.OnClick:=FBClick;
 FB.Parent:=Form1;
end;

end.

В коде создается две кнопки: FB (для внешнего удаления), MB (для внутреннего удаления)

При клике на FB все работает удовлетворительно.

А при клике на MB происходит AV ошибка при выходе из процедуры из-за попытки передачи управления на уже несуществующие адреса.

Вопрос в том как адекватно спилить под собой ветку и не налюбнутся с дерева?
Тость, как можно адекватно(приближенно к правильному) удалять объект MB из той же TForm1.FBClick? Есть ли какие-то стандартные или нестандартные махинации со стеком или прыжками в иное место кода чтоб все адекватно удалялось и работало?

Буду признателен даже за извращенные варианты (хоть эта задачка в принципе извращенная вроде как)... Так сказать если не для дела, то для общего развития и более глубоко понимания сгодятся
Ответить с цитированием
  #2  
Старый 12.04.2017, 20:13
Аватар для Alegun
Alegun Alegun вне форума
LMD-DML
 
Регистрация: 12.07.2009
Адрес: Богородское
Сообщения: 3,025
Версия Delphi: D7E
Репутация: 1834
По умолчанию

Уберите везде строчку с freeandnil и вставьте её первой в createtmbutton ввиде if MB <> nil then FreeAndNil(MB);
Ответить с цитированием
  #3  
Старый 12.04.2017, 20:49
MProg MProg вне форума
Прохожий
 
Регистрация: 12.04.2017
Сообщения: 8
Версия Delphi: Delphi 7
Репутация: 10
По умолчанию

Цитата:
Сообщение от Alegun
Уберите везде строчку с freeandnil и вставьте её первой в createtmbutton ввиде if MB <> nil then FreeAndNil(MB);

Это ничего не изменит и будет примерно также если бы просто расскоментировать строчку CreateTMButton();

Работает (без AV) только из-за того что объект наново создается и в том же адресном пространстве... Но это чисто мое предположение. Я еще не вникал по случайности оно так получается или по какому-то задуманому механизму.

Суть в том что надо вызывать FreeAndNil(MB) или его аналог в любом месте кода. Как во внутрях самого объекта MB так и за их предалами... И не важно будет ли объект пересоздан или нет

Все это не извращенными людьми делается внешними вызовами (в отношении к MB) по типу TForm1.FBClick и разными вариациями на тему...

PS: На коментарии в коде можно не смотреть.
Ответить с цитированием
  #4  
Старый 12.04.2017, 21:00
Аватар для Alegun
Alegun Alegun вне форума
LMD-DML
 
Регистрация: 12.07.2009
Адрес: Богородское
Сообщения: 3,025
Версия Delphi: D7E
Репутация: 1834
По умолчанию

Тогда проще из-самого-себя не удалять, а управлять видимостью
Ответить с цитированием
  #5  
Старый 12.04.2017, 21:10
MProg MProg вне форума
Прохожий
 
Регистрация: 12.04.2017
Сообщения: 8
Версия Delphi: Delphi 7
Репутация: 10
По умолчанию

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

Код:
procedure TMButton.MyFree;
begin
  FreeAndNil(MB);
  MB.I:=0;
end;

procedure TMButton.Click;
begin
  inherited;
  MyFree();
end;


Тойсть ошибка происходить из-за того что идет обращение к объекту или его частям после того как он был удален...

Вопрос в том как излюбнуть систему чтоб управление после FreeAndNil(MB); переходило в какую-то часть программы и дальше все работало в штатном режиме как будто объекта MB и не бывало?

Для людей не насилующих свой мозг:
Удаление MB.I:=0; не решит проблему.. Так как "end" грубо говоря превращается в ассемблерный "ret" который вытаскивает адрес (удаленного объекта) из стека процесора и пытается с ним взаимодействовать


Решение которое мне приходит на ум то это какие-то махинации со стеком или "jmp" в какой-то участок кода, или вообще все вместе...
Но это пока еще вопрос как и не нарушу ли я этим какую-то священную логику самого самого Delphi
Ответить с цитированием
  #6  
Старый 12.04.2017, 21:12
MProg MProg вне форума
Прохожий
 
Регистрация: 12.04.2017
Сообщения: 8
Версия Delphi: Delphi 7
Репутация: 10
По умолчанию

Цитата:
Сообщение от Alegun
Тогда проще из-самого-себя не удалять, а управлять видимостью

Что проще, знаю)
Интересно как такое можно из самого себя провернуть)
Ответить с цитированием
  #7  
Старый 12.04.2017, 22:21
Аватар для Alegun
Alegun Alegun вне форума
LMD-DML
 
Регистрация: 12.07.2009
Адрес: Богородское
Сообщения: 3,025
Версия Delphi: D7E
Репутация: 1834
По умолчанию

Получилось "харакири" через PostMessage
Код:
...
 protected
    procedure WndProc(var Msg: TMessage); override;
...

procedure TForm1.WndProc(var Msg: TMessage);
begin
  case Msg.Msg of
    CM_RELEASE: FreeAndNil(MB);
    else inherited;
  end;
end;

...
procedure TMButton.Click;
begin
  inherited;
  PostMessage(Form1.Handle, CM_RELEASE,0,0);
end;
Ответить с цитированием
  #8  
Старый 12.04.2017, 22:37
lmikle lmikle вне форума
Модератор
 
Регистрация: 17.04.2008
Сообщения: 8,003
Версия Delphi: 7, XE3, 10.2
Репутация: 49089
По умолчанию

Ну еще можно COM попробовать (то бишь интерфейсы). Там вообще удалять не нужно - само умрет, когда счетчик ссылок обнулится.
Ответить с цитированием
  #9  
Старый 12.04.2017, 23:02
MProg MProg вне форума
Прохожий
 
Регистрация: 12.04.2017
Сообщения: 8
Версия Delphi: Delphi 7
Репутация: 10
По умолчанию

Цитата:
Сообщение от Alegun
Получилось "харакири" через PostMessage

Пожалуй с сообщениями окна весьма неплох вариант если развить и немного облагородить небольшой оберткой)

Да и в целом идея в объекте ставить его в очередь на удаление, а удалять уже у в другом объекте наверно лучшее что можно с этой задачей придумать

Но как-то не покидают голову совсем трешовые идеи с наглыми прыжками по коду. К примеру удалить объект и прыгнуть в тот же обработчик сообщений окна... В общем, надо повкуривать отладчик и понять что эта идея если не жутко баговая выйдет, так вообще провальная)

Последний раз редактировалось MProg, 12.04.2017 в 23:04.
Ответить с цитированием
  #10  
Старый 12.04.2017, 23:14
MProg MProg вне форума
Прохожий
 
Регистрация: 12.04.2017
Сообщения: 8
Версия Delphi: Delphi 7
Репутация: 10
По умолчанию

Цитата:
Сообщение от lmikle
Ну еще можно COM попробовать (то бишь интерфейсы). Там вообще удалять не нужно - само умрет, когда счетчик ссылок обнулится.

Не вникал в COM, но идея в том чтоб именно самому "ручками" удалять.

Запилить некое подобие сборщика мусора который теми или иными способами следит за объектам, ставит их в очередь, потом каким-то механизмом удаляет вроде не проблема без добавления 10 технологий
Ответить с цитированием
  #11  
Старый 13.04.2017, 05:05
Аватар для dr. F.I.N.
dr. F.I.N. dr. F.I.N. вне форума
I Like it!
 
Регистрация: 12.12.2009
Адрес: Россия, г. Новосибирск
Сообщения: 660
Версия Delphi: D6/D7
Репутация: 26643
По умолчанию

Если переделывать Ваш пример, то получается:
Код:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    FB: TButton;
    procedure FBClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

  TMButton = class(TButton)
    procedure Click; override;
    procedure CMRelease(var Message: TMessage); message CM_RELEASE;
  end;

var
  Form1: TForm1;
  MB: TMButton;

implementation
 
{$R *.dfm}

procedure CreateTMButton();
begin
  MB := TMButton.Create(Form1);
  MB.Width := Form1.ClientWidth;
  MB.Height := Form1.ClientHeight - 20;
  MB.Caption := 'Class';
  MB.Parent := Form1;
end;

procedure TMButton.Click;
begin
  inherited;
  //PostMessage(Self.Handle, CM_RELEASE, 0, 0);
  PostMessage(MB.Handle, CM_RELEASE, 0, 0);
  //showmessage(inttostr(Integer(MB)));
  //FreeAndNil(MB);
  //CreateTMButton();
  //showmessage(inttostr(Integer(MB)));
  //Showmessage('MButtonClick');
end;

procedure TMButton.CMRelease(var Message: TMessage);
begin
  FreeAndNil(Self);
end;

procedure TForm1.FBClick(Sender: TObject);
begin
  FreeAndNil(MB);
 //CreateTMButton();
 //Showmessage('FBClick');
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  CreateTMButton();
  FB := TButton.Create(Form1);
  FB.Top := Form1.ClientHeight - 20;
  FB.Height := 20;
  FB.Width := Form1.ClientWidth;
  FB.Caption := 'Form';
  FB.OnClick := FBClick;
  FB.Parent := Form1;
end;

end.

Но можно и без ввода дополнительных классов, а "шаманским методом Гео" (ищи на DK) изменить стандартный класс. В таком случае уже все стандартные компоненты "модифицированного" класса, установленные ранее на форме, будут иметь "модифицированные" свойства и методы. Ну и и их можно не создавать динамически.
Код:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TButton= class(StdCtrls.TButton)
  public
    procedure Click; override;
    procedure Release;
  protected
    procedure CMRelease(var Message: TMessage); message CM_RELEASE;
  end;

  TForm1 = class(TForm)
    FB: TButton;
    MB: TButton;
    procedure FBClick(Sender: TObject);
    procedure MBClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation
 
{$R *.dfm}

{ TButton }

procedure TButton.Click;
begin
  inherited;
  Release;
end;

procedure TButton.CMRelease(var Message: TMessage);
begin
  FreeAndNil(Self);
end;

procedure TButton.Release;
begin
  PostMessage(Self.Handle, CM_RELEASE, 0, 0);
end;

{ TForm1 }

procedure TForm1.FBClick(Sender: TObject);
begin
  FreeAndNil(MB);
end;

procedure TForm1.MBClick(Sender: TObject);
begin
  MB.Release;
end;

end.
__________________
Грамотно поставленный вопрос содержит не менее 50% ответа.
Грамотно поставленная речь вызывает уважение, а у некоторых даже зависть.
Ответить с цитированием
  #12  
Старый 13.04.2017, 12:01
MProg MProg вне форума
Прохожий
 
Регистрация: 12.04.2017
Сообщения: 8
Версия Delphi: Delphi 7
Репутация: 10
По умолчанию

Цитата:
Сообщение от dr. F.I.N.
Но можно и без ввода дополнительных классов, а "шаманским методом Гео" (ищи на DK) изменить стандартный класс...
Весьма познавательный этот "шаманский" метод
Пардонте редкому обитателю форумов, а что такое "DK"?


По поводу жесткого посягательства на код программы и не менее жесткой наркомании(пример Delphi 7):

Код:
program Project1;

uses
  Forms,
  Unit1 in 'Unit1.pas' {Form1};

{$R *.res}

begin
  Application.Initialize;
  Application.CreateForm(TForm1, Form1);
  asm
   mov eax,esp
   sub eax,$8
   mov [Unit1.pRunStack],eax
  end;
  pRunLoop:=Addr(TApplication.Run);
  pRunLoop:=Pointer(Integer(pRunLoop)+133);
  Application.Run;
end.

Код:
unit Unit1;

interface

uses SysUtils, Forms, Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    FB:TButton;
    procedure FBClick(Sender: TObject);
  public

  end;

  TMButton = class(TButton)
   procedure Click; override;
  end;

var
  Form1: TForm1;
  MB:TMButton;
  pRunLoop:Pointer;
  pRunStack:Pointer;
implementation

{$R *.dfm}

procedure CreateTMButton();
begin
  MB:=TMButton.Create(nil);
  MB.Width:=Form1.ClientWidth;
  MB.Height:=Form1.ClientHeight-20;
  MB.Caption:='Class';
  MB.Parent:=Form1;
end;

procedure TMButton.Click;
var r:real;
begin
  inherited;
  FreeAndNil(MB);
  asm
   mov ebp,[pRunStack]
   jmp [pRunLoop]
  end;
end;

procedure TForm1.FBClick(Sender: TObject);
begin
 //FreeAndNil(MB);
 if(MB=nil)then CreateTMButton();
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
 CreateTMButton();
 FB:=TButton.Create(Form1);
 FB.Top:=Form1.ClientHeight-20;
 FB.Height:=20;
 FB.Width:=Form1.ClientWidth;
 FB.Caption:='Form';
 FB.OnClick:=FBClick;
 FB.Parent:=Form1;
end;

end.

На удивление и первый взгляд это безобразие даже как-то сносно работает)
Вот только явно не учтено еще как минимум парочку каких-то моментов..
После срабатывания TMButton.Click и закрытия окна, уже радостно встречает другое AV... так, чисто легонько намекая что если уж посягаешься, то посягайся глубже

Последний раз редактировалось MProg, 13.04.2017 в 12:03.
Ответить с цитированием
  #13  
Старый 13.04.2017, 13:32
Аватар для dr. F.I.N.
dr. F.I.N. dr. F.I.N. вне форума
I Like it!
 
Регистрация: 12.12.2009
Адрес: Россия, г. Новосибирск
Сообщения: 660
Версия Delphi: D6/D7
Репутация: 26643
По умолчанию

Цитата:
Сообщение от MProg
Весьма познавательный этот "шаманский" метод
Пардонте редкому обитателю форумов, а что такое "DK"?
В данном случае я подразумевал DelphiKingdom.com
__________________
Грамотно поставленный вопрос содержит не менее 50% ответа.
Грамотно поставленная речь вызывает уважение, а у некоторых даже зависть.
Ответить с цитированием
  #14  
Старый 14.04.2017, 00:36
Аватар для Alegun
Alegun Alegun вне форума
LMD-DML
 
Регистрация: 12.07.2009
Адрес: Богородское
Сообщения: 3,025
Версия Delphi: D7E
Репутация: 1834
По умолчанию

Оффтоп:
Цитата:
Сообщение от MProg
Пожалуй с сообщениями окна весьма неплох вариант если развить и немного облагородить небольшой оберткой)...
Небольшая притча: давно-давно в детстве, в начале 80х годов п.в. задумал я как-то приладить к своему лисапету "Школьник" тягу посредством электродрели, раму сверлил, хомуты гнул, редуктор от швейной машинки прикручивал, результат - в то время автономных шуруповёртов в продаже ещё не существовало, проблема провода в последний момент только проявилась, далеко от розетки не укатишь, мораль тбт: сделать можно всё что угодно, но зачем и какой результат, как оказалось, заранее это просчитывать трэба
Ответить с цитированием
Этот пользователь сказал Спасибо Alegun за это полезное сообщение:
lmikle (14.04.2017)
  #15  
Старый 14.04.2017, 01:51
MProg MProg вне форума
Прохожий
 
Регистрация: 12.04.2017
Сообщения: 8
Версия Delphi: Delphi 7
Репутация: 10
По умолчанию

Цитата:
Сообщение от Alegun
...заранее это просчитывать трэба
Трэба то трэба... но как же любопытство, дух эксперементаторства и все такое?
Да и куда занятней пусть даже вокруг дома погасать на "Лесодрели" нежели просто лежать и мечтать о том что кто-то вскоре что-то подобное или даже лучне придумает.

В моей конечной цели (примитивный API для работы с фреймами и управления ими на формах) некая обертка очень даже кстати.. Чтоб в результате были функции инициализации, деинициализации, парочку рабочих. Удалять фрейм изнутри вроде как удобненько, а какой-то громоздкий механизм управления фреймами городить не хотелось.
Вот и стало интересно что опытные люди используют для таких задач из стандартного или не совсем стандартного.

В итоге заюзаю сообщения окна для большей предсказуемости и адекватности)
Еще как вариант можно очередь на удаления сделать, в удаляемом объекте ставить его в очередь на удаление, а в рабочих функциях при их запуске из других объектов проверять очередь и удалять. Это вариант который приходит в голову чтоб не использовать дополнительные потоки, таймеры и тому подобное.

Ассемблерное извращение это чисто любопытство на тему и желания познать внутренности работы. В нем минусов куда больше, чем плюсов и решение пожалуй для очень специфических задач.

В общем тема вроде как исчерпана и в целом алгоритмы действий понятны)
Всем спасибо

А если у кого-то имеется внушительный опыт и не менее внушительные познания внутренностей, буду рад почитать о плохих вещах (по типу моей идеи с ассемблерными вставками)
Ответить с цитированием
Ответ


Delphi Sources

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения

BB-коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход


Часовой пояс GMT +3, время: 13:47.


 

Сайт

Форум

FAQ

RSS лента

Прочее

 

Copyright © Форум "Delphi Sources" by BrokenByte Software, 2004-2023

ВКонтакте   Facebook   Twitter