![]() |
Delphi-Version: 2009
Mehrere DLL-Forms (Plugins) gleichzeitig öffnen
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:
Typdeklaration: TPlugin (Enthält Infos über das Plugin, sowie das Plugin selbst, wenn es geladen wurde)
TPlugins = class(TObjectList)
private function GetItem(Index: Integer): TPlugin; public property Plugin[Index: Integer]: TPlugin read GetItem; default; end;
Delphi-Quellcode:
Einlesen der installieren Plugins, danach wieder entladen
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;
Delphi-Quellcode:
Benutzen eines Plugins
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;
Delphi-Quellcode:
Das Plugin wieder beenden
//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; ... ...
Delphi-Quellcode:
Und nun noch die Methoden aus der DLL zum Erstellen von Freigeben der Forms:
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;
Delphi-Quellcode:
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.
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; Vielen Dank im Voraus! |
AW: Mehrere DLL-Forms (Plugins) gleichzeitig öffnen
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 |
AW: Mehrere DLL-Forms (Plugins) gleichzeitig öffnen
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.
![]() ... |
Alle Zeitangaben in WEZ +1. Es ist jetzt 11:16 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 by Thomas Breitkreuz