![]() |
Verwenden von GetClass und RegisterClass
Hallo zusammen,
ich habe folgendes Problem: Ich versuche ein DFM mit ReadComponentResFile('c:\temp\test.dfm', form2); auszulesen und dann anzuzeigen. Das Problem ist das nicht alle Klassen registriert sind. Selbst mit ein dfm welches nur Standardkomponenten enthält läßt sich so nicht anzeigen. Funktionieren tut es wenn ich die einzelnen Klassen mit z.Bsp RegisterClass( TButton) registrieren und dann das Fenster anzeige. Gibt es da nicht irgendwie eine Möglichkeit die Standarddelphikomponenten irgendwie zu registrieren bei Programmstart? Striker |
Re: Verwenden von GetClass und RegisterClass
Wenn du die VCL (VCL07.bpl) extern verlinkst, dann können die nicht benutzten componenten nicht weg optimiert werden, und das müsste somit gehen (vermute ich mal).
PS: Wilkommen in der Praxis :dp: |
Re: Verwenden von GetClass und RegisterClass
ja ok aber wie verlinke ich die VCL extern? Mit LoadPackage ?
Loadpackage('vcl60.bpl') wird zwar ausgeführt und ich bekomme auch ein Handle zurück aber GetClass oder FindClass bringen immer noch kein Ergebnis.. :?: Ps: danke für die willkommensgrüsse :-D |
Re: Verwenden von GetClass und RegisterClass
Ne ne, das was du versucht hast, ist dynamisches laden von BPLs zur laufzeit (kann für plugIns recht praktisch sein).
Du musst es statisch extern verlinken: Projektoptionen -> packages -> 'mit laufzeit-packages compilieren' -> rtl60, vcl60 ....in etwa. dh. du musst diese packages (aus %win\system32) dann aber auch mit ausliefern :-D |
Re: Verwenden von GetClass und RegisterClass
Das hab ich nun auch probiert aber es hat auch keinen Erfolg gebracht...
Laut doku ist es doch so dass ein Package alle Klassen registriert sobald es geladen wird. Meine Vermutung ist das die Registrierung nicht global geschieht... :?: :?: :?: |
Re: Verwenden von GetClass und RegisterClass
hmm... hab mal ein bisschen geforscht und fest gestellt, das komponenten, die direkt auf einer form benutzt werden nicht explizit registriert werden müssen. Es wird einfach die fieldClassTable des forms geholt, wo dann alle klassen gelistet sind die das form benutzt...und erst danach wird nach klassen gesucht, die in der normalen registrierung sind :(
So jetzt gibt es da aber einen illegalen trick, der aber relativ effektiv sein könnt. Werd heut abend mal was zu testen und dann bescheid sagen :wink: |
Re: Verwenden von GetClass und RegisterClass
NEIN... :wall: Alles futsch. Ich hoffe mal du hast den beitrag auswendig gelernt? :evil:
|
Re: Verwenden von GetClass und RegisterClass
:wiejetzt:
Neeeeeeeeeeeeeeeeeeeeeeeeeeeinnnnn. Natürlich nicht. :cry: Hast du es bitte noch irgenwo?? |
Re: Verwenden von GetClass und RegisterClass
Liste der Anhänge anzeigen (Anzahl: 1)
Da ich es hasse mich zu wiederholen, mach ich es kurz. In der unit steht jetzt alles nötige und der code von Hagen. Du musst nur die folgende funktion aufrufen:
Delphi-Quellcode:
Das registriert, wie gesagt, alle TPersistent abkömmlinge, deren RTTI einträge in dem modul gefunden werden.
RegisterAllPersistentClasses(HInstance);
viel glück :) |
Re: Verwenden von GetClass und RegisterClass
Hallo Maximov,
Ja super das ist genau das was ich brauche. :spin: Vielen Dank Maximov :dp: |
Re: Verwenden von GetClass und RegisterClass
Hat es denn funktioniert, sprich kannst jetzt beliebige formulare laden, ohne den code zu instanzieren?
|
Re: Verwenden von GetClass und RegisterClass
ja geht wunderbar jetzt danke nochmal...
|
Re: Verwenden von GetClass und RegisterClass
Aber Vorsicht! ;)
der von mir benutzte Trick geht offiziell überhaupt nicht nach Borlands Aussagen. Soll heisen offiziell kann man nicht über alle RTTI's eines Programmes iterieren. Bisher habe ich auch noch keine einzigste andere Implementation meines Tricks gefunden. D.h. wenn du diese Funktionen benutzt dann kannst du dich nur alleine auf mein Wissen stützen. Der obige Source funktioniert auch nur bis Delphi 6. Für Delphi 7 muß eine kleine Änderung durchgeführt werden. Allerdings, während der Entwicklung dieses Tricks habe ich alle Delphi Versionen bis Delphi 6 ausgiebigst getestet. Wenn man weiß wie der Source vorgeht besteht also die Möglichkeit speziellen Code zu programmieren der den Trick "austrickst", er produziert also dann Fehler. Dies könnte man für "Anti-Reverse-Engineering" Fallen benutzen, allerdings muß man dann schon ganz genau wissen was man programmieren muß. Rein zufällig kann ein solcher "Stolper-code" aber nicht entstehen, d.h. mit normalen Packages/Modulen funktioniert obige Funktion absolut sauber. Konzeptonell stellt sich aber die Frage ob die Anwendung der obigen Funktion ansich sauber ist. Soll heissen, das man eigentlich sein eigenes Konzept überdenken sollte bevor man obigen Trick benutzt. Gruß Hagen |
Re: Verwenden von GetClass und RegisterClass
Ja, das dies nicht grade sauber ist, ist mir bewusst. Deshalb auch mein hinweis:
Zitat:
|
Re: Verwenden von GetClass und RegisterClass
Naja, das eigentliche Problem entsteht woanders. Jede eigene TForm Klasse enthält in deren PUBLISHED Sektion Felder auf deren Komponenten und Controls. Der Compiler legt also in der RTTI im Codesegment zu dieser TForm Klasse auch die Informationen auf diese Felder ab. Diese Informationen enthalten den Namen der Komponente/Controls und auch den Klassentyp. Dieser Klassentyp ist aber nichts anderes als ein Zeiger in ds Codesegment wo dann wiederum die RTTI dieser Klassen zu finden ist.
So, lädt sich nun ein TForm selber aus deiner DFM so ist dieser TForm-Klasse sehr wohl bekannt welche Komponenten/Controls es selber enthält und welchen Klassentyp diese besitzen. Dazu muß die virtuelle DFM-Laderoutine -> eg. das Delphi VCL Streaming System, nur ausgehend von der aktuellen TForm Klasse in deren RTTI nachschlagen. Lädt man aber eine x'beliebige DFM, ohne das die dazugehörige TForm-Klasse erzeugt wurde so funktioniert dieses nicht mehr. Da nun eben kein Zugriff mehr auf die korrekte RTTI und deren published Komponentenfelder mehr vorhanden ist. Somit entsteht ein Fehler das eine bestimmte Klasse nicht registriert sei. Denn, eine Klasse ist nichts anderes wie ein Zeiger in das Codesegment. Solche Zeiger kann man aber in DFM's nicht direkt speichern. Um das denoch hinzubekommen benutzt das Delphi Streaming System den Feld-Namen und Klassentyp und speichert diese Informationen in der DFM. Sprich in der DFM steht "Object" -> "Button1" : "TButton" als Strings. Object bezeichnet ein Token so das das Streamingsystem weis das jetzt ein TObject == Klasse gemeint ist. "Button1" wiederum ist der Name des Feldes das in der TForm Klasse definiert wurde -> also der Name der Komponenten. Und "TButton" ist die eigentliche Klasse der Komponente. Delphis Streamingsystem lädt diese Strings aus der DFM und versucht nun diese Namenstrings in Klassen-Zeiger umzuwandeln. Natürlich muß es dazu eben den String "TButton" irgendwo nachschlagen. Da Delphi selber NICHT so einen Trick wie den obigen benutzt (geht ja offiziell auch nicht laut Borland), benutzt die RTL zwei Wege. Zuerstmal schaut es in der aktuellen Instance==Object in deren RTTI nach ob es ein Feld mit Namen "Button1" gibt. Wenn ja vergleicht es über die RTTI dessen Klassennamen "TButton" mit dem der aus der DFM geladen wurde. Wenn diese übereinstimmen hat das Streamingsystem schon die richtige und eindeutige Zuordnung gefunden. Wenn nein, geht es iterariv über die weiteren Felder der Instance und deren RTTI drüber und sucht. Wenn all dies fehlschlägt greift nun das dynamsiche Klassen-Registratuons-Konzept. Mit RegisterClass() wird eine Klasse in einer globalen TList gespeichert und registeriert. Delphi geht nun diese Liste iterativ durch und vergleich von den darin gespeicherten Klassen == RTTI's die Klassennamen mit "TButton". Sollte ein übereinstimmerneder Eintrag gefunden worden sein so hat man zum String "TButton" die Klasse == Zeiger in das Codesegment zur RTTI dieser TButton Klasse gefunden. Statt nun, wie du oben gezeigt hast, mit RegisterClass() alle im Code enthaltenen Klassen zu registrieren wäre es konzeptionell am saubersten die DFM nur durch die richtige TForm Klasse laden zu lassen. Sollte dies aber nicht möglich sein so stellt Delphis Komponmenten-Streaming-Sytsem eine Callback zur Verfügung. Diese Callback wird immer dann aufgerufen wenn Delphi einem Klassennamens-String NICHT die Klasse zuordnen kann. D.h. wenn alle Stricke reisen und selbst mit Registerclass() kein Erfolg beschieden ist. Nun, ich würde diese Callback überschreiben (sie ist zur Laufzeit immer NIL) und darin mit dem obigen Trick nach einer Klassen-RTTI im Codesegment aller geladenen Module nach dem Klassennamen suchen. Somit überfrachtet man nicht die interne Liste der RegisterClass() Funktion. Aber im Grunde wäre es für Borland ein leichtes gewesen von vornherein die RTTI's aller Typdeklarationen untereinander als verlinkte Liste im Codesegment zu speichern. Dann wären solche "um die Ecke Tricks" wie mit RegisterClass() etc. pp. garnicht mehr nötig. Der Compiler würde also alle Typdeklarationen, sprich deren RTTI's, untereinander verlinken und pro Modul gäbe es nur einen globalen Zeiger auf den ersten RTTI Record. Nun, mein obiger Trick geht genau so vor und nutzt einige Eigenheiten wie Code-Aligment dieser RTTI Records aus. Im Grunde also so als wenn diese RTTI Records als verlinkte Liste durch den Compiler gespeichert wurde (was aber nichtreal der Fall ist). Der Trick ist also deterministisch. Gruß Hagen |
Re: Verwenden von GetClass und RegisterClass
Ja,
das ist mir im wesentlichen alles bewusst, aber ich danke dir für diese fundierte zusammenfassung. An den Callback hatte ich auch gedacht, war aber zu faul zu suchen, wo ich ihn letztendlich setzen kann. Naja, striker hat ja was er will, oder glaubt zu wollen. Hab gestern, mit deinen Hack, mal ein bisschen in den delphi eigenen BPLs rum geschnüffelt und wahrlos komponenten und forms instanziert. Das förderte dann einige lustige delphi bruchstücke zu tage. Ich vermute, dass du ähnliches im sinn hattest, als zu von 'reverse engineering' redetest? Hätte mir aber auch eine offizielle lösung von borland gewünscht :stupid: |
Re: Verwenden von GetClass und RegisterClass
Im Grunde ja, nur bin ich noch einen Schritt weiter gegangen.
In meinem Falle konnte ich von einem laufenden Prozess ermitteln ob es sich um eine Delphi/BCB Anwendung handelte. Wenn ja bin ich mit meinem Code über alle geladenen Module dieses Prozesse durchgegangen und habe mir so die RTTI und alle Datentypen des analysierten Programmes angeschaut. Naja war aber eher eine Spielerei die nur abtesten sollte ob es geht. Gruß Hagen |
Re: Verwenden von GetClass und RegisterClass
Zitat:
kannst Du bitte mal den Source für Delphi 7 posten? Danke |
Re: Verwenden von GetClass und RegisterClass
Zitat:
Hagen schrieb in ![]() Zitat:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 04:54 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