Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Problem mit Interfaces und LoadPackage (https://www.delphipraxis.net/47863-problem-mit-interfaces-und-loadpackage.html)

alcaeus 17. Jun 2005 00:23


Problem mit Interfaces und LoadPackage
 
Hallo ihr,

ich hol jetzt mal ein bisschen aus. Ich arbeite zur Zeit an einem Modulsystem, das sich die Module zur Laufzeit aus Packages holt. Dies sieht z.Zt. so aus:
Delphi-Quellcode:
TModuleItem = class(TCollectionItem)
private
   fModuleClassName: String;
   fModuleHandle: LongInt;
   fModuleAbsFileName: String;
public
   MainFormClass: TPersistentClass;
   MainForm: IModuleMainForm;
end;

//
//...
//

//Load package
Module.fModuleHandle := LoadPackage(Module.fModuleAbsFileName);
InitializePackage(Module.fModuleHandle);

//Now grab this class. If it's not there, get out
Module.MainFormClass := GetClass(Module.fModuleClassName);
if not Assigned(Module.MainFormClass) then
begin
   Result := ERR_MCS_MAINFORM_NOT_FOUND;
   Module.ModuleActive := False;
   exit;
end; //if not Assigned(Module.MainFormClass) then

//Actually load the module and initialize it
Module.MainForm := TFormClass(Module.MainFormClass).Create(Application);
with Module.MainForm do
begin
   Align := alClient;
   BorderStyle := bsNone;
   Parent := Self.fMainFormParent;
   Visible := False;
end; //with Module.MainForm do

Dies funktioniert bis jetzt auch ganz gut. Nun will ich aber, dass die Hauptklasse des Moduls bestimmte funktionen bereitstellt, da gewisse Dinge beim Laden erledigt werden muessen. Nachdem der Versuch mit einer Klasse, welche eine virtual abstract-Methode bereitstellt, nicht geklappt hat, habe ich mich fuer Interfaces entschieden. Also hab ich mir mal mein Interface deklariert:
Delphi-Quellcode:
IModuleMainForm = interface
['{EBAE57B3-3C1A-4695-9927-C56D641F6486}']
   procedure SetProgramStyle(const aStyle: String);
end; //type IModuleMainForm = interface
und im Modul die Deklaration entsprechend abgeaendert:
Delphi-Quellcode:
TForm1 = class(TForm, IModuleMainForm)

Nun stehe ich aber vor dem Problem, dass ich nicht weiss wie ich das Dingen verwenden soll.
Wenn ich den Code versuche zu compilieren, laeuft das Ding ja, aber ich komm immer noch nicht auf die Interface-Methoden ran. Also habe ich testweise die Deklaration von MainForm von TForm auf mein Interface geaendert.

Nun bekomme ich aber logischerweise einen Fehler, dass das Interface und TForm inkompatibel waeren (wen wunderts? *g*), und zwar genau hier:
Delphi-Quellcode:
Module.MainForm := TFormClass(Module.MainFormClass).Create(Application);
Wie muss ich den Konstrukt nun umschreiben, so dass ich mein Form erstelle, aber gleichzeitig auch auf die Interface-Methoden zugreifen kann? Ich hab hier irgendwie voll die Denkblockade :pale:

Greetz
alcaeus

HeikoDD 17. Jun 2005 07:54

Re: Problem mit Interfaces und LoadPackage
 
Delphi-Quellcode:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;

Type IMainForm = Interface(IUnknown)
       ['{5C440981-29CB-4F1E-815D-DCA4EFF07437}']
       Procedure HalloWelt; stdcall;
     end;

type
  TForm1 = class(TForm, IMainForm)
    procedure FormCreate(Sender: TObject);
  private
    { Private-Deklarationen }
    procedure HalloWelt; stdcall;
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.HalloWelt;
Begin
  ShowMessage('Hallo Welt');
end;

procedure TForm1.FormCreate(Sender: TObject);
Var M: IMainForm;
begin
  M := Self;
  M.HalloWelt;
end;

end.
M := IMainForm(Form1);
sollte auch funktionieren, ABER TForm stammt nicht von TInterfacedObjekt, weshalb die internen
Mechnismen eines Interfaces natürlich nicht funktionieren dürften.
Sprich die automatische Freigeben des Form über das Interface usw, funktioniert nicht ..
Das Ding kann also nur als Transportkiste verwendet werden und auch sonst ist es nicht ganz konform.

alcaeus 17. Jun 2005 10:11

Re: Problem mit Interfaces und LoadPackage
 
Hallo Heiko,

der Compiler schluckt allerdings weder
Delphi-Quellcode:
Module.MainFormInterface := IModuleMainForm(Module.MainForm);
und auch nicht
Delphi-Quellcode:
Module.MainFormInterface := Module.MainForm;
Gibt es sonst noch irgendwelche Moeglichkeiten?

Weiters, was sind diese interne Mechanismen, die du angesprochen hast?

Greetz
alcaeus

choose 17. Jun 2005 10:19

Re: Problem mit Interfaces und LoadPackage
 
Hallo alcaeus,

interessantes Konzept. Interfaces sind hier der richtige Weg, mache Dir keine Gedanken über Referenzzählung oä: Dein System benötigt ohnehin einen Weg, Plug-ins sauber zu entladen. Wenn Du wirklich vorhast, ausschließlich Forms anzuzeigen, bekommst Du die Freigabe über das TComponent-Konzept des Owners gratis.

Ziehe in Betracht, nicht die Klasse sondern ein Objekt zurückzugeben, auf diese Weise können auch Exemplar von Klassen verwendet werden, deren Konstruktur nicht in der Oberklasse (virtuell) eingeführt ist...

Nicht nur das Hauptformular auch eine Verwaltungsinstanz könnte so in Frage kommen. In diesem Fall könnte Dein Plugin eine Fabrik zurückgeben und über diese erzeugst Du dann Deine Exemplare:
Delphi-Quellcode:
myFactory := Module.GetFactory;
myForm := myFactory.CreateForm;
myMenuItems.Add(myFactory.CreateMenuItems);
Hast Du erst einmal ein Exemplar deiner "dynamisch nachgeladenen" Klasse (egal ob über TFormClass(Module.MainFormClass).Create(Applicatio n) oder über eine Fabrik) kann Du ganz normal eine Interfacereferenz erfragen:
Delphi-Quellcode:
var
  myMainForm: IModuleMainForm;
begin
  //..
  Module.MainForm := TFormClass(Module.MainFormClass).Create(Application);
  if Supports(Module.Mainform, IModuleMainForm, myMainForm) then
    myMainForm.SetProgramStyle(AStyle);
Weiterhin viel Erfolg!

alcaeus 17. Jun 2005 10:26

Re: Problem mit Interfaces und LoadPackage
 
Hallo choose,

der Tipp mit Supports hat weitergeholfen. Jetzt funktioniert es erstmal, und diese AV beim Beenden finde ich auch noch :evil:

Vielen Dank :)

