Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Plugin-System fragen (https://www.delphipraxis.net/151495-plugin-system-fragen.html)

b1428727 20. Mai 2010 09:50


Plugin-System fragen
 
Hallo und guten tag zusammen...

ich mache mir gedanken über ein plugin-system welches ich in meine anwendung integrieren möchte.
habe mir hier im forum auch schon beispiele angesehen wie dies funktionieren könnte.

aber es gibt da eine spezielle hürde, welche ich noch nicht bewältigt habe.

problem
wie kann mann plugins einbinden welche
  • a. in möglichst jeder sprache geschrieben werden können (pascal und c würden mir reichen)
    b. fenster enthalten
    c. diese fenster (b) an mein haupt-formular gedockt werden können
    d. diese gedockten fenster (c) unpinnbar sind
info zu d: pin-klicken sodass diese wie in delphi nach links sliden und keinen platz mehr brauchen


mögliche lösung, ole-variante
ich habe mir gedacht, diese ole schnittstelle wäre ja prima geeignet.
mann kann in verschiedenen sprachen ein ole-objekt erzeugen, somit wäre punk a erfüllt.

ich könnte ein formular in meiner eigenen anwendung erzeugen, somit wäre punkt b,c und d erfüllt.
auf diesem formular platziere ich einen ole-container welches dann das ole-objket vom plugin enthält.

das ole-objekt müsste wohl ein activeform sein, somit kann es sich selber im ole-container zeichnen und dort
ausgeführt werden.

problem an dieser geschichte ist:
wenn ich das ole objekt erzeuge z.b. ein "word.document", oder ein "excel.sheet" funktioniert das
wunderbar in meinem formular, jedoch sobald dies gedockt wird, gibt es probleme.
habe auch ein eigenes activeform objekt in einer bibliothek erstellt und dies in den ole-container
geladen. auch damit funktioniert es nur bis das fenster gedockt wird.

sobald das formular mit dem ole-container gedockt wird, verschwindet der inhalt
vom ole-container. (mit DoVerb(ovShow) wird dann auch nurnoch das menü vom word angezeigt aber
das dokument ist wegg).

ich erkenne die inkompatibilität vom ole-container/-inhalt zum docken nicht.
was können da die ursachen sein? kann mann diese umgehen oder ist es grundsätzlich mit ole-container nicht möglich?

andere varianten
sind mir bisher noch nicht in den sinn gekommen. aber evtl. gibt es eine andere lösung, ohne ole
welche meine wünsche a-d erfüllen könnte?


vielen dank für jeglichen input.

grüsse

himitsu 20. Mai 2010 10:10

Re: Plugin-System fragen
 
Zitat:

a. in möglichst jeder sprache geschrieben werden können (pascal und c würden mir reichen)
DLL und alles über Interfaces (statt String verwende besser den WideString, da der String erstmal nicht über EXE-DLL-Grenzen hinweg verwaltbar und dazu noch ein delphieigener Typ ist).
Du darfst also nur Typen und Methoden nutzen, welche überall existieren.

Zitat:

b. fenster enthalten
Das schließt sich mit A etwas aus, es sei denn du arbeitest NonVCL und oder die Fenster der DLL/Prlugins interagieren nicht mir denen der EXE/Anwendung.

Am Einfachsten, stelle eine Schnittstelle her, über welche die Plugins eine Form zusammenbasteln können.
So mit Funktionen wie ErstelleFenster, ErstelleEdit ... und die Callbacks (die Ereignismethoden ala OnClick wieder über ein Interface im Plugin weiterleiten)
Und schon hast du auch C und D gelöst, da dieses direkt in der Anwendung verwaltet werden kann.
So sind zwar nur "einfache" Fenster möglich, aber immerhin ist dann alles aus einer Hand und eine Anwendung behält die vollte Kontrolle. (ist z.B. gut, falls irgendwann auch noch Themes, bzw. eine Design-Enginge eingesetzt werden sollen)


PS:
http://www.delphipraxis.net/internal...lugin+tutorial
http://www.delphipraxis.net/internal...lugin+tutorial

Und willkommen an Board :hi:

mkinzler 20. Mai 2010 10:23

Re: Plugin-System fragen
 
Zitat:

(statt String verwende besser den WideString, da der String erstmal nicht über EXE-DLL-Grenzen hinweg verwaltbar und dazu noch ein delphieigener Typ ist...)
Ein delphieigener typ ist es nunmal aber nicht, sondern eine OLE-Typ.

Bernhard Geyer 20. Mai 2010 10:34

Re: Plugin-System fragen
 
Sollte alles (u.U. mit viel Aufwand) möglich sein. Unsere eigenes Plugin-System kann Fenster von DLL's (C-Kompatible schnittstelle) in Hauptformular einbetten und unterstützt Shortcuts + Tabs. Tiefgreifende Delphi+Win32-API-Kenntnisse und 1-2 Wochen für das Fensterhandling sind schon nötig.

blackfin 20. Mai 2010 10:46

Re: Plugin-System fragen
 
Eine andere Möglichkeit für ein Plugin-System ist die Erstellung einer eigenen API für das Programm, die du dann über eine Scriptsprache nach aussen trägst.
So etwas in der Art habe ich mal mit Delphi + Scriptsprache Lua gemacht, klappt wunderbar.

Es ist natürlich ein relativ hoher Aufwand, die ganzen Funktionen, die per Scriptscprache zur Verfügung stehen sollen, nach Aussen zu tragen, allerdings hast du dadurch die volle Kontrolle, was deine Plugins dürfen und was nicht.

Fenster, deren Elemente und Ereignisroutinen könntest du über XML beschreiben, die Eventhandler auf Lua-Funktionen legen und in diesen Wiederum die Applikations-API aufrufen.
So in etwa funktioniert auch z.B. das Plugin-System von World of Warcraft, die gesamten Addons werden darüber geschrieben.

b1428727 20. Mai 2010 13:21

Re: Plugin-System fragen
 
Vielen dank für eure antworten.

Zitat:

Zitat von himitsu
...
Am Einfachsten, stelle eine Schnittstelle her, über welche die Plugins eine Form zusammenbasteln können.
So mit Funktionen wie ErstelleFenster, ErstelleEdit ... und die Callbacks (die Ereignismethoden ala OnClick wieder über ein Interface im Plugin weiterleiten)
Und schon hast du auch C und D gelöst, da dieses direkt in der Anwendung verwaltet werden kann.
So sind zwar nur "einfache" Fenster möglich, aber immerhin ist dann alles aus einer Hand und eine Anwendung behält die vollte Kontrolle. (ist z.B. gut, falls irgendwann auch noch Themes, bzw. eine Design-Enginge eingesetzt werden sollen)
...

Das ist mir viel zu viel aufwand. ich befürchte auch, dass die plugin-hersteller dann immer mehr wünsche
haben werden bezüglich zur verfügung stehender controls. im sinne von bitte bau uns noch ein ErstelleTreeview,
ErstelleImage, ErstelleX, ErstelleURLLabel, ErstelleYZ, etc... ich möchte noch events für OnMouseOver, OnEnter, OnXYZ, etc...

darum habe ich mir gedacht, wenn ich dies über einen ole-container mache, können die plugin-hersteller
programmieren was sie wollen und auch so wie sie es in deren sprache bereits gewohnt sind...
und sie können alle Controls benutzen die sie in ihrer sprach-umgebung haben.

Zitat:

Zitat von Bernhard Geyer
Sollte alles (u.U. mit viel Aufwand) möglich sein. Unsere eigenes Plugin-System kann Fenster von DLL's (C-Kompatible schnittstelle) in Hauptformular einbetten und unterstützt Shortcuts + Tabs. Tiefgreifende Delphi+Win32-API-Kenntnisse und 1-2 Wochen für das Fensterhandling sind schon nötig.

diese eingebundenen fenster können dann auch an das hauptformular gedockt werden? so ähnlich wie in delphi?
auch mit der funktion unpinn, pinn (also wegg-sliden und wenn mit maus auf das DockTabSet wieder erscheinen?)
Da gibt es keine probleme?

kann auch in einem teil (container z.b. scrollbox) eines fensters der hauptanwendung das fenster der plugin-dll
angezeigt werden? das wollte ich nämlich auch noch. sodass ich z.b. ein Einstellungen-Fenster in meinem programm habe
mit diversen tabs z.b. Allgemein (meins), Erweitert (meins), Drucken (von Plugin-Drucken), Mailen (von Plugin-Email), etc.

Zitat:

Zitat von blackfin
Eine andere Möglichkeit für ein Plugin-System ist die Erstellung einer eigenen API für das Programm, die du dann über eine Scriptsprache nach aussen trägst.
So etwas in der Art habe ich mal mit Delphi + Scriptsprache Lua gemacht, klappt wunderbar.

Es ist natürlich ein relativ hoher Aufwand, die ganzen Funktionen, die per Scriptscprache zur Verfügung stehen sollen, nach Aussen zu tragen, allerdings hast du dadurch die volle Kontrolle, was deine Plugins dürfen und was nicht.

meine plugins dürfen in einem definierten container eigentlich machen was sie wollen.



die idee dies mit active-forms zu lösen wäre doch eigentlich gut, oder meint ihr nicht?
der internet explorer hat auch so eine funktionalität. flash und solche inhalte werden
dort auch eingebunden (vermutlich auch über diese activeforms) und die können dann in ihrem rahmen machen was sie wollen.

hier ist noch ein beispiel auf welches ich mal gestossen bin wie man mit delphi eine control im internet explorer erzeugt über
activeforms http://delphi.about.com/od/interneti...l/aa042099.htm
das scheint mir eine super lösung zu sein, wenn da nur nicht dieses docking-problem wäre.

und der aufwand ist auch sehr klein, mann braucht nur einen TOleContainer und die angabe,
welches objekt darin angezeigt werden soll.

ein normales fenster kann ich docken, aber wenn auf dem form ein olecontainer ist, dann verschwindet der inhalt
nach dem docken und manchmal stürzt auch der ole-server ab (z.b. word)

b1428727 20. Mai 2010 15:27

Re: Plugin-System fragen
 
habe nun herausgefunden dass selbst das docken eines formulars mit einer twebbrowser-komponente
nicht richtig funktioniert. bzw. die webbrowser komponente wird nach dem eindocken sofort zurückgesetzt.

ich bekomme langsam zweifel daran, dass mann ole und docking überhaupt verbinden kann...

habe auch noch den Jedi docking manager ausprobiert (TJvDockServer mit TJvDockClient),
aber auch hier verschwindet der inhalt vom twebbrowser.

implementation 20. Mai 2010 17:43

Re: Plugin-System fragen
 
Ich habe sowas bisher immer so geregelt, dass ich ein paar Interface zu jedem Zweck gebastelt habe (z.B. eins für Dock-Fenster, eins für Label, usw.) + ein Factory-Interface deklariere und beim Start des Plug-Ins die Factory übergebe.
Delphi-Quellcode:
type
  IFactory = interface
    function CreateDockWindow: IDockWindow;
    ...
  end;
  IDockWindow = interface
    function GetCaption: string;
    procedure SetCaption(val: string);
    property Caption: string read GetCaption write SetCaption;
    ...
  end;

type
  TFactory = class(TInterfacedObject, IFactory)
    ...
  end;
  TDockWindow = class(TInterfacedObject, IDockWindow)
    ...
  end;
Die Interfaces kann dann jeder Plug-In-Entwickler in seiner Sprache deklarieren.
Außerdem können die Plug-Ins schön klein bleiben, da ein Delphi-PlugIn dann z.B. keine VCL braucht, ein VC++-PlugIn keine MFC/WTL usw.

b1428727 21. Mai 2010 07:47

Re: Plugin-System fragen
 
aber auch diese methode schränkt ja die plugin-entwickler auf die vom interface zur verfügung gestellten komponenten ein.

es wäre doch toll, wenn die plugin-entwickler ihre eigenen objekte/komponenten nutzen könnten.
dann habe ich weniger aufwand und die plugin-ersteller müssen nicht meine interface-deklarationen lernen.

b1428727 21. Mai 2010 08:11

Re: Plugin-System fragen
 
die feststellung mit der webbrowser komponente hat mich auf eine seite geführt.
diese erklärt warum docking und ole-(activeforms) nicht funktioniert!

das problem ist delphi.

denn delphi zerstört beim docken alle window-handles (habs selber nicht überprüft)
und erstellt diese dann neu!

die objekte im ole-container halten eine solche prozedur nicht aus und zeigen
danach fehler.

als möglicher lösungsvorschlag wurde das verschieben von activex objekten
in ein anderes formular genannt. also vor dem docken die objekte in ein
anderes formular packen und nach dem dock-vorgang die objekte wieder zurückschieben.

hier der link zu der seite welche dieses problem umschreibt (englisch):
http://community.devexpress.com/foru...053/30661.aspx

es ist ein bisschen ein gebastel, aber ich werde mal probieren ob ich das hinkriege...
ansonsten müssen halt entweder die kunden auf das docking verzichten oder aber
ich erstelle die docking-formulare selber und die pluginhersteller können
über ein interface halt nur daten in eine von mir vorgegebene struktur passen...
ole-container dürften halt dann nur in nicht-dockbaren fenstern vorkommen...


vielen dank für eure hilfen

gruss

himitsu 21. Mai 2010 08:36

Re: Plugin-System fragen
 
Zitat:

Zitat von b1428727
es wäre doch toll, wenn die plugin-entwickler ihre eigenen objekte/komponenten nutzen könnten.
dann habe ich weniger aufwand und die plugin-ersteller müssen nicht meine interface-deklarationen lernen.

Du kannst auch ein ErstellePanel bereitstellen und dessen Handle übergeben.

Ein Panel ist wie eine Form und darin kann man nun alles machen, was man will.
(z.B. bei einer Form MSDN-Library durchsuchenSetParent und da das Handle angeben, schon wird diese Form in das Panel eingefügt)
Aber bei den Standardkomponenten behält deine Anwendung dennoch die Kontrolle.

b1428727 21. Mai 2010 09:45

Re: Plugin-System fragen
 
Zitat:

Zitat von himitsu
Zitat:

Zitat von b1428727
es wäre doch toll, wenn die plugin-entwickler ihre eigenen objekte/komponenten nutzen könnten.
dann habe ich weniger aufwand und die plugin-ersteller müssen nicht meine interface-deklarationen lernen.

Du kannst auch ein ErstellePanel bereitstellen und dessen Handle übergeben.

Ein Panel ist wie eine Form und darin kann man nun alles machen, was man will.
(z.B. bei einer Form MSDN-Library durchsuchenSetParent und da das Handle angeben, schon wird diese Form in das Panel eingefügt)
Aber bei den Standardkomponenten behält deine Anwendung dennoch die Kontrolle.

habe ein test-programm geschrieben um dies auszutesten.

programm hat ein haupt-formular, ein komponenten-formular und ein docking-formular
-das komponenten-formular enthält ein edit, label, memo, etc.
-das docking-formular enthält ein panel, docking-formular kann an das haupt-formular gedockt werden.
-das hauptformular kann docking-formulare erstellen

wenn ich nun mit Windows.SetParent(komponentenformular.handle,docki ngformular.panel.handle)
das ganze formular in das panel packe, dann das dockingformular docke verschwindet auch alles.

himitsu 21. Mai 2010 09:54

Re: Plugin-System fragen
 
Hmmm, kannst du mal etwas testen?

Welchen Wert hat Handle denn vor und nach dem Docking ... verändert sich eventuell das Handle?

b1428727 21. Mai 2010 12:38

Re: Plugin-System fragen
 
ja, es gibt neue handles... für das docking-formular selbst UND auch für das panel im docking-formular.
jeweils nach docking bzw. undocking.

himitsu 21. Mai 2010 12:55

Re: Plugin-System fragen
 
OK, dann erklärt das schonmal das Verschwinden der Nicht-VCL-Komponenten.

Delphi erstellt die internen Windows-Controls gerne mal neu, wenn sich der Fenster-Style verändert.
Dabei gehen natürlich alle WinAPI-Sachen verloren.
Danach wird die Anzeige dann aus den VCL-Objekten neu aufgebaut, aber dort fehlen natürlich die "externen" Controls und alle (der VCL unbekannten und somit nicht beachteten) Änderungen via WinAPI.



Einzige Idee, welche ich aktuell hätte, wäre:

> vor dem (Un)Docking:
- alle externen Controls suchen
(im Fall der GibMirPanel wäre es einfach, denn da müßte man nur diese paar Panels prüfen)
- also via WinAPI alle ChildControls in den entsprechenden Komponenten (Fenster, Panels usw.) suchen, diese mit den Handles der VCL abgleichen >> übrig blieben dann nur die Fremdkomponenten
(sobkomponenten von Fremdkomponenten könnte man wohl erstmal ignorieren)
- dann eine temporäre (unsichtbare) Form erzeugen, darauf die Fremdkomponenten via MSDN-Library durchsuchenSetParent zwischenparken
- dabei die Verbindung von Handle der Fremdkomponente und der VCL-Komponente merken

> nun (un)docken

> nach dem (Un)Docking:
- jetzt die Fremdkomponenten wieder via MSDN-Library durchsuchenSetParent auf die neuen Windows-Controls (neues Handle zu den gemerkten VCL-Objekten) übergeben.
- eventuell Tempform löschen

(klingt schlimmer, als es ist :lol: )


Im Falle einer in ein Panel eingebundenen Form, könnte man sie auch mal kurzzeitig auf SetParent(..., nil) setzen und braucht womöglich keine Tempform.


Tja, wenn du alles/vieles über über die Pluginschnittstelle, als Weiterleitung zur Programminternen VCL, erzeugen ließest, dann würde die VCL alles kennen und nach dem Neuaufbau wäre nichts verschwunden. :stupid:

b1428727 27. Mai 2010 12:54

Re: Plugin-System fragen
 
Zitat:

Zitat von implementation
Ich habe sowas bisher immer so geregelt, dass ich ein paar Interface zu jedem Zweck gebastelt habe (z.B. eins für Dock-Fenster, eins für Label, usw.) + ein Factory-Interface deklariere und beim Start des Plug-Ins die Factory übergebe.
Delphi-Quellcode:
type
  IFactory = interface
    function CreateDockWindow: IDockWindow;
    ...
  end;
  IDockWindow = interface
    function GetCaption: string;
    procedure SetCaption(val: string);
    property Caption: string read GetCaption write SetCaption;
    ...
  end;

type
  TFactory = class(TInterfacedObject, IFactory)
    ...
  end;
  TDockWindow = class(TInterfacedObject, IDockWindow)
    ...
  end;
Die Interfaces kann dann jeder Plug-In-Entwickler in seiner Sprache deklarieren.
Außerdem können die Plug-Ins schön klein bleiben, da ein Delphi-PlugIn dann z.B. keine VCL braucht, ein VC++-PlugIn keine MFC/WTL usw.


zu dieser methode hätte ich noch zwei fragen:

1. gibt es da keine probleme mit der freigabe?
ich kann doch kein DockWindow erzeugen, ein interface darauf an die dll geben und das DockWindow
schliessen ohne dass es in der DLL dann zu problemen kommt? was ich meine: die dll hat das interface
IDockWindow noch, obwohl das Formular bereits geschlossen/zerstört wurde...
wie geht man damit um?

2. wie funktioniert das mit events bei dieser methode? z.b. OnClick, OnChange, etc...

Gibt es dafür ein Interface welches z.B. so aussieht:
Delphi-Quellcode:
IEinInterface = interface
  procedure SetOnChange(OnChangeIntf: IOnChangeEvent);
  property OnChange: IOnNotifyEvent write SetOnChange;
end;

IOnChangeEvent = interface
  procedure OnChangeEvent(Sender: IObject);
end;
das plugin erstellt dann eine klasse TOnChangeEvent und setzt dies über IEinInterface.SetOnChange(MyOnChangeEvent)?

gibt es da eine elegantere lösung?

himitsu 27. Mai 2010 13:16

Re: Plugin-System fragen
 
Das Objekt hinter dem Interface IDockWindow muß Owner des Fensters sein.

- entweder erst wenn das Objekt gelöscht wird, wird auch die Form gelöscht
(wird das Formular geschlossen, wird dieses nur unsichtbar gemacht)

- oder das Formular wird freigegeben, aber IDockWindow reagiert dann entsprechend, wenn man doch noch versucht drauf zuzugreifen
(anfragen ignoreren, diese nur intern verwalten oder einen "Fehler" auslösen)



2. entweder man registriert bei IDockWindow die entsprechenden Methoden/Callbackfunktionen
(wie in deinem Beispliel)
oder man läßt sich vom Plugin passend zu den "Komponenten" ein Event-Interface übergeben.

Delphi-Quellcode:
IEvent = interface
  procedure OnEnterEvent(Sender: IObject);
  procedure OnExitEvent(Sender: IObject);
  procedure OnClickEvent(Sender: IObject);
  procedure OnDblClickEvent(Sender: IObject);
end;

IEdit = interface(IObject)
  procedure SetOnChange(OnChangeIntf: IOnChangeEvent);
  property OnChange: IOnNotifyEvent write SetOnChange;
end;

IFactory = interface
  function CreateEdit(pos: TRect; events: IEvent): IObject{IEdit};
end;

Es gibt da tausende Möglichkeiten.

hanspeter 27. Mai 2010 13:32

Re: Plugin-System fragen
 
Bei dll und Interface gibt es aber noch eine kleine Falle.
Eine Reihe Komponenten von Delphi registrieren sich bei Windows mit "Registerclass".
So eine Komponente kann auch bei Interfaces nicht in 2 Modulen gleichzeitig verwendet werden.
Das jeweils später nachgeladene Modul bringt dann einen Registerclass - Fehler.

Konkretes Beispiel Fastreport.
Fastreport im Hauptprogramm verwendet -> kein Plugin auf dll Basis kann Fastreport verwenden.

Fastreport in A.dll und B.dll.
Jede dll kann verwendet werden. Wird a und b geladen kommt es zum Programmabsturz.

Plugin als Comserver/ActiveX haben das Problem nicht.

Gruß
Peter

b1428727 27. Mai 2010 13:44

Re: Plugin-System fragen
 
Vielen Dank für die Info's!

Werde ein Test-Projekt damit starten um zu sehen wie es so läuft.


Alle Zeitangaben in WEZ +1. Es ist jetzt 07:42 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz