Entwickler-Ecke
Open Source Units - Plugin-System [1.0]
glotzer - Mo 23.08.10 14:50
Titel: Plugin-System [1.0]
Plugin-System [1.0]
Das System basiert auf pointern und DLLs.
Es wurde haupsächlich auf Geschwindigkeit und möglichst geringe Datengröße optiemirt(das gesamte System ohne plugins hat eine Größe von 45kb). Es besteht aus der Plugin_System.DLL, die von dem Program zur verwaltung der Plugins verwendet wird. Jedes Plugin wird in einer DLL gespeichert, es ist möglich mehrere Plugins in einer DLL zu speichern. Auserdem wird der Unti Plugin_Types.pas benötigt, er kapselt die Basisklassen, typen, proceduren, funktionen und kümmert sich um das laden der DLL.
Das System ist nur unter windows funktionsfähig, da linux keine DLLs unterstützt.
Beispiel zur Verwendung im Programm
Initialisierung:
Delphi-Quelltext
1: 2: 3: 4: 5:
| var PSystem : TCustomPlugin_System; begin PSystem := CreatePluginSystem; end; |
Plugins laden:
Delphi-Quelltext
1: 2: 3: 4: 5:
| var i: Integer; begin i := Psystem.LoadPluginDll(PChar('Dll-Name.DLL')); end; |
funktion aufrufen:
Delphi-Quelltext
1: 2: 3: 4: 5: 6:
| var tmp: TCustomPlugin; begin tmp := PSystem.GetPluginByGUID(GUID); tmp.tmp.CallFunction('test', Parameter); end; |
Beispiel für die Programierung eines Plugins
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44:
| library Test_Plugin;
uses SysUtils, Forms, StdCtrls, Plugin_Types;
type TMyPlugin = class(TPlugin) public constructor Create; function DoSillyThings(Parameter:pointer): pointer; end;
var my: TMyPlugin; procedure InitPlugins(PluginSystem: TCustomPlugin_System); cdecl; begin my := TMyPlugin.Create; Pluginsystem.AddPlugin(my); randomize end;
constructor TMyPlugin.Create; begin self.Version := 0.0; self.Name := 't'; self.GUID := StringToGUID('{DE7DCBF7-175A-475C-91AD-D81C67E91746}'); self.AddFunction('test', DoSillyThings); end;
function TMyPlugin.DoSillyThings(Parameter:pointer): pointer; begin TForm(Parameter).Color := random(999999); end;
exports InitPlugins name'InitPlugins'; end. |
FinnO - Mo 23.08.10 15:57
Ich habe das jetzt nicht testen können, aber du könntest dir, um anregungen zu holfen, mal das Modular Application Framework von Helge Lange anschauen, welches sehr, sehr gut ist ;-).
Zumal seine Lösung natürlich nur bei nichtkommerziellem Einsatz kostenlos ist.
HelgeLange - Mo 23.08.10 18:03
2 kleine Anmerkungen zum Plugin-System :
1.) Deine DLL ist in einer bestimmten Delphi-Version gemacht. Das kann sehr schnell zu Problemen führen, wenn man eine andere Delphi Version nutzt. Du solltest den Code der DLL mit veröffentlichen oder die DLL in allen Delphi-Versionen zur Verfügung stellen. Beim ausführlichen Arbeiten mit DLL in Delphi wirst du Schnell feststellen, dass Du sowieso mit Runtime-Packages kompilieren musst, damit Du nur eine RTL/VCL laufen hast. Spätestens dann muss die DLL in der gleichen Delphi-Version sein.
2.) Du nutzt Namen, um Funktionen zu identifizieren. Für kleine Systeme mag das ganz ok sein, wenn es nicht zeitkritisch ist. Bei grösseren Systemen (mit ein paar tausend Funktionen) kann es schon langsam werden. Bei zeitkritischen Systemen (zum Bsp. Spielen) ist es tödlich. Besser über Nummern und Konstanten (zumindest intern).
delfiphan - Mo 23.08.10 18:28
Versteh mich nicht falsch, aber für so "simple" Funktionen ist es nicht wesentlich einfacher, sicherer und klarer, Interfaces zu schreiben und diese durch exportierte Funktionen zurückgeben zu lassen?
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| type IFoo = interface ['{4C1DD91B-AA83-43AE-9064-9181B156EFF2}'] procedure DoSomething; function ReturnString: WideString; end;
function CreateFoo: IFoo;
exports CreateFoo; |
Importieren geht praktisch genau so einfach.
Delphi-Quelltext
1:
| function CreateFoo: IFoo; external 'Foo.dll'; |
Das hier ist übrigens ein extrem Hack:
HelgeLange hat folgendes geschrieben : |
Delphi-Quelltext 1: 2: 3: 4:
| function TMyPlugin.DoSillyThings(Parameter:pointer): pointer; begin TForm(Parameter).Color := random(999999); end; | |
Das Argument
Parameter mag zwar für die Basisapplikation ein
TForm sein, aber nicht das gleiche
TForm wie in der DLL. Du wendest hier praktisch die Daten aus der Basisapplikation auf die Implementation des Plugins an (!). Der Ausdruck
TObject(Parameter) is TObject würde false zurückgeben.
So geht das natürlich nicht ;)
glotzer - Mo 23.08.10 19:13
HelgeLange hat folgendes geschrieben : |
2 kleine Anmerkungen zum Plugin-System :
1.) Deine DLL ist in einer bestimmten Delphi-Version gemacht. Das kann sehr schnell zu Problemen führen, wenn man eine andere Delphi Version nutzt. Du solltest den Code der DLL mit veröffentlichen oder die DLL in allen Delphi-Versionen zur Verfügung stellen. Beim ausführlichen Arbeiten mit DLL in Delphi wirst du Schnell feststellen, dass Du sowieso mit Runtime-Packages kompilieren musst, damit Du nur eine RTL/VCL laufen hast. Spätestens dann muss die DLL in der gleichen Delphi-Version sein.
|
Code liegt doch bei, was meinst du damit?
HelgeLange hat folgendes geschrieben : |
2.) Du nutzt Namen, um Funktionen zu identifizieren. Für kleine Systeme mag das ganz ok sein, wenn es nicht zeitkritisch ist. Bei grösseren Systemen (mit ein paar tausend Funktionen) kann es schon langsam werden. Bei zeitkritischen Systemen (zum Bsp. Spielen) ist es tödlich. Besser über Nummern und Konstanten (zumindest intern). |
hmm gute idee, werd ich in der nächsten version machen
delfiphan hat folgendes geschrieben : |
Versteh mich nicht falsch, aber für so "simple" Funktionen ist es nicht wesentlich einfacher, sicherer und klarer, Interfaces zu schreiben und diese durch exportierte Funktionen zurückgeben zu lassen?
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| type IFoo = interface ['{4C1DD91B-AA83-43AE-9064-9181B156EFF2}'] procedure DoSomething; function ReturnString: WideString; end;
function CreateFoo: IFoo;
exports CreateFoo; |
Importieren geht praktisch genau so einfach.
Delphi-Quelltext 1:
| function CreateFoo: IFoo; external 'Foo.dll'; |
|
könnte gut sein aber ich hab noch nie mit interfacen gearbeited, deshalb hab ich die version über pointer verwendet.
Eventuell kümmer ich mich in späteren Versionen noch darum.
funktioniert doch 8)
naja, soll ja nur ein beispiel sein und das schreibt sich dann noch am schnellsten
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2024 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!