AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Algorithmen, Datenstrukturen und Klassendesign Delphi TVirtualMethodInterceptor - Wie kann ich zwei Methoden vergleichen?
Thema durchsuchen
Ansicht
Themen-Optionen

TVirtualMethodInterceptor - Wie kann ich zwei Methoden vergleichen?

Offene Frage von "backdraft"
Ein Thema von Der schöne Günther · begonnen am 29. Aug 2017 · letzter Beitrag vom 20. Apr 2023
Antwort Antwort
Der schöne Günther

Registriert seit: 6. Mär 2013
6.176 Beiträge
 
Delphi 10 Seattle Enterprise
 
#1

TVirtualMethodInterceptor - Wie kann ich zwei Methoden vergleichen?

  Alt 29. Aug 2017, 11:25
Angenommen ich nehme mir einen System.Rtti.TVirtualMethodInterceptor für eine fiktive Klasse TMyObject mit u. A. einer public procedure doStuff(); virtual; .

Der Interceptor geht ja hin und "proxified" ja grundsätzlich erst einmal ALLE Methoden derer er habhaft werden kann. In meinen OnBefore, OnAfter und OnException-Events (soweit gesetzt) muss ich ja nun erst einmal prüfen, ob ich gerade überhaupt meine "doStuff"-Methode intercepte. Bislang ist mir nichts besseres eingefallen als ein simpler String-Vergleich wie if (Method.Name = 'doStuff') then .

Gibt es hier keinen besseren Weg (kein String, schnellerer Vergleich), beispielsweise irgendwelche Zeiger zu vergleichen? Method.CodeAddress liefert mir leider nichts was ich sonst irgendwo wiederfinde...


PS: Die Interception-Mechanismen in z.B. Spring4D habe ich bislang nur überflogen. Kann ich dort im Vorhinein sagen dass ich nur bestimmte Methoden (z.B. mit einem Attribut) intercepten will und nicht gleich alle? Das ist doch sicher kein unnormaler Anwendungsfall. Bislang müsste ich dafür die System.Rtti.pas modifizieren.

