![]() |
TVirtualMethodInterceptor
Es wird wieder etwas esoterisch. Angenommen ich habe folgende zwei Klassen:
Delphi-Quellcode:
und lasse einen
TBase = class
procedure testMethod(); virtual; end; TSub = class(TBase) procedure testMethod(); override; end;
Delphi-Quellcode:
aus
TVirtualMethodInterceptor
Delphi-Quellcode:
darauf los:
System.Rtti
Delphi-Quellcode:
Dann bekomme ich leider ein
procedure TForm1.FormCreate(Sender: TObject);
begin obj := TSub.Create(); interceptor := TVirtualMethodInterceptor.Create( obj.ClassType() ); interceptor.OnAfter := interceptAfter; interceptor.Proxify(obj); obj.testMethod(); end; procedure TForm1.interceptAfter(Instance: TObject; Method: TRttiMethod; const Args: TArray<TValue>; var Result: TValue); begin if Method.CodeAddress = Addr(TBase.testMethod) then ShowMessage('After base method'); if Method.CodeAddress = Addr(TSub.testMethod) then ShowMessage('After sub method'); end;
Delphi-Quellcode:
. Für die
ShowMessage('After base method');
Delphi-Quellcode:
oder
OnBefore
Delphi-Quellcode:
-Handler des
OnException
Delphi-Quellcode:
verhält es sich ebenso.
TVirtualMethodInterceptor
Wie kann ich feststellen dass
Delphi-Quellcode:
ausgeführt wird? Ich hatte den Compiler im Verdacht dass er mir hier das inlined und es in Wirklichkeit keine virtuelle Methode ist. Wirklich prüfen und beweisen könnte ich das aber wahrscheinlich nur wenn ich mit Assemblercode lesen könnte.
TSub.testMethod()
PS: Leicht ähnliches Thema: ![]() Meine Motivation ist dass halt bei einer bestimmten Methode dazwischen grätschen will und der String-Vergleich mit
Delphi-Quellcode:
echt unschön ist.
Method.Name
Delphi-Quellcode:
sieht da gleich viel besser aus, das funktioniert ja auch wenn jemand die Methode umbenennt.
Method.CodeAddress
PPS: Ich bin mir generell unsicher ob das Statement
Delphi-Quellcode:
überhaupt richtig ist. Angenommen, ich überlade testMethod(). Auf was Zeigt Addr(TBase.testMethod) dann eigentlich?
Addr(TBase.testMethod)
|
AW: TVirtualMethodInterceptor
Kurios, Instance.ClassType zeigt im Debugger TSub an, meint aber zur Laufzeit, dass es nicht TSub ist?
:gruebel:
Delphi-Quellcode:
unit Unit3;
interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, System.Rtti; type TBase = class procedure testMethod(); virtual; end; TSub = class(TBase) procedure testMethod(); override; end; TForm3 = class(TForm) procedure FormCreate(Sender: TObject); private obj: TSub; interceptor: TVirtualMethodInterceptor; procedure interceptAfter(Instance: TObject; Method: TRttiMethod; const Args: TArray<TValue>; var Result: TValue); { Private declarations } public { Public declarations } end; var Form3: TForm3; implementation {$R *.dfm} procedure TForm3.FormCreate(Sender: TObject); var clazz: TClass; begin obj := TSub.Create(); clazz := obj.ClassType(); interceptor := TVirtualMethodInterceptor.Create(clazz); interceptor.OnAfter := interceptAfter; interceptor.Proxify(obj); obj.testMethod(); end; procedure TForm3.interceptAfter(Instance: TObject; Method: TRttiMethod; const Args: TArray<TValue>; var Result: TValue); var Ptr1, Ptr2, Ptr3, Ptr4: Pointer; obj: TSub; MyMethod: TMethod; begin Ptr1 := Method.CodeAddress; if Instance.ClassType = TBase then begin Ptr2 := Addr(TBase.testMethod); if Ptr1 = Ptr2 then ShowMessage('After base method'); end; if Instance.ClassType = TSub then begin Ptr3 := Addr(TSub.testMethod); if Ptr1 = Ptr3 then ShowMessage('After sub method'); end; end; { TBase } procedure TBase.testMethod; begin end; { TSub } procedure TSub.testMethod; begin inherited; end; end. |
AW: TVirtualMethodInterceptor
Zitat:
Delphi-Quellcode:
vor und nach dem Proxify.
obj.ClassType = TSub
Man kann das aber trotzdem realisieren mit
Delphi-Quellcode:
if Instance.ClassNameIs(TSub.ClassName) then
|
AW: TVirtualMethodInterceptor
Der Interceptor erstellt zur Laufzeit eine virtuelle Klasse, also einen Nachfahren der Klasse, wo du dich reinhookst.
Anschließend wird für "alle" virtuellen Methoden (virtual) quasi je eine generische Dummymethode erstellt, welche die Events des Interceptor aufruft. Dann werden noch in der "kopierten" VirtualMethodTable (VMT) die Methodenzeiger überschrieben und durch die Dummymethoden ersetzt. Und in dem gehookten Objekt wird nun noch die eigene Klassenreferenz (die vom Create) gegen die neue Klasse ausgetauscht. Und schwups, schon ist deine Instanz eine "andere" Klasse. Also quasi so, als wenn du TSub nochmal ableitest und dein Objekt damit erstellt hast, aber alle deine Prüfungen kennen nur TSup und TBase, aber nicht die letzte Ableitung. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 13:52 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz