![]() |
Wie private Setter-Methode überschreiben?
Hallo,
ich habe mir mit Txyz = class(TWinControl) eine neue Komponente erstellt. Diese hat auch einen Cursor, da das TWinControl auch einen Cursor hat. Nun muss ich in meiner Komponente darauf reagieren können, wenn mit xyz.Cursor := crHourGlass ein neuer Cursor zugeweisen wird. Wie kann ich dies bewerkstelligen? SetCursor (in der Oberklasse TComponent zu finden) ist ja privat und kann nicht überschrieben werden. Wer kann helfen? Danke! |
Re: Wie private Setter-Methode überschreiben?
Hast du es schon mit reintroduce versucht ?
|
Re: Wie private Setter-Methode überschreiben?
Zitat:
|
Re: Wie private Setter-Methode überschreiben?
Die Setter kannst du nicht überschreiben. Entweder bekommst du über die Quellen raus, ob er vllt. im Original Setter eine Nachricht absetzt auf die du reagieren kannst oder du definierst die Property in deiner abgeleiteten Klasse einfach neu: gleicher Name, eigener Getter/Setter
|
Re: Wie private Setter-Methode überschreiben?
Du kannst aber die Methode im Privat-Bereich neu schreiben, nur inherited funktioniert leider nicht.
die entsprechenden Propertys musst du dementsprechend selber wieder einführen Leider sind einige Interessante Methoden bei Komponenten im private-Bereich versteckt. Noch schlimmer ist es allerdings, dass in der VCL an vielen Stellen Klassen private-Methoden von anderen Klassen aus der Unit benutzen (z.B. TTable ist ganz besonders schlimm). Will man nun bestimmte Sachen dort überschreiben, hat man verloren :cry: |
Re: Wie private Setter-Methode überschreiben?
Zitat:
|
Re: Wie private Setter-Methode überschreiben?
Zitat:
btw, das setzen eines Cursors in einem WinControl wird ganz sicherlich mit einer Nachricht verbunden sein. |
Re: Wie private Setter-Methode überschreiben?
Man kann bei einer published Property den Setter überschreiben, aber das geht nur mit Tricks eg. dem Patchen der RTTI der neuen Klasse. Ist also machbar aber nicht ganz "legal".
Ansonsten bleibt dir nur die Message wm_SetCursor und wm_NCHitTest abzufangen und dort zb. mit API.SetCursor(Screen.Cursors[Control.Cursor].Handle) selber deinen Cursor zu setzen. Gruß Hagen |
Re: Wie private Setter-Methode überschreiben?
Zitat:
|
Re: Wie private Setter-Methode überschreiben?
Das funktioniert aber dann nur wenn im Source explizit der Cursor deiner Klasse angesprochen wird. So bald zb. die VCL den Cursor von deinen Vorfahren anspricht bekommst du nichts mehr davon mit. Probiere mal TWinControl(MeineKlassenInstance).Cursor := crXYZ aus.
Gruß Hagen |
Re: Wie private Setter-Methode überschreiben?
Zitat:
|
Re: Wie private Setter-Methode überschreiben?
Zitat:
|
Re: Wie private Setter-Methode überschreiben?
Zitat:
Das Patchen einer Setter-Methode erfolgt dabei nicht über die VMT der Klasse, sondern man patcht den RTTI Eintrag zu der Property. Deshalb muß die Property in irgendeiner Vorfahrklasse schon mal als published deklariert worden sein, ansonsten gibt es nämlich keine RTTI zu dieser Property. Ist das der Fall so findet man in der RTTI zu dieser Property folgende Struktur:
Delphi-Quellcode:
in Unit TypInfo.pas.
PPropInfo = ^TPropInfo;
TPropInfo = packed record PropType: PPTypeInfo; GetProc: Pointer; SetProc: Pointer; StoredProc: Pointer; Index: Integer; Default: Longint; NameIndex: SmallInt; Name: ShortString; end; Mit
Delphi-Quellcode:
kommt man an diesen Record der ja als RTTI im Codesegment gespreichert wurde ran.
GetPropInfo(TypeInfo: PTypeInfo; const PropName: string): PPropInfo;
Delphi-Quellcode:
In der PPropInfo.SetProc steht dann der Zeiger der Setter Methode. Aber VORSICHT! dieser Zeiger kann unterschiedliche Bedeutungen haben da ja unsere Setter Methode entweder
GetPropInfo(TMyWinControl.ClassInfo, 'Cursor)');
1.) statisch ist -> SetProc ist dann ein Zeiger direkt auf die Methode 2.) virtual ist -> SetProc ist dann ein kombinierter Wert aus $01 XXYYZZ und XXYYZZ ist der VMT Slot Index in die VMT wo dann erst unsere virtuelle Methode drinnen steht 3.) dynamic ist -> SetProc ist dannn ein kombinierter Wert aus $02 XXYYZZ und XXYYZZ ist der DMT Identify in die DMT wo dann die Addresse der dynamischen Methode drinnen steht. 4.) wenn in SetProc aber das oberste Byte $FE ist so stellt der Rest ein Offest beginnend bei der Addresse der Objekt Instance zu einem privaten Feld dar. Das heist es gibt defakto garkeine SetProc sondern nur ein direkter Zugriff in den Speicher des Objectes. SetProc stellt dann also nur den Offset zu diesem Feld innerhalb des Objectes dar. Gut, in deinem Falle kannst du davon ausgehen das SetProc ein Zeiger auf eine statische Methode darstellt, einfach indem du bei TWinControl nachschaust wie die Setter Methode deklariert wurde. Das Patchen ist nun einfach. Du ermittelst wie oben gezeigt die PPropInfo für Property "Cursor" zu deiner Klasse. Gepatcht wird nun @PPropInfo^.SetProc in dem du dort einen Zeiger auf deine Setter Methode rein patcht. Dies gilt dann für deine Klasse, also für ALLE Instancen = Objecte die von deinem Klassentyp sind !! Man patcht also nur einmalig, zb. in der Initialisation Sektion deiner Unit, und danach benutzen alle Instancen deiner Klasse die neue Setter Methode. Schön ist das aber nicht, das möchte ich hier nochmals betonen. Gruß Hagen PS: nachzulesen hier für Delphi 5
Delphi-Quellcode:
procedure SetOrdProp(Instance: TObject; PropInfo: PPropInfo;
Value: Longint); assembler; asm { -> EAX Pointer to instance } { EDX Pointer to property info } { ECX Value } PUSH EBX PUSH ESI PUSH EDI MOV EDI,EDX MOV ESI,[EDI].TPropInfo.PropType MOV ESI,[ESI] MOV BL,otSLong CMP [ESI].TTypeInfo.Kind,tkClass JE @@isClass XOR EBX,EBX MOV BL,[ESI].TTypeInfo.Name.Byte[0] MOV BL,[ESI].TTypeInfo.Name[EBX+1].TTypeData.OrdType @@isClass: MOV EDX,[EDI].TPropInfo.Index { pass Index in DX } CMP EDX,$80000000 JNE @@hasIndex MOV EDX,ECX { pass value in EDX } @@hasIndex: MOV ESI,[EDI].TPropInfo.SetProc CMP [EDI].TPropInfo.SetProc.Byte[3],$FE JA @@isField JB @@isStaticMethod { SetProc turned out to be a virtual method. call it } MOVSX ESI,SI { sign extend slot offset } ADD ESI,[EAX] { vmt + slot offset } CALL dword ptr [ESI] JMP @@exit @@isStaticMethod: CALL ESI JMP @@exit @@isField: AND ESI,$00FFFFFF ADD EAX,ESI MOV [EAX],CL CMP BL,otSWord JB @@exit MOV [EAX],CX CMP BL,otSLong JB @@exit MOV [EAX],ECX @@exit: POP EDI POP ESI POP EBX end; |
Re: Wie private Setter-Methode überschreiben?
Zitat:
Ich habe das mal gemacht um virtual *class* methods umzubiegen... |
Re: Wie private Setter-Methode überschreiben?
macht nichts, denn das Patchen der RTTI ist ebenfalls nur die halbe Miete. Bei einem Zugriff wie Control.Cursor := crHourGlass benutzt der Compiler ja ebenfalls nicht die RTTI um die Setter Methode zu ermitteln. Der Compiler erzeugt einen direkten Code wie MyControl.SetCursor() weil er ja die privaten statischen/virtuellen Methoden ja selber kennt. Nur wenn man zb. ein Control/Form im OI ändert oder aber aus einer DFM lädt wird die RTL über die RTTI gehen. Deshalb eben nur halbe Miete.
Allerdings kann er mit der RTTI die Addresse im Codesegment ermitteln an der die private Setter Methode steht. Er patcht nun nicht mehr die RTTI der Property sondern überschreibt den Code dr Setter Methode. Er patcht also direkt diese Methode und baut ein JMP zu seiner neuen Setter Methode rein. ALLE Controls die von der Basisklasse abgeleitet sind würden ab diesem Moment seine neue Setter Methode benutzen. Kein schöne Sache, aber es geht alles ;) Gruß Hagen PS: ich werde hier keinen fertigen Source liefern ! selber machen und lernen ist also angesagt. |
Re: Wie private Setter-Methode überschreiben?
Wenn du dir die Function SetCursor etwas genauer anschaust, siehst du, daß dort eine Message verschickt wird. Das bedeutet, daß du nur noch CMCursorChanged überschreiben mußt.
|
Re: Wie private Setter-Methode überschreiben?
Zitat:
Und danach eine Entscheidung zu treffen ob es zu ouchy banana ist und eine andere Lösung angebrachter wäre. Man stelle sich ein Package vor, dass das ungefragt machen würde. :shock: |
Alle Zeitangaben in WEZ +1. Es ist jetzt 13:41 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