![]() |
Problem mit GetClass in stat. App bei dyn. geladenen Package
Hallo zusammen,
ich habe folgendes Problem: Ich möchte gerne aus einer Delphi-Applikation (die keine Runtime-Package (VCL, RTL, ...) verwendet) ein einzelnes Package dynamisch laden und auf eine enthaltene Klasse zugreifen, die dann im Kontext der Anwendung laufen soll. Wenn ich die Anwendung auf das Benutzen von dynamischen Package konfiguriere, dann klappt der GetClass Aufruf. Dann ist meine Applikation aber klein und verwendet die Standard Package. Ich möchte aber eine Stand-alone-Exe haben, die bei Bedarf nur auf einem Package etwas nachladen soll. Beisp Package: (der Einfachheit-halber nur ein Formular)
Delphi-Quellcode:
package myPackage;
... contains u_frmPackage in 'u_frmPackage.pas' {frmPackage}; end.
Delphi-Quellcode:
Die Anwendung:
unit u_frmPackage;
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TfrmPackage = class(TForm) Memo1: TMemo; Button1: TButton; procedure Button1Click(Sender: TObject); private { Private-Deklarationen } public { Public-Deklarationen } end; implementation {$R *.dfm} procedure TfrmPackage.Button1Click(Sender: TObject); var i: Integer; begin for i := 0 to Application.ComponentCount - 1 do begin Memo1.Lines.Add(Application.Components[i].Name + ': ' + Application.Components[i].ClassName); end; end; initialization RegisterClasses([TfrmPackage]); ShowMessage('Class registered'); finalization UnRegisterClasses([TfrmPackage]); ShowMessage('Class unregistered'); end.
Delphi-Quellcode:
Wenn "Menu -> Projekt -> Optionen -> Packages -> Laufzeit Packages -> [X] LaufzeitPackages aktivieren" aktiviert ist, dann funktioniert es.
u_frmApp
... type TmyFormClass = class of TForm; procedure TfrmApp.Button1Click(Sender: TObject); var i: HMODULE; c: TmyFormClass; f: TForm; begin i := LoadPackage('myPackage.bpl'); c := TmyFormClass(GetClass('TfrmPackage')); if c = nil then begin Caption := 'Form wurde nicht gefunden'; end else begin Caption := c.ClassName; f := c.Create(self); f.ShowModal; f.Free; end; UnLoadPackage(i); end; ... Was muß ich tun um diese Funktionalität auch zutzen zu können, wenn "Menu -> Projekt -> Optionen -> Packages -> Laufzeit Packages -> [ ] LaufzeitPackages aktivieren" nicht aktiviert ist? Es werden zwar die Klassen registriert (Dialog mit 'Class registered' bzw 'Class unregistered' ist zu sehen), aber GetClass() gibt nur nil zurück. Ich hoffe jemand heit einen guten Vorschlag ;-) Unsere Anwendungen komplett auf Packages umzustellen geht aus verschiedenen technischen Gründen nicht. Danke und viele Grüße MaBuSE :dp: |
Re: Problem mit GetClass in stat. App bei dyn. geladenen Pac
Hallo,
ich kämpfe gerade mit dem gleichen Problem. Nachdem ich wie von MaBuSE beschrieben die Laufzeitpackages aktiviert haben klappt bei mir GetClass für die angegebene Klasse. Dabei taucht gedoch ein anderes Problem auf. Meine Fensterklasse ist von einer eigenen Basisklasse abgeleitet. Deren Vorfahre ist TForm. Diese Basisklasse liegt wieder in einem eigenen Package. Ich kann das Package mit meiner neuen Fensterklasse laden und auch das Fenster erstellen. Klappt soweit alles. Wenn ich jetzt aber eine Prüfung mittels is auf den Vorfahren mache liefert dies False zurück. Meine Vorfahrenklasse ist registriert (hab ich geprüft). Hier noch mal die Hierarchie: TMyBaseForm (liegt in BasePackage und ist mittels RegisterClass registriert) TMySpecialForm = class(TMyBaseForm) (liegt in SpecialPackage und ist registriert) Anwendung lädt Specialpackage mittels LoadPackage und kreiert AForm vom Typ TMySpecialForm. Typprüfung schlägt fehl:
Delphi-Quellcode:
Warum das jetzt? Ich habe andere Formulare in meiner Anwendung die auch den Vorfahren TMyBaseForm besitzen. Diese sind im Projekt der Anwendung eingebunden. Eine Prüfung auf TMyBaseForm funzt da ohne Probleme. Nur halt bei den geladenen nicht.
if AForm is TMyBaseForm then
.... Gruß oki |
Re: Problem mit GetClass in stat. App bei dyn. geladenen Pac
Entweder alles Runtimepackages oder gar nichts! Mixbetrieb ist nicht möglich (bzw. nur mit sehr viel Glück und vielen harten Casts).
Hat deine Anwendung keine Runtimepackages aber die DLL schon, so ist TObject der Exe <> TObject der BPL da beide vollkommen unabhängige RTTI haben! |
Re: Problem mit GetClass in stat. App bei dyn. geladenen Pac
Ich bin ehrlich gesagt irritiert, das LoadPackage keine Exception wirft. Eigentlich sollte LoadPackage auf doppelte Units prüfen und gegebenenfalls eine Exception auslösen. Das aber selbst mit Tricks GetClass nicht funktionieren kann, ist auch klar: Letztlich schreibt RegisterClass die Klasse nur in eine globale Variable der Unit Classes. Und diese Variable ist natürlich nur über Modulgrenzen hinweg benutzbar, wenn man Laufzeitpackages verwendet.
|
Re: Problem mit GetClass in stat. App bei dyn. geladenen Pac
ok,
schon mal Dank. Leider klemmt es jetzt etwas mit dem Verständnis des gesagten; oder besser mit der Umsetzung. Das mit der RTTI und der Registrierung leuchtet mir ein. Die Frage ist jetzt nur, wo genau sollte ich nur mit Runtimepackages arbeiten. Reicht es in meiner Exe oder muss ich da bei meinen Packages etwas beachen? Sorry für die platten Fragen, aber an der Stelle bin ich völlig blass. Hab halt immer meine Packages erstellt (Compiler Design/Runtime) und gut wars. Hatte nie den Bedarf Packages zur Laufzeit zu laden. Ich fasse auch noch mal zusammen, was ich bis jetzt an welcher Stelle gemacht habe: - Package "BasePackage" mit Compilereinstellung "Entwurf und Laufzeit" erstellt. (Ausgabeverzeichnis ...CodeGear\5.0\...) - Package "SpecialPackage" mit Compilereinstellung "Entwurf und Laufzeit" erstellt. (Ausgabeverzeichnis ...CodeGear\5.0\...) Meine Anwendung die SpecialPackage laden soll habe ich mit "Laufzeit-Package verwenden" aktiviert compiliert. Hier konnte ich jedoch die beiden Packages nicht mit eintragen. Kommt der Fehler "F2084 Interner Fehler: U1036" wenn meine MainForm.pas compiliert wird. Das MainForm ist ebenfalls ein Nachfahre meines BaseForms aus "BasePackage". Somit werden da die Units aus dem Package eingebunden. Ich denke das ist vielleicht eine Folge des besagen Mischbetriebes. Da diese Anwendung nur für den internen Gebrauch gedacht ist habe ich kein Problem mit den Laufzeitpackages. Ein sauberer Weg ist mir recht. Nur wie? Schon mal Dank und Gruß oki |
Re: Problem mit GetClass in stat. App bei dyn. geladenen Pac
Alle Units, die in mehreren Modulen verwendet werden, müssen in allen verwendenden Modulen mit einem Laufzeitpackage eingebunden werden. Insbesondere müssen also sowohl die Packages als auch das Hauptprogramm mit den Packages RTL und VCL kompiliert werden.
|
Re: Problem mit GetClass in stat. App bei dyn. geladenen Pac
Hi Apollonius,
das ging zu schnell. ich glaub ich brauch das grad etwas praktischer. Bsp.: ich habe eine Unit MyBaseWindow.pas die ich in folgenden Modulen verwende: - BasePackage.bpl - SpecialPackage.bpl - MyApp.exe in den Projektoptionen habe ich jetzt die Lasche "Beschreibung". Dort kann ich für die angegebenen Packages einmal den Schalter "Verwenden für" mit den Optionen "Entwurf", "Laufzeit" und "Entwurf und Laufzeit" einstellen. Bei allen Modulen kann ich in der Lasche "Packages" die Checkbox "Laufzeitpackages verwenden" wählen. Darüber befindet sich das ListView "Entwurfs-Packages" in der alle in meiner IDE geladenen Packages gecheckt sind. Wo muss ich jetzt was rein und was raus nehmen. Ich stell mich heute vielleicht etwas blöd an, aber mich drückt der Terminschuh und ich hoffe ich schaffe es heute mit euch ohne eigenes Grundlagenstudium. Dank und Gruß oki |
Re: Problem mit GetClass in stat. App bei dyn. geladenen Pac
Jedes Package kann Units enthalten (contains), andere Units in das Package einkompilieren und mit requires andere Packages einbinden. Requires greift dabei auf die Units zu, die im anderen package unter contains aufgelistet sind.
Nun gilt die Regel: Jede Unit darf nur in einem einzigen Modul einkompiliert sein. Wenn sie in mehreren gebraucht wird, muss ein Package die Unit unter contains aufführen, welches die anderen mit requires einbinden. Konkret heißt das bei dir: Deine Unit MyBaseWindow musst du entweder in BasePackage oder in SpecialPackage hineinkompilieren; vermutlich wirst du BasePackage wählen. Das heißt, dass du neben der normalen Auflistung in der Uses-Klausel die Unit in die Contains-Klausel schreibst. In allen anderen Packages, die die Unit verwenden, schreibst du dann BasePackage in die Requires-Klausel. Auf die Requires-Klausel hast du auch direkt im Projekt-Baum Zugriff. Das selbe musst du dann auch für das Hauptprogramm tun. Da es dort jedoch keine Requires-Klausel gibt, musst du die Projekt-Optionen bemühen: Bei Packages die Checkbox "Laufzeitpackages verwenden" setzen und dein Package in das Edit-Feld hinzufügen. Die selben Regeln gelten auch für alle anderen gemeinsam genutzten Units - auch die Delphi-eigenen. Daher musst du in jedem Fall das Package RTL einbinden, gegebenenfalls auch VCL. |
Re: Problem mit GetClass in stat. App bei dyn. geladenen Pac
hab ich verstanden.
Ich teste es. Gruß oki |
Re: Problem mit GetClass in stat. App bei dyn. geladenen Pac
Moin,
ich habe jetzt gründlich aufgeräumt. Alle Units sind nur noch in einem Package eingebunden. In meiner Exe habe ich dann mein BasePackage in der Rubrik "Laufzeitpackage verwenden" zusammen mit "rtl" und "vcl" eingetragen und erfolgreich kompiliert. Das lief dann auch ohne die zuvor erwähnten Fehler ab. Dafür erst mal Dank! :thumb: Jetzt hat sich folgendes herausgestellt. Ich lade mein SpecialPackage zur Laufzeit mittels LoadPackage. Die in diesem Package registrierte Fensterklasse TMySpecialForm wird durch GetClass gefunden. Die Prüfung mit "is" ist erfolgreich. Leider werden aber alle in BasePackage definierten und registrierten Fensterklassen jetzt nicht mehr erkannt. Alle Registrierungen erfolgen in den entsprechenden Units mittels RegisterClass im initialization-Teil der Unit. Ich habe dann in einer Unit des SpezialPackage im initialization-Teil alle Fenster des BasePackage noch einmal mittels RegisterClasses aufgenommen. Siehe da, jetzt werden sie erkannt. Ich hatte eigentlich gehofft, dass ich durch die Einbindung des Packages BasePackage als Runtimemodule das in dem nachzuladenden Package nicht mehr tun muss. Ich habe den Hinweis zur Klassenregistrierung in der Unit Classes zwar wahrgenommen, wie das aber konkret abläuft und sich auswirkt hab ich noch nicht verstanden. Auch das Thema "Modulgrenzen" ist mir so nicht richtig klar geworden. Im Grunde ist mein "Hauptmodul" ja meine Exe. Diese hat das Package BasePackage, angegeben als Runtimepackage, eingebunden. Damit sollte es doch alle registrierten Klassen aus BasePackage kennen. Würde meine Exe jetzt die Klasse aus dem nachgeladenen SpezialPackage nicht kennen, so könnte ich das verstehen. Aber es ist genau umgekehrt. Der Code in meiner Exe erkennt die Klassen aus dem nachgeladenen Spezialpackage, aber nicht die Klassen aus BasePackage. Für mich ist das grad mal verkehrte Welt. Ich habe auch gerade mal eine Idee getestet. Bevor ich das SpezialPackage lade kennt meine Anwendung die registrierten Klassen. Nach dem Laden nicht mehr. Wird da vielleicht im Hintergrund das BasePackage der Exe entladen, damit das in "erforderlich" eingetragenen BasePackage des geladenen SpezialPackage verwendet wird? Da fällt mir ein, dass in den Finalization-Teil der Fensterunits auch ein UnregisterClass für die Fensterklassen aufgenommen habe. Mal schauen, wenn einer eine Idee hat, her damit. Und wieder Dank im Voraus, Gruß oki |
Alle Zeitangaben in WEZ +1. Es ist jetzt 14:32 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