![]() |
Methodenaufruf umbiegen?
Hi,
Ich komme einfach direkt zum Punkt:
Delphi-Quellcode:
Ist es möglich einen Aufruf von GetTest auf GetTest2 umzubiegen?
TTest = class
function GetTest: String; function GetTest2: String; end; |
Re: Methodenaufruf umbiegen?
Mit ein wenig Umweg:
Delphi-Quellcode:
Und die Zuweisungen kannst du zur Runtime beliebig umherwürfeln. Ich bin mir grad nur unsicher, ob die Syntax für TMyFunc so geht, bislang hatte ich irgendwie immer nur procedure of object genutzt :)
type
TMyFunc = function: String of object; TMyClass private function FFunc1: String; function FFunc2: String; public GetText: TMyFunc; GetText2: TMyFunc; end; implementation constructor TMyClass(...) begin GetText := FFunc1; GetText2 := FFunc2; end; |
Re: Methodenaufruf umbiegen?
Hi,
Ich habs wohl zu allgemein ausgedrückt.. Auf die Struktur der Klasse habe ich letztendlich keinen Einfluss. Genauer gesagt habe ich soetwas:
Delphi-Quellcode:
Diese Klasse ist jetzt auch fest. Daran darf im Code nichts geändert werden.
TBeispiel = class
private FText: String; function GetText: String; public property Text: String read GetText; end; Was ich jetzt per RTTI rausfinden kann sind die Properties. Ich hab den Namen der Property und die Pointer zu der jeweiligen Getter und Setter Methode. Was ich jetzt prinzipiell will ist GetText zu "hooken". So in der Art:
Delphi-Quellcode:
function GetTextHook(Self: TBeispiel): String;
begin Result := Self.GetText + '_Hooked!'; end; HookProperty(TBeispiel,'Test',mkGetter,@GetTextHook); |
Re: Methodenaufruf umbiegen?
Wie wäre es mit einer Ableitung der Klasse, die alles wie ihr Vorfahr durchreicht, aber die Property überdeckt und auf decorator-artige Weise erweitert? (Ich weiss nur grad nicht so 100%ig ob sich Properties überhaupt verdecken lassen...)
|
Re: Methodenaufruf umbiegen?
Wenn du das hooken willst, musst du das ganz klassisch machen, also einen Jump bzw. Call an den Anfang des Methodencodes schreiben.
|
Re: Methodenaufruf umbiegen?
Zitat:
Code:
(gut, man darf dieses jetzt nicht wörtlich nehmen, denn es würde eine kleine Endlosschleife entstehen :stupid: )
result := [color=#ff0000]Self.GetText[/color] + '_Hooked!';
|
Re: Methodenaufruf umbiegen?
Zitat:
Zitat:
|
Re: Methodenaufruf umbiegen?
Es geht aber nicht anders. Eigenschaften existieren im Kompilat nur noch als RTTI, die Aufrufe selbst sind nur noch Methodenaufrufe bzw. Feldzugriffe. Zum Hooken musst du dir irgendeine Grenze zwischen Anweisungen suchen. Das ist ein bisschen schwierig, weil du dazu schon fast Maschinencode parsen musst. Quick & Dirty geht es aber meistens, schau dir einfach mal an, was für Code der Delphi-Compiler im Prolog generiert.
|
Re: Methodenaufruf umbiegen?
Das hier:
Delphi-Quellcode:
allerdings ist da halt wirklich nicht viel Platz... :?
push ebx
mov ebx, edx // Result := 'Test'; mov eax, ebx mov edx, $004D6A10 call UStrAsg // end; pop ebx ret Das sind also 3 Bytes bevor der "Result := 'Test'"-Teil kommt... etwas wenig.. |
Re: Methodenaufruf umbiegen?
Zitat:
Edit: Alles andere liefe auf recht unschönes Gehacke in der Methodentabelle hinaus, was nicht nur extrem unelegant ist, sondern aufgrund der Freiheit die ein Compiler da hat auch praktisch unportierbar - möglicherweise eben auch innerhalb der Delphiversionen. Evtl. können wir besser hier weiter machen, wenn du konkret vorstellst, was du möchtest, und vor allem in welchem Kontext. Die bisherigen Beispiele waren offenbar zu stark minimiert. |
Re: Methodenaufruf umbiegen?
Es soll aber mit JEDER Klasse funktionieren. Wie soll ich von ner Klasse ableiten, die jemand der meine Unit benutzen wird gerade erst baut?
|
Re: Methodenaufruf umbiegen?
Du brauchs nen codeoverwriting hook, z.b. den von madshi. Der kann ruhig mehr überschreiben und kann im Anschluss trotzdem noch die Funktion ausführen (da die bytes gesichert werden).
Wenn du es dennoch selbst machen willst gibts mehrere möglichkeiten: 1) dubiegst den relativen jump um der dahinspringt 2) du überschreibst (und in deiner hookroutine schreibst die alten bytes zurück -> langsam und net threadsafe) 3) du verwendest Hardwarebreakpoints bzw. einen int 3 hook (also setzt einen int 3 = breakpoint + hooks den exceptionhandler und fängst deine ab) -> ebenfalls net sonderlich schnell |
Re: Methodenaufruf umbiegen?
Class Helper in Delphi können eine Funktion überdecken (oder hinzufügen), ohne die bestehende Klasse ändern zu müssen:
![]() Sie sind damit quasi das GOTO der objektorientierten Programmierung :) Cheers, |
Re: Methodenaufruf umbiegen?
AHA! Das muss ja nu auch gesagt werden ;) Gekapseltes Verhalten fremder Klassen zu manipulieren fällt definitiv eh schon unter "dirty hack". Was tut deine Unit? Vielleicht fände sich ja generell noch ein Ansatz der mir weniger Kopfweh machen würde :stupid:
Edit: Class-Helper sind auch ein Weg, und werden auch gern zu Decorator-Zwecken genommen. Ich hatte die nur aussen vor gelassen, da ich Gedanklich noch in Delphi 7 stecke, und es sowat da noch nicht gab :angel: |
Re: Methodenaufruf umbiegen?
Zitat:
|
Re: Methodenaufruf umbiegen?
Zitat:
Leute.. Wenn man mein Problem mit OOP lösen könnte, dann hätte ich das schon getan :freak: Was bringt mir ein Class Helper wenn ich Properties von fremden, mir nicht bekannten Klassen überwachen will? :? |
Re: Methodenaufruf umbiegen?
Hat nicht jede jedes Objekt im Speicher eine interene Tabelle, in der Pointer auf die jeweiligen Methoden enthalten sind? Zumindest bei virtuellen bzw. überschriebenen Methoden ist das doch nötig. Eventuell könntest du es darüber irgendwie probieren...
Ansonsten: Könnte man das nicht mit einem Class Helper umsetzen? Ich habe leider keine Erfahrung mit diesen, weil ich keine Delphi-Version besitze, die Class Helper unterstützt, aber so wie ich es verstehe, sind sie ja sozusagen "Patches" für Klassen. Damit wären sie doch eigentlich das, was du brauchst. Edit: @Beitrag über mir: Natürlich bringen Class Helpers nur etwas, wenn sie die Möglichkeit bieten, Methoden zu überschreiben. Davon bin ich ausgegangen. Ist das nicht der Fall, dann ignoriere meinen Vorschlag einfach. |
Re: Methodenaufruf umbiegen?
Nein, bei sowas werden die Prozeduren direkt angesprungen.
z.B. bei der WinAPI (DLL-Exports) gibt es sowas - der Spung zur Tabelle ist hartcodiert und dort ist dann die Tabelle, da die Adressen ja veränderlich sind. virtuelle und dynamische Methoden stehen auch in Tabellen |
Re: Methodenaufruf umbiegen?
Zitat:
Und selbst DANN gibt es fast immer noch Wege an die man selbst evtl. dann doch noch nicht gedacht hat - nobody is perfect. Und da uns partout nicht erzählen magst, was du im großen und ganzen vor hast (um evtl. einen anderen Weg zu finden - was ja schon irgendwo in deinem Interesse sein dürfte), klinke ich mich mal aus. Weil dass das so wie von dir erhofft eher nix wird dürfte nun ja klar genug geworden sein - so "tänzelnde" Beiträge der Art "hmmm, was hast'n vor, das geht evtl. anders" deuten da ja eigentlich ganz gut drauf hin. |
Re: Methodenaufruf umbiegen?
Zitat:
Delphi-Quellcode:
Bei beiden Instanzen sollte DoSomething auf die gleiche Adresse zeigen. Trotzdem kommt jeweils ein anderes Ergebnis zurück. Damit das funktioniert, muss irgendwo eine Tabelle existieren, die die Methodenzeiger enthält. Woher sollte die Klasse sonst wissen, welche Methode aufgerufen werden muss? Wenn eine Methode nicht virtuell ist, ist das natürlich etwas anderes, dann kann der Compiler diesen Schritt wegoptimieren.
type
TClassA = class(TObject) protected function GetMesage: string; virtual; public procedure DoSomething; end; TClassB = class(TClassA ) protected function GetMesage: string; override; end; implementation procedure TClassA.DoSomething; begin ShowMessage(GetMessage); end; function TClassA.GetMessage: string; begin Result := 'Grüße der Basisklasse'; end; function TClassB.GetMessage: string; begin Result := 'Hier spricht ClassB'; end; var Something: TClassA; begin Something := TClassA.Create; Something.DoSomething; // TClassA.DoSomething wird aufgerufen Something.Free; Something := TClassB.Create; Something.DoSomething; // WIEDER wird TClassA.DoSomething aufgerufen, aber mit anderem Ergebnis Something.Free; end. Edit: Ach verdammt, hab dein Edit übersehen :wall: |
Re: Methodenaufruf umbiegen?
Zitat:
Nja, aber er hat ja anscheinend statische Methoden und die brauchen auch keine Tabellen, da sie sich ja normaler Weise nicht ändern und es somit "sinnlose" Sprünge ergeben würde. |
Re: Methodenaufruf umbiegen?
Zitat:
Mein Vorhaben hat absolut nichts mit OOP zu tun :roll: Zitat:
Angenommen ich baue einen Nachfolger von TEdit, der die Caption eines Buttons anzeigt. Der Programmierer kann dann dem Edit einen Button zuweisen.
Delphi-Quellcode:
Nun folgender Code:
TNeutralEdit = class
public Button: TButton; end;
Delphi-Quellcode:
Dafür muss das Edit aber (automatisch!) mitbekommen, wenn die Caption des Buttons geändert wird.
var Edit: TNeutralEdit;
Button: TButton; begin Edit.Button := Button; Button1.Caption := 'Test123'; ShowMessage(Edit.Text); // ==> 'Test123' end; Und genau DAS ist das Problem. Dazu allerdings noch eine Anmerkungen: Das war ein sehr spezielles Beispiel. Ich kann zu diesem Zweck weder Windows Messages abfangen noch einen Class Helper für TButton o.ä. benutzen. Denn der TButton aus dem Beispiel ist durch eine beliebige andere Klasse austauschbar. Die Property, die angezeigt werden soll ebenso. |
Re: Methodenaufruf umbiegen?
Du kannst ja mal versuchen rauszubekommen, wie z.B. TUpDown das Ändern des {Edit}.Text mitbekommt.
|
Re: Methodenaufruf umbiegen?
Zitat:
|
Re: Methodenaufruf umbiegen?
Hast du eigentlich schon meine Lösungen gesehen? Da nicht virtual Methoden keine Adress in irgendeiner LUT haben musst du direkt den Code überschreiben. Anders wist du es nicht hinbekommen.
|
Re: Methodenaufruf umbiegen?
Ich kann mich nicht entsinnen, in deinem ersten Beitrag etwas von Properties und deren Binding gelesen zu haben. Da muss ich wohl mal in die Runde fragen, womit ihr so eure Glaskugeln putzt ;) Das einzige wonach du gefragt hast, ist wie man eine Methode an eine vormals anders implemetierte knoten kann, was mit Properties kam dann danach, was ich als Lösungsversuch verstanden habe, bzw. war nicht eindeutig, dass es im Grunde um Properties geht - von Methoden war die Rede, was ja u.U. etwas allgemeiner, im Falle direkter Variablenbindung aber auch ganz anders ausfällt: Stell dir mal vor, es gäbe Properties die keinen Setter haben, sondern direkt in eine private Variable schreiben (oder aus ihr lesen) :shock:.
Eine generelle Lösung scheint es in Delphi nicht zu geben. Sämtliche Ansätze in diese Richtung die mir bisher so begegnet sind, sind Komponentensammlungen die diese Möglichkeit explizit vorsehen, oder es gab ein globales Update-Objekt, dass Komponenten mit Werten versorgt hat die aus einer DB oder sonstwoher stammen (ein OPC-Server ist da mein aktuellster Kandidat). Dir bliebe lediglich zu hoffen, dass es ein (published) OnChange der zu überwachenden Komponente gibt, dem du mit Hilfe der RTTI dynamisch einen Handler zuweisen könntest. Das muss dann zudem natürlich einheitlich ein TNotifyEvent sein. Problematisch ist dabei, dass man u.U. Handler vom anwendenden Programmierer damit abhängt, bzw. umgekehrt. Da ist dann die Frage wer zuerst kommt beim Laden des Formulars - bist du es, hast du schlechte Karten. Ist es die andere Kompo, lässt sich evtl. der zuvor zugewiesene Handler mit einschleifen. Das OnChange ist dann natürlich allgemein, und du müsstest dir dann noch "von Hand" den betreffenden Wert abholen. Nur muss man dann drauf vertrauen, dass die Kompo auch bei Änderung der gewünschten Property auch wirklich OnChange feuert. |
Re: Methodenaufruf umbiegen?
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:
Die beiden Edit und UpDown sind nur via UpDown.Associate verbunden, aber egal was man macht (UpDown-Klicken oder in Edit was reinschreiben), es ändern sich immer Beide. OK, UpDown weiß beim Klicken über .Associate vom Edit, aber das Edit weiß nichts vom UpDown, also wie bekommt beim Ändern von Edit.Text das UpDown was davon mit? (.Position ändert sich ja) |
Re: Methodenaufruf umbiegen?
Habs den Code von TUpDown kurz überflogen. Sieht danach aus als würde da mit Messages gearbeitet. Auf die muss ich allerdings verzichten. Und OnChange kommt auch nicht in Frage weil die meisten Klassen (!) kein OnChange haben. Die meisten Klassen haben überhaupt keine Events.
@Medium: Ok ich gebe zu mein Ursprungs-Post lässt viel Spielraum für Glaskugeln. Aber schon im 2. Post (der 3. des Threads) habe ich nochmal deutlicher erklärt was ich vorhabe. Und meiner Meinung nach konnte man da schon recht gut rauslesen was ich vorhatte und dass da mit OOP nichts zu machen ist.... |
Re: Methodenaufruf umbiegen?
Ich wollte nur noch mal abschließend (aus meiner Sicht, nicht wegen Groll sondern Unmachbarkeit in dieser Form), auf den recht vernichtenden Umstand: "Properties die keinen Setter haben, sondern direkt in eine private Variable schreiben (oder aus ihr lesen)" hinweisen. Dann gibt es nämlich noch nichtmal eine hartgecodete Methodenadresse die man mit Gefrickel bis der Arzt kommt evtl. noch umbiegen könnte, sondern da wird dann einfach direkt irgendwo im Heap gefummelt wie bei "i := 42" (mal angenommen i sei aufm Heap :)).
|
Re: Methodenaufruf umbiegen?
Es geht teilweise was du vorhast. Dazu muß die Property
1.) eine Setter Methode haben 2.) das Schreiben in diese Property muß über die RTTI dynamisch erfolgen, zb. beim Laden von Komponenten aus DFMs ist dies immer der Fall. Schon kompilierter Code wird durch den Kompiler einen statischen Aufruf der Setter Methode benutzen. Beachte aber das du die Klassen-RTTI im Codesegment manipulieren musst und damit mit einem Hook alle Objekte und deren Nachfahren dieser Klasse beeinflussts. Eine zweite Alternative gibt es noch. Werden Properties eines Objektes dynamisch gesetzt, zb. beim Laden aus DFMs dann könntest du eine "Spiegelklasse" benutzen. Dazu musst du aber die kompletten privaten Felder und Methoden der zu "hookenden" Klasse kennen. Man deklariert also eine komplett neue Klasse abgeleitet von einem gemeinsammen Vorfahr der Zielklasse, maximal also TObject, die Speichertechnisch identisch ist. Nun reimplemetierst du alle Felder, Properties und virtuellen/dynamischen Methoden deiner Zielklasse in der Spiegelklasse, natürlich mit dem gewünschten veränderten Verhalten. Zur Laufzeit hat jedes Objekt in seinem "Speicherrecord" als erstes einen Zeiger auf seine VMT, genauer gesagt einen Zeiger mitten in die RTTI seiner Klasse an der die VMT beginnt. Diesen biegst du bei deinen Zielobjekten auf deine Spiegelklasse temporär um. Also solange wie du das geänderte Verhalten wünscht. Alle nicht statischen Zugriffe auf dieses Objekt die über die RTTI gehen werden ab sofort über deine Spiegelklasse "geroutet". Dynamische Zugriffe können auf Properties, Events, virtuelle, dynamische Methoden (und damit auch Message Methoden), Interfaces, TypInfos, Konstruktoren usw. erfolgen. Mit diesem Trick veränderst du zu einem allozierten Objekt zur Laufzeit deren Klassenbeziehung. Damit das funktioniert muß die VMT und DMT beider Klassen pseudoidentisch sein, also gleiche Anzahl an Methoden und auch gleiche Aufrufparameter jeder Methode in gleicher Slot Position. Nachteil dieser Methode: alle is und as Operatoren funktionieren nicht mehr korrekt. Genauer gesagt: as/is benutzt exakt diesen Zeiger auf die VMT eines Objektes für einen Vergleich beim Typcast bzw. Klassenabfrage. Diese Operatoren vergleichen im Grunde also nur die Codesegement Speicheradresse der RTTI/Klassenstruktur der Objekte. Gruß Hagen |
Alle Zeitangaben in WEZ +1. Es ist jetzt 18:05 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