Имя: Пароль:
IT
 
Delphi. Методы объектов как то по другому хранятся в памяти?
0 H A D G E H O G s
 
30.09.11
13:39
День добрый.
Собственно ситуация.
Есть рабочий код:

function MessageHooker1(Code: Integer; WParam: wParam; LParam: LParam): LongInt;stdcall;
var HookStructure:PHookStructure;
begin
HookStructure:=ptr(LParam);
if (Code>=HC_ACTION) and (HookStructure<>nil) then begin
if HookStructure^.MSG=WM_MOVE  then
showmessage('URRRRA');
end;
Result :=1;
//Result := CallNextHookEx(HookHandle, Code, wParam, LParam);
end;

Procedure Test1();stdcall;
var addr:pointer;
HookHandle:Cardinal;
begin
addr:= @MessageHooker1;
HookHandle:=SetWindowsHookEx(WH_CALLWNDPROC,addr , 0, GetCurrentThreadId());
End;
1 Jstunner
 
30.09.11
13:41
глаза режет
2 H A D G E H O G s
 
30.09.11
13:41
И есть идентичный нерабочий:

function TMyObject.MessageHooker2(Code: Integer; WParam: wParam; LParam: LParam): LongInt;stdcall;
var HookStructure:PHookStructure;
begin
HookStructure:=ptr(LParam);
if (Code>=HC_ACTION) and (HookStructure<>nil) then begin
if HookStructure^.MSG=WM_MOVE  then
showmessage('URRRRA');
end;
Result :=1;
//Result := CallNextHookEx(HookHandle, Code, wParam, LParam);
end;

procedure TMyObject.StartHook;
var addr:pointer;
HookHandle:Cardinal;
begin
addr:= Self.MethodAddress('MessageHooker2');
HookHandle:=SetWindowsHookEx(WH_CALLWNDPROC,addr , 0, GetCurrentThreadId());
end;

Причем в нерабочем коде (через объект) - в callback процедуру управление передается, но вот LParam указывает то на мусор, то вообще на нечитаемую область памяти.

ЧЯДНТ?
3 posq
 
30.09.11
13:43
Ааа... Хуки...
4 posq
 
30.09.11
13:43
Как же хорошо что я все это два года назад забыл.
5 Ненавижу 1С
 
гуру
30.09.11
13:49
по-другому конечно, он вызываться будет для какого объекта?
короче, оберни в обычную процедуру из которой и вызывай метод СВОЕГО объекта
6 Serginio1
 
30.09.11
13:51
Адрес адресом, а во Self нужно указать. Для этого существует функция которая создает в памяти запись self в регистр и переход к процедуре. чнго то там Make...
7 H A D G E H O G s
 
30.09.11
13:53
(5) Еще раз.
Медленно и по другому.
8 Serginio1
 
30.09.11
13:54
Посмотри
MakeObjectInstance
9 Serginio1
 
30.09.11
13:55
Посмотри в Windows. Она там часто используется
10 Ненавижу 1С
 
гуру
30.09.11
13:56
function MessageHooker3(Code: Integer; WParam: wParam; LParam: LParam): LongInt;stdcall;
begin
 Result:=YourObject.MessageHooker1(Code,WParam,LParam);
end;

addr:= Self.MethodAddress('MessageHooker3');
11 Кирпич
 
30.09.11
14:03
Delphi в метод объекта всегда передает первым параметром Self

т.е. написано так
function TMyObject.MessageHooker3(Code: Integer; WParam: wParam; LParam: LParam)

а на самом деле так
function  (SELF;Code: Integer; WParam: wParam; LParam: LParam)

windows вызовет MessageHooker3 с тремя параметрами, а на самом деле там четыре параметра.
можно в реализации метода вставить на асме чо нибудь чтобы стек подправил. или использовать обычную процедуру, куда ссылка на объект не передается.
12 Serginio1
 
30.09.11
14:03
Для примера http://delphi-faq.zoxt.net/1642.htm
13 H A D G E H O G s
 
30.09.11
14:06
(11) Ясно.
Блинн, вчера весь вечер себе сломал из за этого.
14 H A D G E H O G s
 
30.09.11
14:12
(11) Тоесть, первые 4 байта переданные Windows - мне будут недоступны?
15 H A D G E H O G s
 
30.09.11
14:14
(12) Там подмена оконной процедуры своей процедурой с последующим вызовом старой процедуры.
Это как раз то, от чего я сейчас избавляюсь.
16 Кирпич
 
30.09.11
14:22
(14) Да доступны. Надо там указатель стека сдвинуть что ли, или адрес первого параметра в регистре каком то. Я уж забыл как, но делал когда то. В дебаггере глянь.
17 Serginio1
 
30.09.11
15:13
(15) В SetWindowsHookEx тебе нужно передать ссылку на статический метод MakeObjectInstance как раз и создает такой метод но определенной сигнатуры. Еще была аналогичная процедура посмотри

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;

function MethodToProcedure(method: TMethod) : pointer;
begin
 result := MethodToProcedure(TObject(method.data), method.code);
end;

function ProcedureToMethod(self: TObject; procAddr: pointer) : TMethod;
begin
 result.Data := self;
 result.Code := procAddr;
end;
18 Serginio1
 
30.09.11
15:18
У меня нт delph под рукой посмотри. По уму там и MakeObjectInstance подойдет,главное присвоить ссылку уже типизированной переменной содержащий нужную сигнатуру метода
19 Serginio1
 
30.09.11
15:27
Вот метод
function MakeObjectInstance(Method: TWndMethod): Pointer;
const
 BlockCode: array[1..2] of Byte = (
   $59,       { POP ECX }
   $E9);      { JMP StdWndProc }
 PageSize = 4096;
var
 Block: PInstanceBlock;
 Instance: PObjectInstance;
begin
 if InstFreeList = nil then
 begin
   Block := VirtualAlloc(nil, PageSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
   Block^.Next := InstBlockList;
   Move(BlockCode, Block^.Code, SizeOf(BlockCode));
   Block^.WndProcPtr := Pointer(CalcJmpOffset(@Block^.Code[2], @StdWndProc));
   Instance := @Block^.Instances;
   repeat
     Instance^.Code := $E8;  { CALL NEAR PTR Offset }
     Instance^.Offset := CalcJmpOffset(Instance, @Block^.Code);
     Instance^.Next := InstFreeList;
     InstFreeList := Instance;
     Inc(Longint(Instance), SizeOf(TObjectInstance));
   until Longint(Instance) - Longint(Block) >= SizeOf(TInstanceBlock);
   InstBlockList := Block;
 end;
 Result := InstFreeList;
 Instance := InstFreeList;
 InstFreeList := Instance^.Next;
 Instance^.Method := Method;
end;
20 Serginio1
 
30.09.11
15:33
21 H A D G E H O G s
 
30.09.11
15:40
(20) Посмотрю, спасибо.
22 Serginio1
 
30.09.11
15:50