Plugin Interface- Wie am besten umsetzten?

Für allgemeine Fragen zur Programmierung mit PureBasic.
Benutzeravatar
nicolaus
Moderator
Beiträge: 1175
Registriert: 11.09.2004 13:09
Kontaktdaten:

Plugin Interface- Wie am besten umsetzten?

Beitrag von nicolaus »

Hi zusammen,

mal ne frage, wie kann man am besten ein Plugin-Interface umsetzten um seinem Programm die Pluginmöglichkeit zu geben?
Ich überlege schon ein stück wie ichg das am besten realisieren könnte, habeaber noch nicht wirkllich den richtigen weg gefunden.

Was bedingung ist:
- Plugins müßen alls dll vorliegen
- Programm soll Plugins aus Folder XXX automatisch erkennen

Danke euch schon mal für eventzuelle Anregungen.

Nico
Benutzeravatar
TroaX
Beiträge: 720
Registriert: 08.03.2013 14:27
Computerausstattung: PC: Ryzen 9 3950X, 96 GB RAM, RX6800XT, 2.5 TB SSD, 21:9 Display, Linux Mint | Lappi: Ryzen 7 5800H, 16 GB RAM, 1 TB SSD, Linux Mint
Wohnort: NRW
Kontaktdaten:

Re: Plugin Interface- Wie am besten umsetzten?

Beitrag von TroaX »

Im Grunde ist das ja garnet so schwer. Du definierst einen Ordner, in dem die Plugins sind. Bei Programmstart durchsuchst du diesen Ordner nach DLL's, öffnest die mit OpenLibrary und führst eine festgelegte Prozedur aus der DLL aus. Das ist grob der einfachste Ansatz. ;)
PC: Ryzen 9 3950X | 96 GB RAM | RX6800XT | 2,5 TB NVMe | Linux Mint
Notebook: 16" 3:2 | Ryzen 7 5800H | 16 GB RAM | Radeon Vega | 1TB NVMe | Linux Mint
NAS: N150 Mini-PC | 16 GB RAM | Debian 13+CasaOS
Coding: Purebasic, Spiderbasic, Gambas
Blog: https://techtroax.de
Repos: https://codeberg.org/TroaX
Derren
Beiträge: 558
Registriert: 23.07.2011 02:08

Re: Plugin Interface- Wie am besten umsetzten?

Beitrag von Derren »

Ich hab sowas mal angefangen, aber nachdem das Hauptprojekt derzeit auf Eis liegt, wurde das Pluginsystem auch nicht weiter entwickelt.

Hier, ist sogar kommentiert, dein Glück :D


Plugin Host

Code: Alles auswählen

EnableExplicit 

Define PS_PluginPath			.s		= "plugins/"	;Pfad und ID des Plugin Ordners.
Define PS_PluginDirectoryID	.i

Define.i 	WindowEvent, EventGadget, Main_WindowID


Prototype proto_init(hWnd.i)							;Prototypen der Plugin-Funktionen
Prototype proto_eventgadget(eventgadget.i)

Structure plugins_structure							;Struktur, welche die LibraryID enthält 
	libID				.i								;und alle Prototype-Funktionen
	plugin_init			.proto_init
	plugin_eventgadget	.proto_eventgadget
EndStructure


NewList plugins.plugins_structure()					;Liste aller Plugins


Define PS_PluginDirectoryID = ExamineDirectory(#PB_Any, PS_PluginPath, "*.dll")	;Pluginordner durchkämmen und jede DLL laden
While NextDirectoryEntry(PS_PluginDirectoryID)
	AddElement(plugins())
	With plugins()		
		\libID = OpenLibrary(#PB_Any, PS_PluginPath + DirectoryEntryName(PS_PluginDirectoryID))	;DLLs laden und Funktionen mit 
		\plugin_eventgadget = GetFunction(\libID, "plugin_eventgadget")							;Prototype in die Struktur speichern
		\plugin_init 		= GetFunction(\libID, "plugin_init")		 		
	EndWith 
Wend 


Main_WindowID = OpenWindow(#PB_Any , 0, 0, 400, 300, "plugin test", #PB_Window_ScreenCentered|#PB_Window_SystemMenu)

ForEach plugins()
	plugins()\plugin_init(WindowID(Main_WindowID))				;Init-Funktion aller Plugins aufrufen.
Next 

Repeat 
	WindowEvent = WaitWindowEvent(20)
	Select WindowEvent
		Case #PB_Event_Gadget
			EventGadget = EventGadget()
			Select EventGadget
				Case -900		;Irgendeinen Unsinn, damit "Default" funktioniert
					Debug "..."
					
				Default 
					ForEach plugins()								;EventGadget an alle Plugins weiterleiten, die selbst überprüfen, 
						plugins()\plugin_eventgadget(EventGadget)	;ob das EventGadget zum Plugin gehört
					Next 
					
			EndSelect 
			
	EndSelect 
	
	
Until WindowEvent = #PB_Event_CloseWindow
End 

Testplugin, als DLL kompiliert und in den angegebenen Unterordner geschoben.

Code: Alles auswählen

;test.dll

Define button.i

ProcedureDLL plugin_init(hWnd.i)
	Shared button
	UseGadgetList(hWnd)			;Vom Hauptprogramm mitgeteilte GadgetList verwenden (Fenster oder auch ContainerGadget etc...)

	button = ButtonGadget(#PB_Any, 0, 0, 100, 20, "Plugin")
	
	

EndProcedure

ProcedureDLL plugin_eventgadget(eventgadget.i)
	Shared button
	
	If eventgadget = button			;Das Plugin überprüft selbst, ob das EventGadget ein eigenes ist und führt entsprechend Code aus.
		MessageRequester("Plugin","Button pushed")
	EndIf 
EndProcedure 

Der Host erlaubt den Plugins Gadgets zu erstellen. Das sollte viel restriktiver sein, damit sich keine Gadgets von verschiedenen Gadgets überlagern. Aber oftmals öffnet sich für ein Plugin eh ein neues Fenster. Dann gibt es keine Probleme.

Wenn ein Gadget betätigt wird, wird die plugin_eventgadget() Funktion aufgerufen. Somit kann das Gadget reagieren. Das ist nicht sehr elegant, dafür einfach.
Man kann natürlich auch jedes vom Plugin erstelle Gadget an den Host senden, so dass dieser erstmal prüft zu welchem Plugin der Button gehört, bevor die entsprechende Pluginfunktion aufgerufen wird.

Man kann immer alles besser machen und sich natürlich fragen ob man ein System entwickeln will, dass sich auf Riesenanwendungen á la Photoshop hochskalieren lässt, oder ob man eher erstmal kleinere Brötchen backt.
Signatur und so
Benutzeravatar
nicolaus
Moderator
Beiträge: 1175
Registriert: 11.09.2004 13:09
Kontaktdaten:

Re: Plugin Interface- Wie am besten umsetzten?

Beitrag von nicolaus »

Ich danke euch schon mal.
Das Sample hilft super!
Antworten