Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Hook in Klasse einbinden... (https://www.delphipraxis.net/52343-hook-klasse-einbinden.html)

glkgereon 28. Aug 2005 12:11


Hook in Klasse einbinden...
 
Hi

ich habe folgendes Konstrukt(gekürzt):
Delphi-Quellcode:
TTastaturStatistik = class(TObject)
  //Tastatur
  private
    FOverAll: Int64;
    HookHandle: Cardinal;
    //Set-Methoden
    procedure SetKeyHits(New: Int64);
    //Hook
    procedure Hook;
    procedure UnHook;
  public
    constructor Create;
    destructor Destroy;
    //Propertys
    property KeyHits:Int64 read FOverAll write SetKeyHits;
  end;

implementation

procedure TTastaturStatistik.Hook;
//Hook aktivieren
begin
  HookHandle := SetWindowsHookEx(WH_KEYBOARD_LL, LLKeyboardHookProc, hInstance, 0); //HIER 2
  if HookHandle = 0 then RaiseLastOSError;
end;

procedure TTastaturStatistik.UnHook;
//Hook deaktivieren
begin
  if HookHandle <> 0 then
    begin
    UnhookWindowsHookEx(HookHandle);
    HookHandle := 0;
    end;
end;

function LLKeyboardHookProc(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
//Wenn Taste gedrückt wird
begin
  if nCode = HC_ACTION then //lParam ist richtiger Typ
    Inc(FOverAll); //HIER 1
  Result := CallNextHookEx(HookHandle, nCode, wParam, lParam);
end;
nur das geht ja nicht (HIER 1), da ich so FOverAll ja nicht ansprechen kann :(

wenn ich allerdings LLKeyboardHookProc als Private der Klasse deklariere, dann kommt bei HIER 2 der Fehler das LLKeyboardHookProc eine reguläre Procedure und kein Methodenzeiger sei...

hat irgendwer eine Lösung für mich?

Edit: DUDEN, hilf mir :mrgreen:
der Code ist übrigens im wesentlichen von Flocke...

DGL-luke 28. Aug 2005 15:48

Re: Hook in Klasse einbinden...
 
Ich weiss nicht mehr genau wie es ging, aber es gibt da einen kleinen asm trick, um eine klassenmethode beim hook zu registrieren.

und es müsste auch mit

Delphi-Quellcode:
SetWindowsHookEx(WH_KEYBOARD_LL, TTastaturStatistik.LLKeyboardHookProc, hInstance, 0); //HIER 2
also mit dem klassennamen(!) funktionieren.

noch fragen?

du musst mal im forum suchen, irgendwo steht der assembler trick auch. müsste sogar in dem thread von flocke sein.

SirThornberry 28. Aug 2005 16:16

Re: Hook in Klasse einbinden...
 
mit dem klassennamen das geht nicht weil der unsichtbare Self-Parameter nicht bei der HookProcedure als erster Parameter mitkommt, sondern es kommt die Action mit. Als Umweg könnte man zur Laufzeit eine Procedure im Speicher erzeugen und dort fest den Self-Paremter reinpatchen. Diese zur Laufzeit erzeugte Procedure kann dann wiederum die Klassenmethode mit den entsprechenden parametern aufrufen.

Flocke 28. Aug 2005 16:29

Re: Hook in Klasse einbinden...
 
Du kannst es ähnlich machen wie Delphi mit den Fensterprozeduren. Dazu solltest du dir mal den Code zu "MakeObjectInstance" in Classes.pas ansehen.

Du brauchst in Assembler einen Stub wie:
Code:
pop eax  // Rücksprungadresse runter
push Self // Self auf den Stack legen (32-Bit Wert / Zeiger)
push eax  // Rücksprungadresse wieder drauf
jmp TTastaturStatistik.LLKeyboardHookProc
LLKeyboardHookProc muss natürlich "stdcall" deklariert sein.

Den Speicherblock musst du dir mit
Delphi-Quellcode:
Block := VirtualAlloc(nil, PageSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
holen und dann statt deiner Prozedur eben "Block" als Zeiger bei SetWindowsHookEx angeben.

[Nachtrag]

Beispielcode (ungetestet):

Delphi-Quellcode:
function ClassProcAsHook(Obj: TObject; Method: Pointer): Pointer;
type
  PCodeBlock = ^TCodeBlock;
  TCodeBlock = packed record
    bPopEax: byte;
    bPushImm32: byte;
    lSelf: longint;
    bPushEax: byte;
    bJmpDisp32: byte;
    lDisp: longint;
  end;
var
  Block: PCodeBlock;
begin
  Block := VirtualAlloc(nil, SizeOf(TCodeBlock), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
  Block^.bPopEax := $58;
  Block^.bPushImm32 := $68;
  Block^.lSelf := longint(Obj);
  Block^.bPushEax := $50;
  Block^.bJmpDisp32 := $E9;
  Block^.lDisp := longint(Method) - (longint(@Block^.lDisp) + 4);
  Result := Block;
end;
Beim Opcode für PUSH bin ich mir nicht ganz sicher, bitte überprüfen.

NicoDE 28. Aug 2005 16:37

Re: Hook in Klasse einbinden...
 
http://www.delphipraxis.net/internal...=387393#387393

Flocke 28. Aug 2005 16:44

Re: Hook in Klasse einbinden...
 
@Nico: :thumb: natürlich wesentlich besser, da nicht eben so hingehackt 8)

glkgereon 28. Aug 2005 19:15

Re: Hook in Klasse einbinden...
 
hmmm :gruebel:

ich glaub das is mir etwas zu schnell...

also ich soll zur laufzeit eine procedure erzeugen, die dann die klassen-proc aufruft?

auch wenn ihr das eigentlich nicht macht, könntet ihr mir das ausnahmsweise in meinen quelltext einbauen? *ganz lieb guck*

ich werds zwar auch versuchen, aber ehrlich gesagt würde ich da keine große hoffnung hegen :(

NicoDE 28. Aug 2005 19:31

Re: Hook in Klasse einbinden...
 
Also...

Das Problem ist, dass die Win32-API-Funktion eine Callback-Funktion mit einem bestimmten Funktionstyp erwartet. Methoden haben aber einen impliziten ersten Parameter (Self). Es nutzt also nichts, die Methode an die API-Funktion weiterzugeben, da sie immer inkompatibel ist.
Die Lösung besteht nun darin, eine Funktion zur Laufzeit zu erzeugen (da Self nicht statisch ist), welche aufrufkompatibel zur API-Funktion ist und nichts anderes macht, als deine gewünschte Methode in der Klasse aufzurufen. Es gibt dann also zwei Callback-Funktionen: eine Callback-Methode und eine Callback-Funktion (die wiederum nur die Methode aufruft).

Am besten siehst Du dir das Beispiel im o.g. Thead an.
( http://www.delphipraxis.net/internal...=387139#387139 )

glkgereon 28. Aug 2005 19:55

Re: Hook in Klasse einbinden...
 
also müsste ich das in etwa so machen:

Delphi-Quellcode:
type
  TCallback = procedure(bla: Integer); cdecl;
  TMethodCallback = procedure(bla: Integer) of object; cdecl;
TDings = class
private
  FCallback: TCallback;
  FMethodCallback: TMethodCallback;
  Method(bla: Integer); cdecl;
end;

//erstellen
  FCallback := TCallback(MakeCdeclCallback(TMethod(FMethodCallback), 4));
  FMethodCallback := Method;


procedure TDings.Method(bla: Integer); cdecl;
begin
  ShowMessage('MethodCallback: ' + string(Text));
end;

//weg damit
  FreeCdeclCallback(@FCallback);

//Hooken
HookHandle := SetWindowsHookEx(WH_KEYBOARD_LL, FCallback, hInstance, 0);
stimmt das alles?

Flocke 28. Aug 2005 21:37

Re: Hook in Klasse einbinden...
 
Eher so (auf dein erstes Beispiel angewendet, ungetestet):
Code:
TTastaturStatistik = class(TObject)
  //Tastatur
  private
    FOverAll: Int64;
    HookHandle: Cardinal;
    [b]FCallback: Pointer;[/b]
    //Set-Methoden
    procedure SetKeyHits(New: Int64);
    //Hook
    procedure Hook;
    procedure UnHook;
    [b]function LLKeyboardHookProc(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;[/b]
  public
    constructor Create;
    destructor Destroy;
    //Propertys
    property KeyHits:Int64 read FOverAll write SetKeyHits;
  end;

implementation

procedure TTastaturStatistik.Hook;
//Hook aktivieren
begin
  [b]FCallback := MakeStdcallCallback([color=red]LLKeyboardHookProc[/color]);[/b]
  HookHandle := SetWindowsHookEx(WH_KEYBOARD_LL, [b]FCallback[/b], hInstance, 0); //HIER 2
  if HookHandle = 0 then RaiseLastOSError;
end;

procedure TTastaturStatistik.UnHook;
//Hook deaktivieren
begin
  if HookHandle <> 0 then
    begin
    UnhookWindowsHookEx(HookHandle);
    HookHandle := 0;
    end;
[b] if FCallback <> nil then
  begin
    FreeCallback(FCallback);
    FCallback := nil;
  end;[/b]
end;

function [b]TTastaturStatistik[/b].LLKeyboardHookProc(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
//Wenn Taste gedrückt wird
begin
  if nCode = HC_ACTION then //lParam ist richtiger Typ
    Inc(FOverAll); //HIER 1
  Result := CallNextHookEx(HookHandle, nCode, wParam, lParam);
end;
So ist LLKeyboardHookProc eine Methode deiner Klasse und du kannst Self usw. darin benutzen.

Bei der roten Stelle bin ich mir nicht sicher, ob da ein Cast herum muss.


Alle Zeitangaben in WEZ +1. Es ist jetzt 14:01 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz