Вверх ↑
Этот топик читают: Гость
Ответов: 2059
Рейтинг: 132
#1: 2014-04-29 01:30:24 ЛС | профиль | цитата
Как-то не задумывался, не обращал внимания...
Вывод чего-то из цикла, в точку вывода (тавтология) удобней делать, а точнее только и работает - _hi_OnEvent(OnEvent,Тра-та-та).
С другой стороны _hi_CreateEvent(_Data, @_event_Name,Тра-та-та) "корректнее" (не могу подобрать слова) работает в однократной передаче.
Вопрос такой - каков механизм того и другого?
Желательно объяснить на пальцах, на ассемблере будет доходчевей, если дело в стеке.
Интересны формулировки механизмов нижних (и верхних) точек в случае EventFromData - Генерирует событие при обращении к данным.
С точками доступа к элементам массива вопросов наверное не у кого не возникает, но для комплекта ... - начинающие будут благодарны.
карма: 6

0
Ответов: 9906
Рейтинг: 351
#2: 2014-04-29 07:49:45 ЛС | профиль | цитата
flint2 писал(а):
Вопрос такой - каков механизм того и другого?

_hi_OnEvent -- работает "по настоящему".
Т.е., делает реальный функциональный вызов некого метода некоторого объекта. Которые записаны в структуре THI_Event при инициализации объекта.
После чего, возвращаясь из этого вызова, продолжает выполнять последующий код.

А вот _hi_CreateEvent не делает "почти ничего". Он просто немножечко модифицирует структуру TData. И никого не вызывает.
В этой структуре есть хитрое поле Next, в которое заносится значение, обозначенное Вами как _event_Name.
Больше он не делает ничего (разве что взводит старший бит в поле TData.data_type - для надежности), продолжая исполнять последующий код.

Использование поля Next происходит уже очень потом, при полном окончании исполнения метода, в котором и применялся _hi_CreateEvent.
Примерно здесь (share.pas):
#pas
procedure __hi_OnEvent(const PointEvent:THI_Event;var Data:TData);
var P:PHI_Event;
begin
P := @PointEvent;
while Assigned(P.Event) do begin
{$ifdef _DEBUG_}CallEvent(2,P^,Data);{$endif}
P.Event(Data,P.Index); //а потом ТУТА
if(Data.data_type and $80)=0 then break;
dec(Data.data_type,$80);
P := PHI_Event(Data.next); //сначала ЗДЕСЯ
end;
end;

По простому: _hi_CreateEvent не делает функционального вызова, а поручает сделать его своему "предшественнику"
Экономим стек (точнее, снимаем ограничение по стеку на длину последовательных вызовов).
В качестве побочного эффекта - начинают работать некоторые "кольцевания" (точнее, тот OnEvent, который исполняется как _hi_CreateEvent - уже можно "закольцовывать")

------------ Дoбавленo в 07.49:
flint2 писал(а):
Интересны формулировки механизмов нижних (и верхних) точек в случае EventFromData - Генерирует событие при обращении к данным.

Ну да: генерирует событие при обращении к данным. Обратился --> Сгенерировалось событие --> Возвращается результат, который то самое событие передало на doData.
Непонятно, вопрос то в чем

flint2 писал(а):
С точками доступа к элементам массива вопросов наверное не у кого не возникает, но для комплекта ... - начинающие будут благодарны.

Опять непонятно, вопрос то в чем

карма: 9

1
Голосовали:flint2
Ответов: 2059
Рейтинг: 132
#3: 2014-04-29 09:30:41 ЛС | профиль | цитата
Непонятно, вопрос то в чем

Получается "до кучи".
За ответ, - большущие спасибо!
Лучше - и не объяснишь!
карма: 6

0
Ответов: 4664
Рейтинг: 767
#4: 2014-04-29 11:38:49 ЛС | профиль | цитата
Как следствие, одна особенность _hi_CreateEvent и _hi_OnEvent (Galkov, вроде, раньше уже объяснял):
_hi_CreateEvent можно применять только в методах _work_doXXX и _var_XXX (ну и в функциях, которые они вызывают, с передачей своей TData).
А в обработчиках "системных" событий (сообщений, callback-ов, параллельных потоков и др. функций, которые вызывает система) применяется только _hi_OnEvent. В частности, в событиях визуальных компонентов.
Правильно?
карма: 26

0
Ответов: 9906
Рейтинг: 351
#5: 2014-04-29 12:52:23 ЛС | профиль | цитата
ДА, правильно.

Обработчик батона (к примеру) обязательно содержит _hi_OnEvent.
Не, ну можно попробовать _hi_CreateEvent - и ничего не получим. Некому просто будет исполнять вышеупомянутое "поручение"
Самый первый исполнитель-то -- должен быть.

Add(MainForm,2953706,343,133)
{
}
Add(Button,12545460,112,126)
{
Left=200
Top=105
link(onClick,11928653:doWork2,[])
}
Add(Edit,5116022,273,63)
{
Left=200
Top=70
Text="99995"
Alignment=1
}
Add(If_else,4885337,266,126)
{
Type=3
link(onTrue,11928653:doWork1,[(305,132)(305,118)(172,118)])
link(onFalse,2953706:doCaption,[])
link(Op2,5116022:Text,[])
}
Add(Counter,6657830,196,126)
{
Max=100000
link(onNext,4885337:doCompare,[])
}
Add(HubEx,11928653,168,126)
{
link(onEvent,6657830:doNext,[])
}
В этом примере именно БАТОН делает все вызовы, и именно поэтому "кольцевание" является корректным. ((даже doCaption делает батон))
Если знать некоторые подробности...
В данном случае, оно не более, чем "графическое"