Greetz
alcaeus

alcaeus 17. Jun 2005 11:05

Re: Problem mit Interfaces und LoadPackage
 
Hehe...weiter gehts mit meinem Problem

Ich arbeite jetzt wie vorgeschlagen mit Supports(). Beim Laden des Moduls geschieht folgendes:
Delphi-Quellcode:
//Actually load the module and initialize it
Module.MainForm := TFormClass(Module.MainFormClass).Create(Application);
if Supports(Module.Mainform, IModuleMainForm, Module.MainFormInterface) then
   Module.MainFormInterface.SetProgramStyle(ProgramOptions.GetOption('ProgramStyle'));
with Module.MainForm do
begin
   Align := alClient;
   BorderStyle := bsNone;
   Parent := Self.fMainFormParent;
   Visible := False;
end; //with Module.MainForm do
Die Routine zum Freigeben sieht so aus:
Delphi-Quellcode:
function TModules.FreeModule(Module: TModuleItem): Integer;
begin
   Result := ERR_NO_ERROR;
   if not Module.fModuleActive then
   begin
      exit;
   end; //if not Module.fModuleActive then
   Module.MainFormInterface._Release;
   FinalizePackage(Module.fModuleHandle);
   UnloadPackage(Module.fModuleHandle);
end; //function TModules.FreeModule(Module: TModuleItem): Integer;
Wenn ich nun aber das Item selbst freigebe (was geschieht sobald ich die Collection freigebe), erhalte ich eine AV beim Aufruf, in den ich leider auch nicht reindebuggen kann. FreeModule() wird vor dem Free der Collection fuer alle Elemente aufgerufen. Wenn ich die gesamte Interfacesache ausklammere, funktionierts ohne Probleme. Die _Release-Zeile habe ich eingefuegt, um der AV entgegenzuwirken, aber das hat leider auch nichts gebracht :(

Kann mir (wiedermal) jemand weiterhelfen?

Greetz
alcaeus

[edit]Offene Frage[/edit]


Alle Zeitangaben in WEZ +1. Es ist jetzt 14:35 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