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