------------ Дoбавленo в 12.42:
И еще один момент про НИЗЯ для _hi_CreateEvent: следует помнить, что сначала закончится метод, а уже потом вызовется событие (если будет кому его вызывать)
Например здесь -- НИЗЯ
#pas
procedure THIConvertor._work_doConvert12(var _Data:TData; Index:word);//StrToStream
var S:string;
St:PStream;
len:cardinal;
begin
S := ReadString(_Data,_data_Data);
St := NewMemoryStream;
len := Length(S);
if len > 0 then St.Write(s[1],len);
St.Position := 0;
_hi_OnEvent(_event_onResult,St);
St.free;
end;
Упадет все нафиг, когда будет отправлено событие (предшественником) с уже убитым стримом

------------ Дoбавленo в 12.52:
Да, и еще первый аргумент типа TData....
Это не какая-то левая структура, а именно входной аргумент метода. Просто обязательно.
А иначе как "предшественник" узнает о твоих хитромудрых манипуляциях
карма: 9

0
Ответов: 4664
Рейтинг: 767
#6: 2014-04-29 12:55:09 ЛС | профиль | цитата
Проще говоря, _hi_CreateEvent "не дожидается" завершения обработки события, после которого с чистой душой можно освободить все ненужные ресурсы, а возвращает управление сразу. То-есть, если в методе _work_doXXX нужно вызвать событие и завершиться не дожидаясь его завершения, то применяем _hi_CreateEvent.
Классический случай:

#pas
....
if Rslt = SOME_ERROR_CODE then // Условно
begin
_hi_CreateEvent(_Data, @_event_onError, Rslt); // Поскольку мы всё равно завершаемся, то нам не нужно дожидаться окончания обработки события
Exit;
end;
....
карма: 26

0
Ответов: 9906
Рейтинг: 351
#7: 2014-04-29 13:02:42 ЛС | профиль | цитата
Ну да, как-то так.
Кстати говоря, похожее мероприятие совершают уважающие себя оптимизаторы в ЯВУ.
Последний CALL Function; RET; обычно заменяется на JMP Function;.
В полном соответствии с: завершиться не дожидаясь его завершения
карма: 9

0
Ответов: 2059
Рейтинг: 132
#8: 2014-05-01 22:00:25 ЛС | профиль | цитата
Последний CALL Function; RET; обычно заменяется на JMP Function;.

Я не знаю, кто такой Луис Карвалол, или Кавалан и что такое оптимизаторы в ЯВУ,
но выше приведенная комбинация RET, CALL, JMP - спасают от диктата " это верно, - потому что верно и во веки веков!".
Особенно раздражает, когда компилятор редактирует твою мысль входа в ассемблерную fp (прибавляя свой код типа
push EBP
mov EBP,ESP
...)
- это как правило, но иногда и кренделя - поверте.
Почему мне говорят, как думать? Конечно не вопрос обойти, но зачем лишние телодвижения?
Как будто не понятно, что надо делать с ESP,EBP, да и с EDI..ESI, если портишь.
Вот демократия и в асскмблере. Побеспокоились, - соломку подстелили.

P.S.
Если так положено, то есть правила CALL - RET.
P.S.
А не кто не пробовал написать в машинном коде первую команду?
Примерно:
asm
db $FF,$44,$24,$18
MOV [EBP -4], EAX
...
или бесполезно?
Все равно начальный будет код прибавлен?
------------ Дoбавленo в 22.00:
Как вывести True/False в точки var и Event?
Сейчас делаю через 0/1: Integer;
а потом перевожу в Boolean в другом компоненте через if /else.
Очень не удобно.
Примеров не нашел, но наверняка это можно делать.
карма: 6

0
Разработчик
Ответов: 4698
Рейтинг: 426
#9: 2014-05-02 15:52:11 ЛС | профиль | цитата
flint2, в пакете Delphi нет такого типа данных, как boolean, это значит, что передать его можно как раз через
flint2 писал(а):
0/1: Integer;
, но напрямую, увы, никак.
карма: 10
0
Ответов: 4664
Рейтинг: 767
#10: 2014-05-02 15:57:33 ЛС | профиль | цитата
flint2 писал(а):
Все равно начальный будет код прибавлен?
Объявляй как

#pas
function Foo():Integer; assembler;
asm

end;
Ничего лишнего не будет.
карма: 26

0
Ответов: 16884
Рейтинг: 1239
#11: 2014-05-02 16:58:14 ЛС | профиль | цитата
flint2 писал(а):
Сейчас делаю через 0/1: Integer;

А я экономлю байты
code_33520.txt
А может быть и нет...
карма: 25
Немного терпения! Дежурный экстрасенс скоро свяжется с Вами!
0
файлы: 1code_33520.txt [640B] [150]
Гость
Ответов: 17029
Рейтинг: 0
#12: 2014-05-04 11:46:05 правка | ЛС | профиль | цитата


Редактировалось 2 раз(а), последний 2025-01-10 15:42:55
карма: 0

0
Ответов: 2059
Рейтинг: 132
#13: 2014-05-04 11:48:18 ЛС | профиль | цитата
Assasin, Netspirit, Tad
Спасибо!
Все советы для меня ценны и поучительны.
Потихоньку начинаю врубаться, что к чему.
Netspirit
Я долго бы копался, пока на конец не понял, что надо "function Foo():Integer; assembler;"
Tad]
А может быть и нет...

Увы, нет.
карма: 6

0
13
Сообщение
...
Прикрепленные файлы
(файлы не залиты)