AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Object-Pascal / Delphi-Language Delphi Mehrere DLL-Forms (Plugins) gleichzeitig öffnen
Thema durchsuchen
Ansicht
Themen-Optionen

Mehrere DLL-Forms (Plugins) gleichzeitig öffnen

Ein Thema von TheMiller · begonnen am 17. Jul 2012 · letzter Beitrag vom 5. Nov 2012
Antwort Antwort
Benutzerbild von TheMiller
TheMiller

Registriert seit: 19. Mai 2003
Ort: Gründau
2.480 Beiträge
 
Delphi XE7 Architect
 
#1

Mehrere DLL-Forms (Plugins) gleichzeitig öffnen

  Alt 17. Jul 2012, 10:46
Delphi-Version: 2009
Hallo,

ich verzweifel mal wieder etwas an DLL-Forms, obwohl ich sie eigentlich recht gut im Griff habe - denke ich jedenfalls. Bevor ich den Quelltext poste, erst einmal eine kleine Fehlerbeschreibung:

Ich lade ein Plugin, entlade es wieder, lade es wieder, entlade es wieder usw. Irgendwann kommt die Meldung "[Programmname] funktioniert nicht mehr". Dabei stoppt der Debugger nicht. Das alles passiert aber nur, wenn mehrere Plugins im Spiel sind. Ist nur eins eingebunden, dann kann ich das so lange machen, bis ich umkippe.

Damit sich die VCL nicht stören, habe ich Methoden in die DLL eingefügt, die die Form erstellen, anzeigen und wieder freigeben. Wenn ich Strings übergebe, dann nur über den Umweg des Buffers (lasse mir die Länge des Strings ausgeben, reserviere Speicher und kopiere mir den String mit der Länge "Buffer" aus dem Speicher). Daher habe ich auch keine gemeinsame Speicherverwaltung, außer zu Debugzwecken FastMM4

Probleme treten nur beim Entladen mit FreeLibrary auf und auch nur dann, wenn ich die Methoden zum Erstellen|Anzeigen|Freigeben von Forms aufrufe. Rufe ich sie einfach nicht auf, scheint alles zu funktionieren.

Der Hauptfehler tritt dann bei Methode "UnloadPlugins" in der Nähe/oder bei "FreeLibrary" auf.

Ich hoffe, ihr könnt mir trotz der ungenauen Fehlerbeschreibung helfen und habt Lust, euch durch den Quelltext zu wühlen. Ich habe die wichtigsten Stellen gepostet und nochmal näher dokumentiert. Die Reihenfolge der Quelltexte ist vom Ablauf systematisch, also Einlesen, Öffnen, Schließen und dann die DLL.