Geändert von Der schöne Günther (29. Aug 2017 um 11:28 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.184 Beiträge
 
Delphi 12 Athens
 
#2

AW: TVirtualMethodInterceptor - Wie kann ich zwei Methoden vergleichen?

  Alt 29. Aug 2017, 12:21
Abgesehn davon, dass so das Programm auch extrem ausgebremst werden kann, wenn alles Intercepted ist, anstatt nur das gewollte.

Ich hatte mir da mal die Adressen der VMT gespeichert, den TVirtualMethodInterceptor auf die Klasse losgelassen und am Ende einfach alle Adressen wieder zurückgesetzt, welche ich nicht wollte.

Der TVirtualMethodInterceptor ist schon ein krankes Teil.
Es wäre ja nett, wenn da nicht alles so krankhaft weggekapselt wäre und man die Teilfunktionen auch einzeln nutzen könnte.
$2B or not $2B
  Mit Zitat antworten Zitat
Benutzerbild von Zacherl
Zacherl

Registriert seit: 3. Sep 2004
4.629 Beiträge
 
Delphi 10.2 Tokyo Starter
 
#3

AW: TVirtualMethodInterceptor - Wie kann ich zwei Methoden vergleichen?

  Alt 29. Aug 2017, 13:09
Einzelne Methoden zu hooken geht auch ohne RTTI recht trivial und zudem noch deutlich performanter.

Im Grunde musst du nur über die VMT der zu hookenden Instanz iterieren und dort den Zeiger auf deine Zielfuntkion suchen. Sobald du Diesen gefunden hast, sicherst du ihn und schreibst stattdessen den Zeiger zu deiner Callback-Funktion. Innerhalb der Callback-Funktion kannst du nun ganz dynamisch entscheiden, ob du die originale Funktion aufrufen willst (und sogar deren Parameter modifizieren, etc.).
Projekte:
- GitHub (Profil, zyantific)
- zYan Disassembler Engine ( Zydis Online, Zydis GitHub)
  Mit Zitat antworten Zitat
Der schöne Günther

Registriert seit: 6. Mär 2013
6.176 Beiträge
 
Delphi 10 Seattle Enterprise
 
#4

AW: TVirtualMethodInterceptor - Wie kann ich zwei Methoden vergleichen?

  Alt 29. Aug 2017, 13:30
Was mir am TVirtualMethodInterceptor so sympathisch war: Er ist eine Abstraktion. Ich habe bis heute keine Ahnung was in einer VMT so üblicherweise drinsteht. Er tut fast 100%ig was er soll - Nur ein bisschen sehr schwerfällig und übermotiviert.

Als ersten Schritt wollte ich den String-Vergleich rausbekommen, denn kein Delphi-Refactoring-Tool der Welt erwischt so etwas, sollte die Methode einmal umbenannt werden (oder?).
  Mit Zitat antworten Zitat
Benutzerbild von Zacherl
Zacherl

Registriert seit: 3. Sep 2004
4.629 Beiträge
 
Delphi 10.2 Tokyo Starter
 
#5

AW: TVirtualMethodInterceptor - Wie kann ich zwei Methoden vergleichen?

  Alt 29. Aug 2017, 13:34
Als ersten Schritt wollte ich den String-Vergleich rausbekommen, denn kein Delphi-Refactoring-Tool der Welt erwischt so etwas, sollte die Methode einmal umbenannt werden (oder?).
Vollkommen korrekt, ja.

Die Delphi VMT ist COM-kompatibel, was bedeutet, dass sie einfach als array of Pointer implementiert ist und auch immer sein wird. Hierbei zeigt das erste Element auf die erste virtuelle Methode, das zweite Element auf die zweite virtuelle Methode, etc.

Hab mal aus dem Kopf ganz schnell was zusammengehackt:
Delphi-Quellcode:
type
  TBaseClass = class
  public
    procedure Virt1(const S: String); virtual;
    procedure Virt2(const S: String); virtual;
    procedure Virt3(const S: String); virtual;
  end;

  TDerivedClass = class(TBaseClass)
  public
    procedure Virt2(const S: String); override;
  end;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    class var FOriginalVirt2: procedure(Self: TBaseClass; const S: String);
    class procedure CallbackVirt2(Self: TBaseClass; const S: String); static;
  public
    procedure Hook(Instance: TObject; Target, Callback: Pointer; var OriginalFunc: Pointer);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

{ TBaseClass }

procedure TBaseClass.Virt1(const S: String);
begin
  ShowMessage('A1: ' + S);
end;

procedure TBaseClass.Virt2(const S: String);
begin
  ShowMessage('A2: ' + S);
end;

procedure TBaseClass.Virt3(const S: String);
begin
  ShowMessage('A3: ' + S);
end;

{ TDerivedClass }

procedure TDerivedClass.Virt2(const S: String);
begin
  ShowMessage('B2: ' + S);
end;

class procedure TForm1.CallbackVirt2(Self: TBaseClass; const S: String);
begin
  FOriginalVirt2(Self, '[Intercepted]' + S);
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  C: TBaseClass;
begin
  C := TDerivedClass.Create;
  try
    C.Virt2('test');
    // Wichtig ist hier `TDerivedClass.Virt2` und nicht `TBaseClass.Virt2` zu verwenden!
    Hook(C, @TDerivedClass.Virt2, @CallbackVirt2, @FOriginalVirt2);
    C.Virt2('test');
  finally
    C.Free;
  end;
end;

procedure TForm1.Hook(Instance: TObject; Target, Callback: Pointer; var OriginalFunc: Pointer);
type
  PVMT = ^TVMT;
  TVMT = array[0..0] of Pointer;
var
  VMT: PVMT;
  I: Integer;
  OldProtect: DWord;
begin
  VMT := Pointer(Pointer(Instance)^);
  I := 0;
  // Achtung: Endlosschleife, wenn Target nicht existiert!
  while (VMT^[I] <> Target) do
  begin
    Inc(I);
  end;
  ShowMessage(I.ToString);
  OriginalFunc := VMT^[I];
  VirtualProtect(VMT, I * SizeOf(Pointer), PAGE_READWRITE, OldProtect);
  VMT^[I] := Callback;
  VirtualProtect(VMT, I * SizeOf(Pointer), OldProtect, OldProtect);
end;
Projekte:
- GitHub (Profil, zyantific)
- zYan Disassembler Engine ( Zydis Online, Zydis GitHub)
  Mit Zitat antworten Zitat
backdraft

Registriert seit: 19. Apr 2005
Ort: Hückeswagen
335 Beiträge
 
Delphi 11 Alexandria
 
#6

AW: TVirtualMethodInterceptor - Wie kann ich zwei Methoden vergleichen?

  Alt 20. Apr 2023, 15:29
Als ersten Schritt wollte ich den String-Vergleich rausbekommen, denn kein Delphi-Refactoring-Tool der Welt erwischt so etwas, sollte die Methode einmal umbenannt werden (oder?).
Vollkommen korrekt, ja.

Die Delphi VMT ist COM-kompatibel, was bedeutet, dass sie einfach als array of Pointer implementiert ist und auch immer sein wird. Hierbei zeigt das erste Element auf die erste virtuelle Methode, das zweite Element auf die zweite virtuelle Methode, etc.

Hab mal aus dem Kopf ganz schnell was zusammengehackt:
Würde auch ein "inherited" in der FOriginalVirt2 funktionieren?
Könnte man sich so auch in den Destructor hängen von einer Klasse?
Oliver
  Mit Zitat antworten Zitat
Antwort Antwort

 

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 00:50 Uhr.
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