![]() |
Flexibles Pluginsystem: Diskussion
Flexibel heisst aus meiner Sicht aber auch, dass der Entwickler der Anwendung nicht wissen muss, was der Entwickler des Plugins mit dem Plugin in/an/mit/durch die/der Anwendung machen will. Soll heissen, woher weiss die Anwendung, welche Daten sie wann dem Plugin liefern muss?
Vielleicht löst du das erst mal noch :wink: Dieses Thema bezieht sich auf diesen ![]() [edit=Phoenix]Codelib-Bezug eingefügt. Mfg, Phoenix[/edit] |
Re: Flexibles Pluginsystem
naja die daten sind immer die gleichen
Bsp von Trillian Load Befehl: Zitat:
Des hab ich sogar vergessen zu sagen: Da dem Plugin ein Pointer von der Variable des Records übergeben wird. Somit kann das Plugin die Daten verändern und die Anwendung kann das dann ohne Probleme auslesen. z.b. Versions nummer des Plugins |
Re: Flexibles Pluginsystem
Hallo Alex,
Deine Idee ist nicht schlecht, hat aber einen gaaanz kleinen Haken:
Delphi-Quellcode:
'Befehl an die Anwendung' muss in der PlugIn-dll geparse't werden, was etwas Zeit kostet.
PluginSend('Befehl an die Anwendung', nil);
Ich hatte soetwas ähnliches in meinem Editor auch gemacht, je komplexer das System wurde, umso langsamer wurde es aber. Allerdings ist Deine Methode unschlagbar flexibel. |
Re: Flexibles Pluginsystem
Zitat:
Des war nur ein Beispiel das das Plugin JEDERZEIT einen Befehl an die Anwendung senden kann damit die anwendung irgendwas macht. Das kann man machen muss man aber nicht. Zitat:
Zitat:
|
Re: Flexibles Pluginsystem
Zitat:
Delphi-Quellcode:
aufruft, dann muss in "PluginMain" ja "Befehl" geparse't werden
PluginMain(Befehl, Parameter);
Delphi-Quellcode:
was nicht sooo performant ist, als wenn "machwas" oder "machwasanderes" direkt aufgerufen werden.
if (Befehle = 'BringToFront') then machwas;
if (Befehle = 'GotoXY') then machwasanderes; usw. Selbst wenn man mit "Goto" aus der Schleife rausspringt. Insbesondere wenn man Zitat:
|
Re: Flexibles Pluginsystem
Zitat:
|
Re: Flexibles Pluginsystem
aso jetzt versteh ich des wie du des meinst ... ja das war auch meine Überlegung das alles etwas langsamer wird
naja flexiblität hat seinen Preis :mrgreen: noch ein Tipp:
Delphi-Quellcode:
Dann wird sofort nachdem er den Befehl hat rausgesprungen (sowas wie goto)
if Befehl = '1' then
begin Bla; exit; end; if Befehl = '2' then begin BlaBla; exit; end; if Befehl = '3' then begin BlaBlaBla; exit; end; |
Re: Flexibles Pluginsystem
dat würd ich anders machen ^^
Delphi-Quellcode:
mMn sehr viel eleganter...
case AnsiIndexStrings(Befehl,['1','2','3']) of
0: Do_One; 1: Do_Two; 2: Do_Three; end; |
Re: Flexibles Pluginsystem
Zitat:
"FindComponent" ist da wohl doch etwas performanter. |
Re: Flexibles Pluginsystem
ah des ist ja genial
ich hätte schon case genommen ... mein problem war einfach nur des case nur mit integer geht und die Funktion AnsiIndexStrings kannte ich nicht @kalmi01: FindComponent? Wie soll des gehen? |
Re: Flexibles Pluginsystem
@DGL-luke: Ich wollt des gerade in mein TestPlugin einfügen doch leider kann ich die Funktion AnsiIndexStrings nicht finden. Naja daraus schliesse ich des du sie selber geschrieben hast. Ich bin nur etwas ratlos wie ich die Funktion am besten schreibe vorallem wegen dem zweiten Parameter :wall:
//edit: Habs geschafft:
Delphi-Quellcode:
Kann man des noch irgendwie optimieren?
function AnsiIndexStrings(Befehl : String; StringArray : array of String) : integer;
begin for result := 0 to Length(StringArray) - 1 do begin if Befehl = StringArray[result] then exit; end; Result := -1; end; procedure PluginMain(Befehl : PChar; Parameter : Pointer); stdcall; begin case AnsiIndexStrings(Befehl,['PluginInit', 'PluginStart', 'PluginStop', 'PluginFree']) of 0://PluginInit begin PluginSend := TPluginRecord_PluginInit(Parameter^).PluginSend; end; 1://PluginStart begin end; 2://PluginStop begin end; 3://PluginFree begin end; end; end; |
Re: Flexibles Pluginsystem
Zitat:
![]() Des Weiteren befindet sich in der Unit "StrUtils" eine Funktion die genau das Gleiche tut:
Delphi-Quellcode:
so far
function AnsiIndexStr(const AText: string; var AValues: array of string): Integer;
GimbaR |
Re: Flexibles Pluginsystem
Ich bitte dich... ich würde hier doch nie meine eigenen FUnktionen kommentarlos hinklatschen^^
heisst halt nur n bischen anders: ![]() @GimbaR: jaa.... |
Re: Flexibles Pluginsystem
hehe jetzt hab ich es schon selber geschafft :mrgreen:
troztdem danke Aber noch eine wichtige Frage kann man des noch optimieren ... vllt. mit ein bissi asm? (ich kann leider kein inline asm) @DGL-luke: ja ich habs sie nur nicht gefunden (nicht mal mit Unit suchen) |
Re: Flexibles Pluginsystem
Hi,
alternativ könnte man auch statt eines Strings einen Integer übergebenm, und dort mit Konstanten oder Enumerationen für Befehle arbeiten. Das hätte folgende Vorteile: 1) Schnellere Überprüfung auf Gleichheit! 2) Keine Fehler durch Rechtschreibfehler oder der gleichen. und wenn man neue Konstante immer nur Hinten anfügt hat man auch die Abwertskompatibilität berücksichtigt! Greetz Boombuler PS: War nur so ne Idee :freak: |
Re: Flexibles Pluginsystem
man könnte einen Pointer auf einen Record übergeben. Anonsten nur mit Integer als Enumeration zu arbeiten ist halt blöd, weil damit das übergeben von Parametern (fast) unmöglich ist.
Gruß alias5000 |
Re: Flexibles Pluginsystem
Zitat:
ja es würde ein bisschen die Gischwindigkeit steigern aber naja man könnte sich immer noch mit der Nummer vertippen ABER des mit String Kommands zu machen hat menschliche vorteile ... "Was war Befehl 34345 noch mal *kratz*". aber wenn da steht "ProgrammStart" dann weiss man sofort bescheid :zwinker: es steht natürlich jedem frei integer zu verwenden. aber ich bleibe bei Strings :zwinker: |
Re: Flexibles Pluginsystem
Hallo,
Zitat:
Gruß xaromz |
Re: Flexibles Pluginsystem
man könnte sogar das windows messaging missbrauchen und sich per
![]() aber konstante sollten hier reichen,. |
Re: Flexibles Pluginsystem
ok stimmt :thumb:
Am besten in der Gemeinsamen Unit (also die die man veröffentlichen sollte) einfach alle Konstanten definieren. |
Re: Flexibles Pluginsystem: Diskussion
so ich hab nochmal wegen dem Observer nachgedacht und mir ist dann ein super konzept eingefallen :mrgreen:
hab heut den ganzen Tag an diesem System programmiert. Nun ist es ein Flexibles Observer Pluginsystem :cheers: Die Flexiblität des Pluginsystems ist erhalten geblieben. Nur muss das Plugin beim starten der Anwendung bei meinem Observer anmelden. Sobald einmal angemeldet wird das Plugin bei diesem Ereignis benachrichtigt und kann sofort darauf reagieren. *auf Uhr schau* (1:20 Uhr) Ich bin jetzt aber viel zu müde um ein Tutorial darüber zu schreiben, denn das ganze ist hoch komplex und wird wahrscheinlich nicht leicht zum erklären sein. Vielleicht komm ich morgen oder übermorgen dazu. |
Re: Flexibles Pluginsystem: Diskussion
Kann man eigentlich auch Plugins in einer anderen Sprache programmieren?
Also das das Programm in Delphi ist, das Plugin aber beispielsweise C++ oder so? Ich weis dass es Records nur unter Delphi gibt(oder? :gruebel: ) Aber wenn man etwas anderes verwendet was andere Sprachen auch können müsste es doch gehen oder? |
Re: Flexibles Pluginsystem: Diskussion
sicher kann man das
und man kann auch records benutzen weil records ist ja nichts delphi spezielles (außer der name) sonderen nur eine datenttyp wo mehere variablen nacheinander reingestopft werden. In C++ und so gibt es des imho auch nur weiß ich gerade nicht wie es heißt |
Re: Flexibles Pluginsystem: Diskussion
... records gibt es auch in C, die heißen da nur structs. und sind je nach cmopiler eventuell anders aligned, weshalb man in delphi packed records verwenden sollte.
|
Re: Flexibles Pluginsystem: Diskussion
also wenn ich packed records verwende kann ih ohne größere Probleme die Plugins in anderen Sprachen schreiben?
Ihr sagt in C da heissen die Structs, C++, wo noch? Gibts da irgendwo Informationsquellen dafür? |
Re: Flexibles Pluginsystem: Diskussion
Mir ist gerade eingefallen des ich des selber mal in der DP gefragt hab:
![]() |
Re: Flexibles Pluginsystem: Diskussion
Wie sieht es denn aus mit dem Flexiblen Observer Pluginsystem Tutorial? Würde mich scon interessieren, da ich da im moment auch dran arbeite sowas zu machen. Wär cool, wenn du das noch mal machen könntest gsh...
|
Re: Flexibles Pluginsystem: Diskussion
hmm jojo wenn ich dazu zeit hätte, aber da ich zur zeit 3,5 Jobs habe bin ich ehrlich gesagt zu erschöpft um mich da dran zu setzen
aber mal schaun wollt mir jetzt eh mal wieder urlaub gönnen :mrgreen: |
Re: Flexibles Pluginsystem: Diskussion
heyho, also ich hab mich jetzt auch mal an ein Pluginsystem gesetzt...im Grunde ist das ne Mischung aus dem Tutorial von sakura und deiner Idee (denk ich zumindest oO ^^) also es ist auf jedenfall nichts besonderes denk ich...
es gibt eine Klasse TPlugin, von dem man seine Plugins ableiten kann...jedes Plugin enthält den Befehl Execute dem man dann die Parameter übergeben kann...dann gibts noch die Callbackprozedur Send, mit der dann Werte zurückgegeben werden können...sprich ich übergeb z.B. einem Downloadplugin den Befehl CMD_DOWNLOAD (einfach Konstanten) und dazu dann die Parameter als array of string, und in der DLL wird der Command ausgewertet, verarbeitet, und mit Send werden dann wieder Daten zurückgegeben, z.B. die Fortschrittsanzeige...in der Anwendung sieht dass dann z.B. so aus
Delphi-Quellcode:
Die PluginDefinition.pas enthält alle Klassen und die FUnktion zum Laden des Plugins, sprich man braucht außer dieser Unit und der RecieveProc Prozedur nichts...in der DLL nimmt man ebenfalls die plugindefinition.pas, und erstellt sich eine Klasse...z.B.
uses {...} PluginDefinition;
var plugin1: TPlugin; procedure RecieveProc(cmd: integer; parameter: array of string); begin case cmd of // hier werden dann die commands ausgewertet CMD_SHOWMESSAGE: showmessage(parameter[0]); end; end; {...} procedure TForm1.FormCreate(Sender: TObject); var name: string; begin plugin1 := TPlugin.Create; loadplugin('plugins/plugin.dll', plugin1); plugin1.Send := RecieveProc; plugin1.Execute(CMD_GET_NAME,['']); // nur ein Beispiel ;-) end;
Delphi-Quellcode:
Das mag jetzt zwar nicht soooo besonders anspruchsvoll und schwierig sein, und über Interfaces könnte man denk ich mal da schon bessere Sachen machen, aber es erfüllt seinen Zweck Prima...man definiert sich einfach seine Konstanten, und kann sich damit dann doch auch eine ganz flexible API erstellen...
{...}
TPlugin01 = class(TPlugin) public constructor Create(aParent: THandle); overload; function GetName: string; override; stdcall; function GetAuthor: string; override; stdcall; function GetComment: string; override; stdcall; procedure Execute(cmd: integer; parameter: string); override; stdcall; end; constructor TPLugin01.Create(aParent: Cardinal); begin inherited Create; Parent := aParent; end; function TPlugin01.GetName: string; begin result := 'Testplugin'; //showmessage('Testplugin'); end; function TPlugin01.GetAuthor; begin result := 'LH_Freak'; end; function TPlugin01.GetComment; begin result := 'Nur ein Test'; end; procedure TPlugin01.Execute(cmd: Integer; parameter: string); begin case cmd of CMD_GET_NAME: send(CMD_SHOWMESSAGE, ['Testplugin']); end; end; function LoadPlugin(Parent: THandle; var PlugIn: TPlugIn): Boolean; export; begin try PlugIn := TPlugIn01.Create(Parent); Result := True; except Result := False; end; end; exports LoadPlugin name 'LoadPlugin'; begin //MessageBeep(0); end. Bei Bedarf kann ich die PluginDefinition.pas ja mal hier veröffentlichen :) Gruß Flo P.S.: Ich werde das ganze demnächst in den MUH Messenger einbauen, da mich das schon irgendwie reizt auszuprobieren was damit alles geht, und das eignet sich ja mal wohl perfekt ;-) |
Re: Flexibles Pluginsystem: Diskussion
Für Plugins empfehlen sich Interfaces, gerade dann, wenn man auch Sprachenunabhängig arbeiten will (C, Delphi...)
Oder Packages, wenn man bei Delphi bleibt... Denn mit sowas da
Delphi-Quellcode:
in dlls, kommt man sehr sehr schnell ans Limit der flexibilität...
function LoadPlugin(Parent: THandle; var PlugIn: TPlugIn): Boolean; export;
begin try PlugIn := TPlugIn01.Create(Parent); Result := True; except Result := False; end; end; Bye Christian |
Re: Flexibles Pluginsystem: Diskussion
Nein das Flexible Pluginsystem von mir beruht NICHT auf dem Tutorial von sakura (ich kannte des zu dem zeitpunkt noch nicht mal)
und du hast mehr von sakura reinkopiert kommt mir vor denn in meinem TUT ist keine einzige Klasse und der Parameter ist auch ein ganz ein anderer |
Re: Flexibles Pluginsystem: Diskussion
Zitat:
Zitat:
|
Re: Flexibles Pluginsystem: Diskussion
Problem dabei, die RTTI steht dir dabei nur bedingt zur Seite...
Was zu sehr vielen kleinen Problemen und AHA-Effekten führen wird. Interfaces an sich sind gar nicht mal so schwer wie sie aussehen, zudem legen sie die Grundlage für schöne Erweiterungen, z.B. Com-Schnittstellen ec... Bye Christian |
Re: Flexibles Pluginsystem: Diskussion
Delphi-Quellcode:
Hey Leute, kann mir jemand diesen teil erklären? mit "PluginSend;"?
var
TempPluginRecord_PluginInit : TPluginRecord_PluginInit; PluginMain : procedure(Befehl : PChar; Parameter : Pointer); begin {Plugin laden und PluginMain procedure zuweisen} TempPluginRecord_PluginInit.PluginSend := PluginSend; //PluginSend? TempPluginRecord_PluginInit.NochEinPChar := 'blabla'; PluginMain('PluginInit', @TempPluginRecord_PluginInit); end; 1.klappt das bei mir nicht, ist ja auch nicht verwunderlich da ich das nicht deklariert habe, und 2. ich kopiere nicht gerne source wo ich nicht alles verstehe.. |
Re: Flexibles Pluginsystem: Diskussion
ich hab da mal ne frage. oben wurde gasagt es empfiehlt sich interfaces zu verwenden. aber warum soll man dies tun, ich mein was hat das für nen vorteil oder warum stößt man dabei an die grenzen der flexibilität?
|
Re: Flexibles Pluginsystem: Diskussion
Meiner Erfahrung nach gibt es zwei Probleme bei der Plugin/DLL-Geschichte:
* Strings * Objekte und Klassen Strings und alle nicht Basistypen wie integer, char, pointer (damit auch pchar) [was ist mit variants?] verursachen in DLLs Probleme. Hängt mit dem Speichermanager zusammen, kann jeder nachlesen, steht da wenn man eine neue DLL erstellt. Lösung hier ein anderer Speichermanager. Bei Objekten und Klassen ist das ganze schon schwieriger zu lösen. Delphi macht es mit den Laufzeit Packages. Der Kern des Problems liegt darin, dass Delphi wissen muss dass ein "TObject" aus der Anwendung auch ein "TObject" aus der DLL ist. Was ja nicht der Fall sein muss, wenn die beiden mit verschiedenen Versionen erstellt wurden. Also wirft das hier erst einmal eine Exception:
Delphi-Quellcode:
Das zieht sich durch die ganze Klassenhierarchie und macht sich immer wieder durch Laufzeitfehler bemerkbar.
// code in der Anwendung, ObjektAusDLL wurde zuvor von der DLL initialisiert
// z.B. mit ObjektAusDLL := TFormDLL.create( nil); return ObjektAusDLL if not(ObjektAusDLL is TObject) then raise Exception.create('Nicht mit Anwendungs-RTL kompatibel'); // z.B. ObjektAusDLL.Parent := self; Die Lösung hier sind Interfaces, so zwar konsequent so, dass die Anwendungs-RTTI und die DLL-RTTI nicht miteinander in Berührung kommen. Denn Interfaces nutzen GUID's, die Sprachunabhängig definiert sind und so beliebig funktioneren. D.h. man hat am besten als Include oder "interface"-Unit
Delphi-Quellcode:
und bindet diese sowohl in die Anwendung als auch in die DLL ein. Das ist wichtig damit die GUID in beiden identisch sind.
// ['{3F2504E0-4F89-11D3-9A0C-0305E82C3301}'] ist die GUID für das interface
// kopiert aus dem wikipedia Artikel zu "Globally Unique Identifier" IUnserInterface = interface ['{3F2504E0-4F89-11D3-9A0C-0305E82C3301}'] damit ist eine Abfrage erfolgreich:
Delphi-Quellcode:
Man abstrahiert demnach das Identifizieren von gleichen Typen auf eine compiler- und plattformunabhängige Art.
dllInstanz := GetDLLInterface;
if dllInstanz is IUnserInterface then ShowMessage( 'Alles ok'); ACHTUNG: Damit ist es aber immer noch nicht möglich Steuerelemente die in der DLL erstellt werden in der Anwendung zu benutzen! Ein Panel aus der DLL wird nicht auf einer Anwendungsform korrekt funktionieren, da die interne Struktur auf oben genannte Probleme keine Rücksicht nimmt! |
Re: Flexibles Pluginsystem: Diskussion
Ok das ist zwar alles schön und gut aber.. wie kann man eine DLL zur Laufzeit laden und das noch mit flexiblem Dateinamen oO?
Nur mal so als Beispiel:
Delphi-Quellcode:
Das steht im interface Bereich.. wie bekomme ich so ein "icmp.dll" dynamisch zugeordnet?
function IcmpCreateFile : THandle; stdcall; external 'icmp.dll';
|
Re: Flexibles Pluginsystem: Diskussion
Mir stellt sich da die Frage wie ich so ein Plugin in die Menüstruktur / Befehlstruktur einfüge:
Das Plugin muß eine Anmelderoutine haben wo es in Listenform angibt welche Befehle es anbietet und welche Menuenamen diese Befehle haben. Eine Andere Vairante ist das es selbst ein Panel anbietet wo die einzelnen Befehle als Ereignisse hinterlegt sind. Bei anmelden des Plugins wird dann der Parent auf ein Panel der Hauptanwendung gelegt... Grüße // Martin |
Re: Flexibles Pluginsystem: Diskussion
Zitat:
![]() Zitat:
1. Du könntest für Plugins einen befehl bereitstellen der das MenuItem erstellt und verschiedene erreignisse zurückgibt. 2. Oder was glaube ich einfacher ist das du das Parent Object auf Anfrage übergibst und sie dann selber sich eine menü struktur anlegen können. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 16:08 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