Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Общие вопросы Delphi
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 09.05.2024, 19:04   #1
killzone
 
Регистрация: 25.03.2010
Сообщений: 8
По умолчанию Двойное разыменовывание??? Код рабочий, но не понимаю как работает.

Приветствую уважаемые форумчане!
Привожу рабочий код. Но не понимаю как это всё работает, я раньше не встречал символ двойного разыменовывания ^^. Нашел в интернете такую функцию.
Код:
type
TNotifyReference = reference to procedure(Sender: TObject);

function Proc2NotifyEvent(const aProc: TNotifyReference): TNotifyEvent;
type
  TVtable = array[0..3] of Pointer;
  PVtable = ^TVtable;
  PPVtable = ^PVtable;
begin
  TMethod(Result).Code := PPVtable((@aProc)^)^^[3];
  TMethod(Result).Data := Pointer((@aProc)^);
end;
Я эту функцию использую для присвоения кнопке на событие OnClick анонимную процедуру:
Код:
Form_GridClient.Button_SelectAll.OnClick := Proc2NotifyEvent(
    procedure (Sender:TObject)
    begin
      showmessage('Я работаю, всё ок!');
    end);
Всё отлично работает, но хочу понять что вообще происходит внутри этой функции и как называется эта операция ^^?
killzone вне форума Ответить с цитированием
Старый 09.05.2024, 22:01   #2
Vapaamies
Ваш К. О.
Участник клуба
 
Аватар для Vapaamies
 
Регистрация: 26.12.2012
Сообщений: 1,799
По умолчанию

Разыменование — одноместная операция, применяемая к аргументу слева. Несколько операций подряд дают множественное разыменование, по числу знаков: двойное, тройное, и так далее.

Процедура основана на знании внутренних структур типов, генерируемых компилятором. Тип TMethod описан так:
Код:
type
  TMethod = record
    Code, Data: Pointer;
  end;
Есть и теория по разным типам ссылок на процедуры. Она должна быть описана в справке.
Vapaamies вне форума Ответить с цитированием
Старый 10.05.2024, 06:40   #3
killzone
 
Регистрация: 25.03.2010
Сообщений: 8
По умолчанию

Спасибо за статью, в голове начинает проясняться.
Значит я конвертирую анонимную процедуру в метод. Хотя наверно слово "конвертирую" тут не подходит, я создаю метод из анонимной процедуры.
PPVtable это адрес в памяти, по которому находится адрес в памяти по которому находится виртуальная таблица (методов?) (TVtable состоящая из 4х указателей). Проще говоря PPVtable это указатель на указатель на виртуальную таблицу. Отсюда и идут подряд операции разыменовывания ^^ чтобы добраться до виртуальной таблицы без промежуточных переменных. Это вроде понятно.
В строчке
Код:
 TMethod(Result).Data := Pointer((@aProc)^);
мы показываем начало анонимной процедуры, а вот в строчке
Код:
TMethod(Result).Code := PPVtable((@aProc)^)^^[3];
мы показываем 4й (начинаем с 0) указатель из виртуальной таблицы.
Вот тут не понимаю почему [3]? Что является [0], [1], [2], [3]. У нас что [0] это будет адрес начала анонимной процедуры, [1] это адрес Sender:TObject?, [2] - это ... of object? Тут в общем запутался...



В строчке
Код:
 TMethod(Result).Data := Pointer((@aProc)^);
Мы показываем Sender:TObject.

А вот в строчке
Код:
TMethod(Result).Code := PPVtable((@aProc)^)^^[3];
Мы показываем тело анонимной процедуры. [0] - это QueryInterface, [1] - AddRef, [2] - Release [3] - MyAnonymousProcedure? Верно?

Последний раз редактировалось killzone; 10.05.2024 в 06:56.
killzone вне форума Ответить с цитированием
Старый 10.05.2024, 10:01   #4
Vapaamies
Ваш К. О.
Участник клуба
 
Аватар для Vapaamies
 
Регистрация: 26.12.2012
Сообщений: 1,799
По умолчанию

Цитата:
Сообщение от killzone Посмотреть сообщение
Мы показываем тело анонимной процедуры. [0] - это QueryInterface, [1] - AddRef, [2] - Release [3] - MyAnonymousProcedure? Верно?
Отладчик у тебя перед глазами, не у меня. Я сам не пишу на модных версиях Delphi, так что не знаю, как оно там внутри. Могу предложить включить в настройках генерацию map-файла с номерами строк (Detailed), а потом посмотреть по адресам. Возможно, в отладочной сборке придется также отключить ASLR (dynamic image base), если не отключено по умолчанию.
Vapaamies вне форума Ответить с цитированием
Старый Вчера, 20:39   #5
phomm
personality
Старожил
 
Аватар для phomm
 
Регистрация: 28.04.2009
Сообщений: 2,883
По умолчанию

Цитата:
Сообщение от killzone Посмотреть сообщение
В строчке
Код:
TMethod(Result).Data := Pointer((@aProc)^);
Мы показываем Sender:TObject.

А вот в строчке
Код:
TMethod(Result).Code := PPVtable((@aProc)^)^^[3];
Мы показываем тело анонимной процедуры. [0] - это QueryInterface, [1] - AddRef, [2] - Release [3] - MyAnonymousProcedure? Верно?
Data это указатель на то, что будет передано в качестве Self методу, а Code это сам метод класса, взятый, как видно, из VMT (внутри обёртки анонимной процедуры, которая является неким объектом со стандартными методами), таким образом метод класса будет работать над нужным нам объектом-экземпляром этого класса. Sender:TObject в этом деле не участвует никак, потому что сендером будет потом кнопка, которая вызовет данный код, мы лишь сохраняем для неё в ивенте OnClick нужную структуру-ссылку, которая для неё нашей магией видится валидным TNotifyEvent.
Касательно индексов - вот статья , в целом верно, что по определённому смещению будет лежать пользовательский метод, но в частном случае надо будет подбирать значение, в зависимости от иерархии классов, возможно где-то и лежит универсальное/вычисляемое значение, тут не знаю. Для анонимки скорее всего верно, т.к. её внутренности определяются версией компилятора, а меняются и того реже.

P.S. надо быть аккуратным, используя хаки, например, произойдёт Release вашей анонимки, она managed type with reference counting, а вы держите на неё ссылку в кнопке, всё может упасть, возможно, придётся самому заботиться о подсчете ссылок вручную. А если вы делаете свой класс, то можно воспользоваться советом из https://docwiki.embarcadero.com/RADS...hods_in_Delphi там есть раздел для ивентов, но на стандартную кнопку это, конечно, не распространяется.

Последний раз редактировалось phomm; Вчера в 21:01.
phomm вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Не понимаю как работает CALL Bizunov SQL, базы данных 0 04.06.2013 11:29
Что то не понимаю как этот код работает? Denis19061989 Помощь студентам 0 26.05.2013 10:33
Не работает рабочий код при навеске на другой контрол samouelson C# (си шарп) 3 21.06.2012 20:25
Разыменовывание итератора litviak Общие вопросы C/C++ 5 08.06.2012 14:29
Вирус,из-за которого не работает рабочий стол JerryS Безопасность, Шифрование 7 13.09.2009 19:54