Typdeklaration: TPlugins (ObjectList, die alle Plugins hält
Delphi-Quellcode:
  TPlugins = class(TObjectList)
  private
    function GetItem(Index: Integer): TPlugin;
  public
    property Plugin[Index: Integer]: TPlugin read GetItem; default;
  end;
Typdeklaration: TPlugin (Enthält Infos über das Plugin, sowie das Plugin selbst, wenn es geladen wurde)
Delphi-Quellcode:
  TPlugin = class(TObject)
  private
    fActive: Boolean;
    fFilename: String;
    fHandle: Cardinal;
    fFormHandle: Cardinal;
    fImageIdx: Integer;
    fPlugin: TxPlugin;
    fRechte: Boolean;
    fTitel: String;
    fUMID: String;
  public
    property Active: Boolean read fActive write fActive;
    property Filename: String read fFilename write fFilename;
    property FormHandle: Cardinal read fFormHandle write fFormHandle;
    property Handle: Cardinal read fHandle write fHandle;
    property ImageIdx: Integer read fImageIdx write fImageIdx;
    property Plugin: TxPlugin read fPlugin write fPlugin;
    property Rechte: Boolean read fRechte write fRechte;
    property Titel: String read fTitel write fTitel;
    property UMID: String read fUMID write fUMID;
  end;
Einlesen der installieren Plugins, danach wieder entladen

Delphi-Quellcode:
procedure TForm1.InstallPlugins;
var
  sr: TSearchRec;
  dir, ext: String;
  TempHandle: Cardinal;
  ProcAddr: Pointer;
  LoadPlugInProc: TLoadPlugin;
  TempPlugin: TxPlugin;
  i,j: Integer;
  titel, umid: String;
  Buffer: PChar;
  Plugin: TPlugin;
  TreeItem: TTreeNode;
begin
  if (Plugins = nil) then
    Plugins:=TPlugins.Create;

  Plugins.Clear;

  Dir:=ExtractFilePath(ParamStr(0))+'PlugIns\';
  Ext:='*.dll';
  if FindFirst(Dir+Ext, faAnyFile - faDirectory, sr) = 0 then
  begin
    try
      repeat

        //Plugin über export-Fkt. laden via LoadLibrary
        //TempPlugin.Handle enthält das von LoadLibrary angegebene Handle
        TempPlugin:=LoadPlugin(Dir+Sr.Name);

        //Gathering Plugin-Titel (Unicode-String "übergeben")
        i:=(TempPlugin.GetTitel(nil, 0))*2+2;
        try
          GetMem(Buffer, i);
          TempPlugin.GetTitel(Buffer, i);
          titel:=Buffer;
        finally
          FreeMem(Buffer);
        end;

        //Gathering UMID (Unicode-String "übergeben")
        i:=(TempPlugin.GetGUID(nil, 0))*2+2;
        try
          GetMem(Buffer, i);
          i:=TempPlugin.GetGUID(Buffer, i);
          umid:=Buffer;
        finally
          FreeMem(Buffer);
        end;

        Plugin:=TPlugin.Create; //Plugin-Objekt "komfortables Behältnis" erstellen
        Plugin.Plugin:=TempPlugin;
        Plugins.Add(Plugin); //Behältnis zur Plugin-Liste hinzufügen
        Plugin.Active:=True; //Es wird gerade ausgeführt.
        Plugin.Filename:=Dir+sr.Name;
        Plugin.ImageIdx:=Plugin.Plugin.PngImgIndex; //Integer
        Plugin.Titel:=titel; //String
        Plugin.UMID:=umid;
        Plugin.Rechte:=False; //Hat der User Rechte, das Plugin zu nutzen?
        UnloadPlugin(Plugin.Titel); //Plugin wieder entladen. Installation fertig.

      until
        FindNext(sr) <> 0
    finally
      FindClose(sr);

    end;
  end;
  TreeView1.Items.Item[0].Expand(True);
end;
Benutzen eines Plugins
Delphi-Quellcode:
  //Das zu öffnende Plugin in der Plugins-Liste suchen
  //Dann wieder (wie bei InstallPlugins) mit LoadPlugin (=> LoadLibrary) laden
  //Forms von DLL erstellen lassen
  //Forms von DLL anzeigen lassen
  if (TreeView1.Selected <> nil) then
  begin
    for j:=0 to Plugins.Count-1 do
    begin
      umid:=String(TreeView1.Selected.Data);
      if (Plugins.Plugin[j].UMID = umid) then
      begin
        Plugins.Plugin[j].Plugin:=LoadPlugin(Plugins.Plugin[j].Filename);
        Plugins.Plugin[j].Active:=True;

        Plugins.Plugin[j].Plugin.GetMfHandle(Self.Handle);
        Plugins.Plugin[j].Plugin.CreateForms; <-- Erstellt die Forms
        //Plugins.Plugin[j].FormHandle:=Plugins.Plugin[j].Plugin.SendFormHandle;
        Plugins.Plugin[j].Plugin.GetUID(Benutzer.UserID);
        Plugins.Plugin[j].Handle:=Plugins.Plugin[j].Plugin.Handle;

        //Plugins's "Start-UP" aufrufen
        Plugins.Plugin[j].Plugin.Execute;
      end;
... ...
Das Plugin wieder beenden
Delphi-Quellcode:
procedure TForm1.UnloadPlugIn(modulName: string);
var
  i: Integer;
begin
  for i:=0 to Plugins.Count-1 do
  begin
    if (Plugins.Plugin[i].Titel = Trim(Modulname)) then
    begin
      if (Plugins.Plugin[i].Active) then
      begin
        Plugins.Plugin[i].Plugin.FreeForms;
        Plugins.Plugin[i].Active:=False;
        FreeLibrary(Plugins.Plugin[i].Plugin.Handle);
      end;
    end;
  end;
end;
Und nun noch die Methoden aus der DLL zum Erstellen von Freigeben der Forms:

Delphi-Quellcode:
procedure TPlugin1.CreateForms;
begin
  Form1:=TForm1.Create(nil);
end;

procedure TPlugin1.Execute();
begin
  if (Form1 <> nil) then
    Form1.StartUp;
end;

procedure TPlugin1.FreeForms;
begin
  if (Form1 <> nil) then
  begin
    Form1.Free;
    //Form1.Release <-- erzeugt (mehr) Fehler bei FreeLibrary
  end;
end;

function TPlugin1.GetTitel(Buffer: PChar; lenBuffer: Integer): Integer;
var
  s: String;
begin
  //Danke an Luckie für sein gutes DLL-Strings-Tutorial
  s:='Adressen';
  if Assigned(Buffer) then
  begin
    StrLCopy(Buffer, PChar(s), lenBuffer);
  end;
  result:=length(s);
end;

procedure TPlugin1.SwitchShowStyle;
begin
  if (Form1 <> nil) then
  begin
    if (Form1.Visible = true) then
      Form1.Hide
    else
      Form1.Show;
  end;
end;
Ich habe echt viel darüber gelesen, arbeite schon länger mit DLLs und habe darauf geachtet, dass ich gegen keine "Regel" verstoße (VCLs, Speichermanager). Aber anscheinend habe ich irgendwo was übersehen oder wusste generell was noch nicht.
Vielen Dank im Voraus!
  Mit Zitat antworten Zitat
Benutzerbild von TheMiller
TheMiller

Registriert seit: 19. Mai 2003
Ort: Gründau
2.480 Beiträge
 
Delphi XE7 Architect
 
#2

AW: Mehrere DLL-Forms (Plugins) gleichzeitig öffnen

  Alt 18. Jul 2012, 09:46
Hallo,

ich habe gestern den ganzen Tag nochmal probiert und gedebuggt. Es ist also so, dass jeweils nur ein Plugin wunderbar funktioniert. Habe ich zwei am Laufen und schließe sie, dann wird das erste Plugin komplett korrekt entladen, keine Speicherlecks alles ok. Das zweite Plugin wird versucht zu entladen, bleibt bei "FreeLibrary" hängen, weil er das Formular in der zweiten DLL nicht freigeben kann. Daher ist kein einiges Objekt freigegeben und ein Speicherleck von über 38 MB (Textdatei von FastMM4) entsteht. Danach bricht das Programm ab.

Warum geht dies so schief, wenn's doch mit einer DLL (mit Formular) wunderbar klappt? Überschreibe ich was? Habe ich was nicht bedacht? Sollte ich auf EXEn als "Plugins" umsteigen? BPLs mag ich nicht nehmen.

Danke
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.062 Beiträge
 
Delphi 12 Athens
 
#3

AW: Mehrere DLL-Forms (Plugins) gleichzeitig öffnen

  Alt 5. Nov 2012, 10:43
Zum Thema VCL in DLL gibt es ja eigentlich genügend Thread, womit man sich das hätte selbst erklären können, warum ich jetzt einfach mal "NEIN, geht nicht" sage.

http://www.delphipraxis.net/171338-t...onize-dll.html
...
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:32 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz