|
Иногда они возвращаются.... Хранение методов в памяти. | ☑ | ||
---|---|---|---|---|
0
H A D G E H O G s
01.08.13
✎
01:39
|
Ночи доброй.
Это было давно и успело зарастись травом, я просто сделал и забыл но все таки. Ветка: Delphi. Методы объектов как то по другому хранятся в памяти? Использование метода объекта, как call-back процедуру пост (17) function MethodToProcedure(self: TObject; methodAddr: pointer) : pointer; type TMethodToProc = packed record popEax : byte; // $58 pop EAX pushSelf : record // push self opcode : byte; // $B8 self : pointer; // self end; pushEax : byte; // $50 push EAX jump : record // jmp [target] opcode : byte; // $FF modRm : byte; // $25 pTarget : ^pointer; // @target target : pointer; // @MethodAddr end; end; var mtp : ^TMethodToProc absolute result; begin mtp := VirtualAlloc(nil, sizeOf(mtp^), MEM_COMMIT, PAGE_EXECUTE_READWRITE); with mtp^ do begin popEax := $58; pushSelf.opcode := $68; pushSelf.self := self; pushEax := $50; jump.opcode := $FF; jump.modRm := $25; jump.pTarget := @jump.target; jump.target := methodAddr; end; end; Все понятно, кроме 3-х вещей: 1) Че это такое: jump.pTarget := @jump.target; Указатель на сам себя, я правильно понял? Зачем? 2) Как программа определяет, что пошел код, а не данные? 2) Кто освободит память за собой? |
|||
1
NS
01.08.13
✎
01:40
|
программе не надо определять идет код или данные.
|
|||
2
H A D G E H O G s
01.08.13
✎
01:43
|
(1) Нууу.
Тогда вызвался этот метод, выделилась память под структуру, заполниласб структура и все.. Управление не перешло по адресу jump.target := methodAddr; У тут - переходит. |
|||
3
ЧеловекДуши
01.08.13
✎
06:23
|
(0) jump.pTarget := @jump.target;
Запоминает адрес в памяти Родителя :) |
|||
4
ЧеловекДуши
01.08.13
✎
06:25
|
+(0) Кто освободит память за собой?
Придется еще чего записать, память никто не освобождает при таком методе :) Тебе ещн нужно будет организовать... Функция VirtualFree освобождает выделенную память. http://www.firststeps.ru/mfc/winapi/r.php?113 |
|||
5
skunk
01.08.13
✎
06:38
|
(4)это не пхп ... в дельфях вроде как деструктор объекта и освобождает память
|
|||
6
skunk
01.08.13
✎
06:39
|
хотя там тоже фримем использовать надо
|
|||
7
Кирпич
01.08.13
✎
09:23
|
понимай эту фигню как программу на асме
popEax := $58; pushSelf.opcode := $68; pushSelf.self := self; pushEax := $50; jump.opcode := $FF; jump.modRm := $25; jump.pTarget := @jump.target; jump.target := methodAddr; т.е pop eax push self push eax jmp methodAddr функция MethodToProcedure создает этот код и возвращает указатель на него. этот код помещает self в стек, т.к. метод объекта ожидает первым параметром self. затем управление передается в метод объекта. удалять эту структуру из памяти ты должен сам (в деструкторе объекта можно это сделать) я так понимаю. |
|||
8
Лефмихалыч
модератор
01.08.13
✎
09:26
|
(0) а проблема-то исходно в чем? В том, что ты в callback суёшь указатель на метод класса и этот метод не выполняется?
|
|||
9
Кирпич
01.08.13
✎
09:26
|
jmp methodAddr это jmp [jump.target]
т.е. переход по указателю на methodAddr в jump.target это указатель на methodAddr |
|||
10
Кирпич
01.08.13
✎
09:32
|
автор похоже спит. автор спит, а проблемы решаются без него. вот что такое "утро вечера мудреннее" )
|
|||
11
Кирпич
01.08.13
✎
09:34
|
(8) ну да. он хочет чтобы windows вызывала метод его объекта как простую функцию.
|
|||
12
Лефмихалыч
модератор
01.08.13
✎
09:37
|
была у меня когда-то такая проблема:
http://www.rsdn.ru/forum/delphi/1409601.flat так и не понял, как это сотонинство победил и сделал в классе static-функцию в и всё зашиблось. Но у меня было смягчающее обстоятельство - аналоговый модем, в котрый два экземпляра одновременно позвонить гарантированно не могут |
|||
13
Лефмихалыч
модератор
01.08.13
✎
09:38
|
так и не понял, как это сотонинство победиТЬ. Там в последнем посте какой-то добрый человек кастанул что-то на дельфях, но я не осилил понять и перевести :)
|
|||
14
sda553
01.08.13
✎
09:39
|
Освободить память, насколько я помню VirtualFree это противоположность упомянутого в коде VirtualAlloc
|
|||
15
Лефмихалыч
модератор
01.08.13
✎
09:42
|
там, если я правильно все забыл, проблема в том, что метод класса действительно как-то под другому хранится. Более того - у него всегда первым скрытым параметром - указатель на объект, без которого он не может выполниться. И вот эта бяка jump.pTarget := @jump.target; нужна, чтобы все окружающее fcмоподобное сотонинство смогло как-то найтить объект от метода и там тудым-сюдым дальше я не понял
|
|||
16
Лефмихалыч
модератор
01.08.13
✎
09:42
|
fcмоподобное = ASM-оподобное
|
|||
17
Кирпич
01.08.13
✎
09:48
|
(15) что такое jump.pTarget := @jump.target я написал в (9)
но автору нужно смотреть на функцию MakeObjectInstance. она ему нужна. а то, что в (0) скорее не подойдет. есть еще заморочки со способами вызова (cdecl, pascal, stdcall). |
|||
18
Кирпич
01.08.13
✎
09:50
|
в (12) правильная ссылка
|
|||
19
Кирпич
01.08.13
✎
09:55
|
хотя MakeObjectInstance тоже не катит :))
|
|||
20
Кирпич
01.08.13
✎
10:22
|
Разобрался. Короче MethodToProcedure работает правильно, если способ вызова stdcall
А MakeObjectInstance это совсем другая фигня. |
|||
21
Кирпич
01.08.13
✎
10:24
|
вот так оно работает
procedure TForm1.Hello(param1, param2: integer); begin ShowMessage('p1:' + IntToStr(param1) + ' p2: ' + IntToStr(param2)); end; procedure TForm1.Button3Click(Sender: TObject); var P : procedure (param1 : integer; param2 : integer); stdcall; begin @P := MethodToProcedure(Self,@TForm1.Hello); P(100,500); end; |
|||
22
H A D G E H O G s
01.08.13
✎
14:44
|
static метод как раз не подходит, мне нужен self в callback.
Ну все работает, просто захотелось понять. |
|||
23
Кирпич
01.08.13
✎
14:51
|
при чем тут static. в static тоже есть self
procedure TForm1.Hello(param1, param2: integer); stdcall; begin ShowMessage(Self.Name + ' p1:' + IntToStr(param1) + ' p2:' + IntToStr(param2)); end; procedure TForm1.Button3Click(Sender: TObject); var P: procedure(param1: integer; param2: integer); stdcall; begin @P := MethodToProcedure(Self, @TForm1.Hello); P(100, 500); end; |
|||
24
H A D G E H O G s
01.08.13
✎
14:56
|
http://www.gunsmoker.ru/2008/12/static-delphi.html
Теперь ещё один шажок и мы переходим к тому, о чём говорил Реймонд Чен. Классовый метод можно объявить статическим (только в новых версиях Delphi). В этом случае у него не будет неявного параметра. Разумеется, при этом он не может использовать информацию экземпляра и класса. Зато он и не отличается от обычной функции. "Разумеется, при этом он не может использовать информацию экземпляра и класса." |
|||
25
Кирпич
01.08.13
✎
14:57
|
или ты хочешь свой callback в виртуальный метод засунуть?
|
|||
26
H A D G E H O G s
01.08.13
✎
14:58
|
Вообще спасибо большое этому головняку, у меня прям прыжок в понимании объектов.
|
|||
27
Кирпич
01.08.13
✎
14:59
|
тебе нужен self в классовом методе чтоли? нафига это надо, если можно использовать обычный метод.
|
|||
28
Кирпич
01.08.13
✎
15:00
|
(26) ну это все в книжках есть. просто никто не читает особо.
|
|||
29
H A D G E H O G s
01.08.13
✎
15:03
|
(27) У. Меня. Все. Работает.
Мне нужно было вооот это: ThreadProcAddress:=Self.MethodAddress('ThreadProc'); ThreadProcAddress:=MethodToProcedure(self,ThreadProcAddress); CreateThread(nil,0,ThreadProcAddress,nil,0,PID); Procedure T_vk_object.ThreadProc();stdcall; begin Self.iEvent.ExternalEvent('MyComponent','Создан поток',''); end; |
|||
30
H A D G E H O G s
01.08.13
✎
15:03
|
Self.iEvent.ExternalEvent('MyComponent','Создан поток','');
Ухожу от извращений с глобальными переменными. |
|||
31
H A D G E H O G s
01.08.13
✎
15:04
|
(28) Некогда читать. Надо писать код!
|
|||
32
Кирпич
01.08.13
✎
15:07
|
а чо спрашивать если работает :)
|
|||
33
H A D G E H O G s
01.08.13
✎
15:08
|
(32) Понять хотел, как работает.
|
|||
34
Кирпич
01.08.13
✎
15:13
|
если у тебя метод классовый, то наверное надо так
Procedure T_vk_object.ThreadProc(myself:TObject);stdcall; begin MySelf.iEvent.ExternalEvent('MyComponent','Создан поток',''); end; |
|||
35
Кирпич
01.08.13
✎
15:14
|
иначе в стеке так и останется твой self
|
|||
36
Кирпич
01.08.13
✎
15:14
|
это для дальнейшего понимания :)
|
|||
37
H A D G E H O G s
01.08.13
✎
15:16
|
Что ты делаешь, все же работает...
Дома отладчиком гляну, что придет в параметр myself |
|||
38
Кирпич
01.08.13
✎
16:07
|
(37) если ты будешь использовать MethodToProcedure и твой callback будет
class Procedure T_vk_object.ThreadProc();stdcall; static; то после N вызовов твоей T_vk_object.ThreadProc стек переполнится и твое творение рухнет. поэтому нужно делать так class Procedure T_vk_object.ThreadProc(myself:TObject);stdcall; static; или просто не использовать метод класса. он нафиг не нужен. Т.е. писать так Procedure T_vk_object.ThreadProc();stdcall; |
|||
39
Принт
01.08.13
✎
21:40
|
Высокий ООП с костылями на асме.. Оно такое точно нужно?
|
|||
40
Кирпич
02.08.13
✎
22:14
|
(39) ну иногда нужно. только не в этом случае конечно.
тут можно обойтись классом TThread и ничего не выдумывать. Можно писать на api и в функцию потока передавать свой объект. в функции потока для этого есть специальный параметр. у автора этого параметра почему-то нету. затупил наверное) но это не важно. важно чтобы автор не задавал глупые вопросы типа "2) Как программа определяет, что пошел код, а не данные? " |
Форум | Правила | Описание | Объявления | Секции | Поиск | Книга знаний | Вики-миста |