![]() |
einfaches plugin-system
Hallo
ich bräuchte ein Pluginsystem, wo jedes Plugin nur eine einfache Funktion beinhaltet, die einen String zurückgibt. Hat jemand ein einfaches Beispiel, Code, Tips?? Tnxs the OmeGa |
Ich bin mir ja nicht sicher, was Du erreichen willst, aber das hört sich nach einem typischen DLL Problem an. Das heisst, alle Plugins liegen als DLL vor und werden vom Programm "on-demand" geladen.
Wenn es das ist, dann ist es eigentlich recht einfach. :cat: P.S. Unter Umständen reicht eine INI Datei (oder mehrere)... |
nein, eine INI-Datei reicht nicht, weil die Plugins verschiedene Daten zurückgeben(u.a. aus dem Internet, aus dem Netzwerk, Bios, Hardware)
Aber sonst müßte das mit einfachen DLLs schon gehen. Hat jemand (hast du) ein Beispiel???? Tip? |
Beispiel habe ich keines; dafür aber einen Tipp:
Deine Anwendung könnte sich aus Deinem PlugIn-Verzeichnis alle DLL's herauslesen ("FindFirst" / "FindNext"), jede dieser Bibliotheken laden und mittels "GetProcAddress" herausfinden, ob die aktuell geladene Bibliothek eine von Dir definierte Prozedur exportiert. (Mehr zu GetProcAddress in der MSDN-Bibliothek unter ![]() Grüße, Daniel |
Das blick ich jetzt nicht
|
Du schreibst eine Funktion, wie etwa:
Code:
Da es sich um eine DLL handelt, musst du dafür sorgen, dass diese Funktion auch exportiert wird. (Wie, steht in der Delphi-Hilfe.) Mir ist jetzt nichts Besseres eingefallen; aber bei einer Funktion sollte man noch irgendwas machen, dass den Rückgabewert rechtfertigt. Es kann also auch eine Prozedur sein.
function IchBinEinPlugin: boolean;
begin MessageBox(0,'Da bin ich!','Plugin', MB_OK or MB_ICONINFORMATION); Result := true; end; Der Rest ist dynamisches Laden von DLL-Prozeduren und -Funktionen. Beispielsweise so:
Code:
So, ich hoffe, dass ich jetzt keine groben Schnitzer gemacht habe (vielleicht Schreibfehler), aber so sähe das Prinzip mit GetProcAddress aus. Bei all deinen Plugins solltest du immer den gleichen Funktionsnamen benutzen - in dem Fall also "IchBinEinPlugin" - damit dein Programm nur die korrekten DLLs lädt.
type
// diese Deklaration MUSS der Deklaration der // DLL-Funktion entsprechen!!! // In diesem Fall ist es also eine Funktion mit // Bool-Rückgabewert TDllFunc = function: boolean; var MeineDll : dword = 0; DllFunc : TDllFunc; { ... } MeineDll := LoadLibrary('plugin.dll'); if(MeineDll <> 0) then begin // hier wird versucht, die Funktion "IchBinEinPlugin" // (s. erstes Code-Beispiel) zu laden DllFunc := GetProcAddress(MeineDll,'IchBinEinPlugin'); // geht nicht, dann ist´s auch kein Plugin von dir if(@DllFunc = nil) then begin FreeLibrary(MeineDll); MeineDll := 0; end; end; { ... } // irgendwas machen // am Programmende immer die DLL(s) freigeben if(MeineDll <> 0) then FreeLibrary(MeineDll); Wenn das Laden also geklappt hat, kann dein Programm die Plugin-Funktion aufrufen, was eine Dialogbox mit der Meldung "Da bin ich" zur Folge haben sollte. Habe ich was vergessen, Leute? :? |
passt genau, für nachmacher den Tip: die funktionen in der DLL dürfen als rückgabewert keinen String enthalten, stattdessen pchar verwenden.
|
Zitat:
:cat: |
Ich habe mal die unendlichen Weiten meiner HD durchwühlt und folgendes Beispiel eines Plugins gefunden, was IMHO richtig interessant ist und als Ansatzpunkt für eigene Dinge benutzt werden kann. (Ich wusste doch, dass ich so was rumliegen habe.) Das Beispiel stammt von William Yang. Ich habe - soweit ich´s für erforderlich hielt - Kommentare eingesetzt. Ansonsten ist aber nichts verändert!
1. Das Programm, dass die Plugins lädt, exportiert selbst eine Funktion, die den ausgewählten Text eines Memos ändert. Das Folgende steht im Projektquelltext (*.dpr):
Code:
procedure ReplaceText(Text: PChar); far;
begin Form1.Memo1.SelText := StrPas(Text); end; exports ReplaceText; 2. Die Plugin-DLL besteht nur aus den paar Zeilen:
Code:
library First;
{ Important note about DLL memory management: ShareMem must be the first unit in your library's USES clause AND your project's (select View-Project Source) USES clause if your DLL exports any procedures or functions that pass strings as parameters or function results. This applies to all strings passed to and from your DLL--even those that are nested in records and classes. ShareMem is the interface unit to the DELPHIMM.DLL shared memory manager, which must be deployed along with your DLL. To avoid using DELPHIMM.DLL, pass string information using PChar or ShortString parameters. } uses SysUtils, Classes, Windows; type //Turn the optimize and huge string option off //if Delphi cannot compile your plugin // you will see when your have some compilicated typecasts iReplace = procedure (Text: PChar); var OwnerApp: Integer; function GetName: Pchar; far; begin // Das ist der Eintrag, der später im Menü des Hauptprogramms // stehen wird Result := '&First Test'; end; // hier ruft die DLL die "ReplaceText"-Funktion aus dem Hauptprogramm // auf und ersetzt den ausgewählten Text im Memo durch einen fixen // Text procedure InsertText; far; begin iReplace(GetProcAddress(OwnerApp, 'ReplaceText'))('Magic Plugins'); end; procedure Init(Owner: Integer); far begin OwnerAPP := Owner; end; exports GetName, InsertText, Init; begin end. 3. Im Formularcode wird jetzt ein solches Plugin geladen und in eine eigene Klasse geschrieben. Bevor ihr loslegt: ihr braucht noch ein Memo und ein Hauptmenü mit dem Eintrag "Plugin". Vorhanden? Dann kommt das: [code:1:68de408964]var Plugins: TList; type //plug in object TTestPlugIn = class Name: String; Address: Integer; Call: Pointer; end; //type cast of plug in functions GetNameFunction = function : PChar; InserText = procedure; //HInstance is the application's histance, send it to the //plugin so it can use the exports function from here. PlugInInit = procedure (Owner: Integer); var StopSearch : boolean; // btw: noch eine Variante zum Dateiensuchen ;o) procedure SearchFileExt(const Dir, Ext: String; Files: TStrings); var Found: TSearchRec; Sub: String; i : Integer; Dirs: TStrings; //Store sub-directories Finished : Integer; //Result of Finding begin StopSearch := False; Dirs := TStringList.Create; Finished := FindFirst(Dir + '*.*', 63, Found); while (Finished = 0) and not (StopSearch) do begin //Check if the name is valid. if (Found.Name[1] <> '.') then begin //Check if file is a directory |
Das ist jetzt schon wesentlich komplizierter. Aber ich habe es mit MathiasSimmack's Tip hinbekommen. Aber aus irgendeinem Grund nur mit PChar. Bei Strings gab es einen laufzeitfehler, tortz eingebundener sharemem.
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 04:49 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