Autor Beitrag
henni
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 48

Win 7
Delphi 5 Standart, C# (Visual Studio 2008 Express Edition)
BeitragVerfasst: So 19.07.09 23:38 
Hallo!

In diesem Thread stelle ich euch das

Plugin-System V. 3.1.0

vor, und ich muss sagen, dass es mir sehr viel Denkarbeit gekostet hat.
Und Denkarbeit ist schwierig - darum hat das Denken letztendlich mehrere Wochen gebraucht, das implementieren dann aber nur 2 Tage.

Crosspost bei Delphi-Treff
Crosspost bei Delphi-PRAXIS

Ach ja: zwischendurch gab es auch das Plugin-System Version 2.
Bei dieser Version hat mir die Interface-Referenzzählung aber einen gewaltigen Strich durch die Rechnung gezogen, darum habe ich es verworfen.
Das Plugin-System Version 1 findet ihr bei Delphi-Treff, ich werde es aber hier nicht verlinken, da es veraltet ist und ich es nicht mehr unterstütze.

Allgemeine Informationen
Entwickler: Henning Dieterichs
Lizenz: Dieses System kann frei verwendet werden, ich würde mich aber darüber freuen, wenn ich bei Benutzung von diesem Plugin-System namentlich erwähnt werde!
Getestetet mit folgender Umgebung: Windows XP, Delphi 7 (mit früheren Version nicht getestet!).
Benötigte Fremdkomponenten: Keine.

WICHTIG:
Bei Unklarheiten bitte sofort Fragen - egal wie dumm die Fragen sind!


Download
Ganz kurz vorweg: Download gibts hier (mit 9 Demos).
Größe ca. 100 KiB.

Hier gibts das ganze mit bereits kompilierten DLLs und EXEn.
Größe ca. 3,5 MiB.

Alle benötigten Dateien sind jeweils im Archiv enthalten.

Wichtigste Features (Insider-Wissen)

  • Client <-> Host und Client <-> Client Interaktion möglich
  • Sprachunabhängig
  • Objekt-Export
  • Vererbung, Überschreibung exportierter Objekte
  • Klassen, Klassen-Methoden
  • Flexible Plugin-Quelle durch Plugin-Packages (z.B. aus DLLs)


Was macht dieses Plugin-System?
Dieses Plugin-System ist dazu dar, ein Programm zu schreiben, welches nachher beliebig erweitert werden kann.
Dabei können vorhandene Module überschrieben, erweitert und verbessert werden, ohne das an ihnen etwas verändert werden muss.

Für wen ist dieses Plugin-System geeignet?
Im Grunde genommen für jeden, der es sich zutraut, sich mit den Interfaces von Delphi rumzuschlagen - der Einstieg ist sehr kompliziert, das Ergebnis dafür aber um so besser.
Dieses Plugin-System kann für kleinere Programme als auch für größere verwendet werden - auch wenn das System nicht ganz ausgenutzt wird.
Dadurch können fremde Programme durch andere Entwickler spielend leicht verbessert oder nach ihren Wünschen angepasst werden.
So kann es beispielsweise ein Plugin geben, welches einem Programm ein Tray-Icon hinzufügt - dabei spielt es letzendlich keine Rolle, um welches Programm es sich handelt, solange es mit dem Plugin-System ausgestattet ist.

Wie kann das funktionieren?
Ganz einfach - über Interfaces.
Die gesamte Kommunikation innerhalb des Plugin-Systems baut nur auf Interfaces auf, weshalb das gesamte System sogar Programmiersprachen-Unabhängig ist.

Allerdings besitzen die Interfaces von Delphi eine sehr unangenehme Eigenschaft: die Referenzzählung.
Warum die so blöd ist, kann hier und hier nachgelesen werden.
Das Problem habe ich letztendlich mit Pointer auf Interfaces in den Griff bekommen - bei ihnen ignoriert Delphi die Referenzzählung.
Allerdings muss dazu einiges beachtet werden:
Die PInterfaces (Pointer auf Interfaces) dürfen nicht (bzw. wenn, dann nur, wenn man weiß, was man tut) dereferenziert werden.
Wenn ein PInterface in ein anderes gewandelt werden soll, kann die Klasse TIntf dazu benutzt werden - sie verwaltet das dann.

Aufbau des Plugin-Systems


Begriffe
Damit die Erklärung einfacher wird, habe ich mir einige Begriffe einfallen lassen, bzw. sie mit einer Bedeutung belegt:

Plugin: Das Plugin ist die kleinste Einheit: es stellt ein Objekt bzw. seine Klasse dar
Package: Ein Package ist eine Ansammlung von Plugins
Host: Der Host ist das Modul, das die Packages verwaltet.
Client: Der Client ist das Gegenstück und stellt ein Package dar, die Multiplizität zum Host beträgt N:1
Library: Der Host verwaltet alle Packages in einer gemeinsamen Library (= Bücherei)

Units
Das Plugin-System besteht hauptsächlich aus 7 Units:
plgHeader7 (die wichtigste Unit)
plgCore (enthält allgemeine Klasse)
plgLibrary (für den Host)
plgPackage (für den Client)
plgPackageSysUtils (Nützliche Klassen für den Client)
plgInterfaces
plgInterfaceImpl

Client (als DLL)
- Erstellen eines Plugins

Erst ein Plugin enthält ausführbaren Code und ist somit das wichtigste Element in diesem System.

-- Festlegen des Interfaces
Zuerst muss das Interface festgelegt werden, welches das Plugin implementiert. Jedes Interface muss eine GUID besitzen.
Ein Plugin kann auch mehrere Interfaces implementieren.

Beispiel:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
IDemo = interface
  ['{AD1D916F-6AD4-4221-BBCC-1960A30110DB}']
  procedure WriteSth;
end;


-- Implementieren des Interfaces
Nachdem die zu implementierenden Interfaces festgelegt wurden, können sie von einem oder mehreren Plugins implementiert werden.
Für jedes Plugin wird dazu eine neue Klasse erstellt, die von der Klasse TBasePlugin und dem Interface erbt.

Beispiel:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
TDemo = class(TBasePlugin, IDemo)
public
  procedure WriteSth;
end;
{ TDemo }
procedure TDemo.WriteSth;
begin
  WriteLn('Hello World!');
end;

Das erste Plugin ist fertig - jetzt muss es nur noch in das Package eingebunden werden.

- Zusammenstellung des Packages
-- Einbinden der Package-Unit
Damit das Package benutzt werden kann, muss erstmal die Unit plgPackage eingebunden werden.
Diese Unit verwaltet ein Package-Objekt und exportiert automatisch eine Funktion, die das Package-Objekt exportiert.

Beispiel:
ausblenden Delphi-Quelltext
1:
2:
uses
  [...], plgPackage, [...];

-- Konfigurieren des Packages
Der Host sollte wissen, mit welchem Package er es zu tun hat.
Es hängt aber auch nur vom Host ab, ob er unkonfigurierte Clients zulässt.

Es ist aber trotzdem immer besser, ein Package mit einer Version, Reversion und einer eindeutigen GUID zu versehen, damit es identifiziert werden kann.
Außerdem sollte auch der Autor angegeben werden.

Beispiel:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
  PluginPackage.Version := 1;
  PluginPackage.Reversion := 0;
  PluginPackage.Author := 'Henning';
  PluginPackage.GUID := StringToGUID('{65FE93FD-3E7C-464F-9A95-1B66EEE3557C}');

Hinweis: eine eindeutige GUID kann in Delphi mit der Tastenkombination Strg+Shift+G erzeugt werden.

-- Befüllen des Packages mit Plugins
Anschließend kann das Package mit Plugins befüllt werden.
Dazu wird zu dem Plugin eine Plugin-Klasse erzeugt, die die Informationen zu dem Plugin bereithält.
Diese sind einmal der Namespace und Name des Plugins.
Der Namespace bestimmt die Gültigkeit des Namens - zwei Plugins mit selben Namen aber unterschiedlichen Namespaces gehören nicht zusammen.
Der Namespace verringert also die Gefahr von unbeabsichtigten Namenskonflikten.
Dann muss jedem Plugin ebenfalls eine eindeutige GUID zugeordnet werden, sodass es innerhalb des Plugin-Systems identifizierbar bleibt.
Der Parameter Data (der letzte Parameter, im unten stehendem Beispiel nicht angegeben) ist optional und kann weggelassen werden.
Beispiel:
ausblenden Delphi-Quelltext
1:
  PluginPackage.AddPluginClass(TCustomPluginClass.Create(TDemo, 'demo''demo1', StringToGUID('{11139406-15BF-4769-87B6-5195A0AC6020}')));					

Hinweis: es können beliebig viele Plugins zu einem Package zusammengefasst werden.

- Fertig! Der Client ist jetzt eingerichtet!
Die DLL kann jetzt vom Host geladen werden.

Host
- Festlegen der Interfaces
Damit der Host die Plugins bedienen kann, müssen ihm die implementierten Interfaces bekannt sein.

- Erzeugen der PluginLibrary
Damit der Host PluginPackages laden kann, benötigt er erstmal eine PluginLibrary.
Diese ist in der Unit plgLibrary enthalten und muss manuell erzeugt und am Ende wieder freigegeben werden.

Beispiel:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
uses
  [...], plgLibrary, [...];
[...]
var
  PluginLib: TPluginLibrary;
begin
  PluginLib := TPluginLibrary.Create;
  try
    [...]
  finally
    PluginLib .Free;
  end;
end;

- Einbinden der Packages
Schon jetzt können die Packages der Clients eingebunden werden.

Beispiel:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
[...]
try
  PluginLib.AddPackage(TDLLLibPlgPackage.Create('projClient.dll', PluginLib));
finally
[...]

Dabei wird eine Klasse erzeugt, die das Package aus der DLL wrappt.
Auf diese Weise ist es auch Möglich, die Packages aus anderen Quellen zu beziehen (weiteres in den Demos).

- Benutzung der darin enthaltenen Plugins
Jetzt geht es los - die Plugin-Klasse kann herausgesucht und erzeugt werden! Dabei kommen jetzt die PInterfaces ins Spiel, also Vorsicht!

Beispiel:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
var
  DemoObj : TIntf;
[...]
  DemoObj := TIntf.ApplyPIntf(PluginLib.PlgClasses['demo''demo1'].CreatePlugin([]));
[...]

Um jetzt das Interface aus diesem DemoObj zu erhalten muss erstmal eine weitere Variable angelegt werden.

Beispiel:
ausblenden Delphi-Quelltext
1:
2:
3:
var
  PIDemoIntf: ^IDemo; //Pointer auf das Interface IDemo
[...]

Über DemoObj kann diese Variable befüllt werden:
ausblenden Delphi-Quelltext
1:
2:
3:
  [...]
  DemoObj.GetPIntf(IDemo, PIDemoIntf);
  [...]

Jetzt kann die Funktion WriteSth aufgerufen werden:
ausblenden Delphi-Quelltext
1:
2:
3:
  [...]
  PIDemoIntf.WriteSth;
  [...]

Und zum Schluss darf nicht vergessen werden, das Demo-Plugin wieder freizugeben:
ausblenden Delphi-Quelltext
1:
2:
3:
  [...]
  DemoObj.Free;
  [...]

Fertig! Das erste Plugin-System wurde benutzt und kann jetzt auch mit viel komplexeren Plugins bestückt werden! (siehe Demos)


Wie am Anfang gesagt:
Es ist ganz wichtig, das ihr, falls ihr Fragen habt, fragt!
Also kurz gesagt:
Bei Fragen: fragen!

In den Demos wird auch noch vieles klarer und verständlicher.
Sie sind nach ihrem Schwierigkeitsgrad geordnet und die letzten beiden enthalten nochmal (fast) alles zusammen.


Zuletzt bearbeitet von henni am Di 21.07.09 21:45, insgesamt 3-mal bearbeitet
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Mo 20.07.09 09:52 
Kannst Du neben CRC32 bitte MD5\SHA oder GnuPG-Signaturen angeben? CRC kollidiert zu leicht ;-)

Wie hängt das zusammen, dass in deinem Beispiel überall ne andere GUID auftaucht? Was gibt welche an?

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
henni Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 48

Win 7
Delphi 5 Standart, C# (Visual Studio 2008 Express Edition)
BeitragVerfasst: Mo 20.07.09 10:55 
Danke, dass du dir das angeguckt hast!

Zitat:
Kannst Du neben CRC32 bitte MD5\SHA oder GnuPG-Signaturen angeben? CRC kollidiert zu leicht ;-)

GnuPG wird schwierig, ansonsten kein Problem ;) :
Plugin System 3.zip: MD5: B13982F960C06341BD74B3BFCB87F71C und SHA-1: 4D205EA099BC5D63197CD2B58FA158F044178942
Plugin System 3 Exe.zip: MD5: FDC7F3A4A7B8CC25F2FCE006653D16F1 und SHA-1: C585C1330D2660735EAAF6233172F92D222CD07D

Zitat:
Wie hängt das zusammen, dass in deinem Beispiel überall ne andere GUID auftaucht?

Über eine GUID kann in dem Plugin-System jedes Objekt eindeutig identifiziert werden.
Wenn es also Objekte mit unterschiedlichen Aufgaben gibt, sollten die also eine unterschiedliche GUID haben.
So können z.B. Fehler schneller gemeldet, oder konkrete Abhängigkeiten erstellt werden.

Zitat:
Was gibt welche an?

In den Demos noch gar nichts.
Sie halten aber Möglichkeiten offen - und genau dazu gibt es ja dieses Plugin-System ;)
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Mo 20.07.09 11:34 
Dass eine GUID ein Globally Unique Identifier ist, weiß ich. Meinte das so, ob die im Interface verwendeten GUIDs durch das Pluginsystem ausgewertet werden für irgendwelche Zwecke. Oder erfolgt die Erzeugung\Instantiierung allein über die registrierten Namen bei den registerPlugin-Aufrufen. Das kam mir oben etwas kurz rüber.

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
henni Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 48

Win 7
Delphi 5 Standart, C# (Visual Studio 2008 Express Edition)
BeitragVerfasst: Mo 20.07.09 14:09 
Zitat:
Meinte das so, ob die im Interface verwendeten GUIDs durch das Pluginsystem ausgewertet werden für irgendwelche Zwecke.

Jedes Plugin sollte unabhängig der implementierten Interfaces eine eigene GUID haben, weil es durch die implementierten Interfaces nicht eindeutig identifizierbar ist.

Beispiel:
Es gibt ein Interface IGUIPlugin und zwei Plugins, die dieses Interface implementieren - von der äußerlichen Funkionalität sind die beiden Plugins also gleich.
Damit sie aber voneinander unterschieden werden können, benötigen sie eine davon unabhängige GUID.

Beim Laden eines Packages können dann alle Plugins erzeugt werden, die IGUIPlugin implementieren.

Dabei fällt mir gerade ein: der letze Parameter, der angibt, welches Interface das Plugin implementiert, ist unwichtig, da der ja über die Klasse ermittelt werden kann...
Demnächst wirds also ein Update geben ;)
HelgeLange
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 735
Erhaltene Danke: 6

Windows 7
Delphi7 - Delphi XE
BeitragVerfasst: Mo 20.07.09 17:23 
Süss :)
Die nächste Aufgabe sollte dann für Dich sein, das ganze in Komponenten zusammenzufassen, gerade damit sich ein Programmierer nicht mit den ganzen Interfaces rumschlagen muss. Dann musst Du auch mal schaun, inwieweit das ganze als Blackbox-System laufen kann, da ein Plugin-System meiner Meinung nach nur so funktionieren darf, andererseits wären es nur ausgelagerte und Austauschbare Funktionen. Beim drüberschaun von Deinem Code kam mir so das Gefühl, dass die sich irgendwie kennen müssen, um sich zu initialisieren und aufgerufen zu werden. Kann allerdings auch trügerisch sein, dieser Eindruck von mir. Vielleicht kannst Du mir es ja verständlich machen, falls ich falsch liegen sollte. :)

Du sagst auch, dass man Funktionen überschreiben kann indem man neue Plugins bildet, Beispiel ist dieser primzahl test, wenn ich das richtig sah. Wie entscheidet Dein plugin-System, welches der bessere/neuere Test ist? Wird dieser automatisch genutzt oder wird es durch das laden des neueren Modules bestimmt, was Dein Hauptprogramm anstösst ?

_________________
"Ich bin bekannt für meine Ironie. Aber auf den Gedanken, im Hafen von New York eine Freiheitsstatue zu errichten, wäre selbst ich nicht gekommen." - George Bernhard Shaw
henni Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 48

Win 7
Delphi 5 Standart, C# (Visual Studio 2008 Express Edition)
BeitragVerfasst: Mo 20.07.09 20:57 
Zitat:
Süss :)

Danke ;)

Zitat:
Die nächste Aufgabe sollte dann für Dich sein, das ganze in Komponenten zusammenzufassen, gerade damit sich ein Programmierer nicht mit den ganzen Interfaces rumschlagen muss.

Das werde ich erst ganz zum Schluss in Angriff nehmen (wenn nur noch sehr wenig Fehler drin sind (ja, ich bin ein Optimist ;) )) - und um Interfaces kommt man nicht herum.

Zitat:
Dann musst Du auch mal schaun, inwieweit das ganze als Blackbox-System laufen kann

Was meinst du genau mit Blackbox?
Die Anwendung, die das Plugin-System benutzt bestimmt die Flexibilität des Programmes.
Du könntest z.B. alle Plugins, die im Namespace "create" sind, automatisch erzeugen, oder alle Plugins, die im Namespace "forms" sind, mit bestimmten Parametern erzeugen und z.B: für das Plugin extra ein TabSheet hinzufügen (siehe Demo 7).
Wenn halt sehr viel über das Plugin-System läuft, lässt sich sehr schnell interner Code mit neuerem austauschen bzw. erweitern.
Es darf aber auch nicht zu flexibel sein - es soll schließlich nicht alles änderbar sein (z.B. wäre das ja bescheuert, wenn mit einem Plugin ein Aktivierungsprozess ausgehebelt werden kann).
Zitat:

Beim drüberschaun von Deinem Code kam mir so das Gefühl, dass die sich irgendwie kennen müssen

Ja und nein: das bestimmt der Entwickler eines Plugins.
Natürlich muss das Plugin die Interfaces der Plugins kennen, die es benutzt.
Und natürlich muss die Anwendung die Interfaces der Plugins kennen, damit sie sie erzeugen kann.
Die Interfaces können aber auch sehr allgemein gehalten werden, so können Richtlinien an die Entwicklung eines Plugins gestellt werden.

Du als Programmierer kannst so frei festlegen, inwiefern deine Anwendung manipulierbar/erweiterbar sein soll/darf!

Zitat:
andererseits wären es nur ausgelagerte und Austauschbare Funktionen

Dazu kann mein Plugin-System natürlich auch benutzt werden.

Zitat:
Du sagst auch, dass man Funktionen überschreiben kann indem man neue Plugins bildet, Beispiel ist dieser primzahl test, wenn ich das richtig sah

Richtig.

Zitat:
oder wird es durch das laden des neueren Modules bestimmt, was Dein Hauptprogramm anstösst ?

Die Lade-Reihenfolge der Packages spielt eine sehr große Rolle.

Wenn es z.B. zwei Plugins gibt, die eine von der Anwendung bereitgestellte Schnittstelle implementieren sollen (z.B. ein Benachrichtigungs-Modul), woher soll das Plugin-System dann wissen, welches Plugin letztendlich genommen werden soll?
Mein Plugin-System benutzt dazu die Reihenfolge, in der die Packages geladen wurden - das letze, also das neuste, überschreibt die älteren.

Wenn jetzt ein Plugin durch ein neues überschrieben werden soll, hat das neue die Möglichkeit, bestimmte Methodenaufrufe an das überschriebene (Ancestor) zu delegieren.
So können mehrere Plugins hierarchisch zusammengefasst werden.

Weiteres dazu gibt es in der Demo 6 bzw. Demo 7. Falls die Dokumentation der Demos schlecht ist, oder ihr ein anderes bzw. weiteres Demo haben wollt, um zu sehen, wie flexibel (das soll bitte nicht als Angeben betrachtet werden!) das System ist, sagt es mir einfach. Ich werde dann gucken, was ich machen kann :)

Falls meine Antworten zu ungenau oder nicht aufschlussreich genug sind, bitte nachhacken!
Manchmal verstehe ich selbst nicht mehr, was ich da eigentlich geschrieben habe.

P.S: Demnächst wird es eine neue Version geben, die leider etwas inkompatibel mit dem alten ist :( (ich musste eine Funktion eines wichtigen Interfaces ändern)
Dafür aber etwas logischer ;)
HelgeLange
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 735
Erhaltene Danke: 6

Windows 7
Delphi7 - Delphi XE
BeitragVerfasst: Mo 20.07.09 21:25 
user profile iconhenni hat folgendes geschrieben Zum zitierten Posting springen:

Zitat:
Die nächste Aufgabe sollte dann für Dich sein, das ganze in Komponenten zusammenzufassen, gerade damit sich ein Programmierer nicht mit den ganzen Interfaces rumschlagen muss.

Das werde ich erst ganz zum Schluss in Angriff nehmen (wenn nur noch sehr wenig Fehler drin sind (ja, ich bin ein Optimist ;) )) - und um Interfaces kommt man nicht herum.


Komponenten bauen ist anders als "normalen" code zu schreiben, aus meiner Erfahrung heraus kostet es ungleich mehr Zeit. Aber ist natürlich Deine Sache :P

user profile iconhenni hat folgendes geschrieben Zum zitierten Posting springen:
Zitat:
Dann musst Du auch mal schaun, inwieweit das ganze als Blackbox-System laufen kann

Was meinst du genau mit Blackbox?


Ein System, wo keiner keinen kennt... Alles sind Blackboxen.

user profile iconhenni hat folgendes geschrieben Zum zitierten Posting springen:
Es darf aber auch nicht zu flexibel sein - es soll schließlich nicht alles änderbar sein (z.B. wäre das ja bescheuert, wenn mit einem Plugin ein Aktivierungsprozess ausgehebelt werden kann).


Warum nicht ? Vielleicht ist genau das ja gewollt ?

user profile iconhenni hat folgendes geschrieben Zum zitierten Posting springen:
Zitat:

Beim drüberschaun von Deinem Code kam mir so das Gefühl, dass die sich irgendwie kennen müssen

Ja und nein: das bestimmt der Entwickler eines Plugins.
Natürlich muss das Plugin die Interfaces der Plugins kennen, die es benutzt.
Und natürlich muss die Anwendung die Interfaces der Plugins kennen, damit sie sie erzeugen kann.
Die Interfaces können aber auch sehr allgemein gehalten werden, so können Richtlinien an die Entwicklung eines Plugins gestellt werden.


Warum ? Wie kannst Du denn ein Plugin kennen was erst in einem jahr geschrieben wird ?

user profile iconhenni hat folgendes geschrieben Zum zitierten Posting springen:
Zitat:
andererseits wären es nur ausgelagerte und Austauschbare Funktionen

Dazu kann mein Plugin-System natürlich auch benutzt werden.


Was ich meinte ist, dass es mir vorkommt, als könne es genau nur das.

_________________
"Ich bin bekannt für meine Ironie. Aber auf den Gedanken, im Hafen von New York eine Freiheitsstatue zu errichten, wäre selbst ich nicht gekommen." - George Bernhard Shaw
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Mo 20.07.09 21:33 
Die Einschränkung bei deinem System liegt, wenn ich das richtig sehe, ein wenig darin, dass du in deinem System nur Funktionalität erweitern kannst, für die eine explizite Schnittstelle in der Hauptanwendung oder durch ein Plugin vorgesehen ist. Was somit nicht ohne weiteres geht, ist einfach nur Teile einer bestimmten Funktionalität bereitzustellen oder zu ersetzen.

Schau Dir einmal von user profile iconHelgeLange seine ERP-Komponenten an. Die arbeiten mit Hooks zum Erweitern der Funktionalität, was im Extremstfall soweit geht, dass man ein blankes Mainform haben kann, wo die eigentliche Anwendung nur noch ein Plugin ist, welches seinerseits von Plugins erweitert werden kann.

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
henni Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 48

Win 7
Delphi 5 Standart, C# (Visual Studio 2008 Express Edition)
BeitragVerfasst: Mo 20.07.09 22:43 
Zitat:
Warum nicht ? Vielleicht ist genau das ja gewollt ?

Wie - bei dir ist es gewollt, dass der Anwender ein Plugin schreiben kann, dass deinen Software-Aktivierungsprozess umgeht?? :)
Der Anwender könnte vielleicht sowas wollen, aber du würdest daran dann wenig verdienen ;)

Wie gesagt: die Flexibilität wird durch die Anwendung und Integrierung in das Programm bestimmt.
Du allein bestimmst, was erweiterbar sein soll, und was nicht.

Zitat:
Warum ? Wie kannst Du denn ein Plugin kennen was erst in einem jahr geschrieben wird ?

Doch, ich kenne es bereits. Ich garantiere dir, dass es das Interface IPlugin implementieren wird ;)
Es hängt dann nur von dem Programm ab, ob es benutzt wird.
Gegenfrage: wie kann Delphi wissen, was du in einem Jahr programmieren wirst?

Guck dir mal Demo 7 an - Plugin2 muss Plugin1 nicht kennen, obwohl Plugin1 sich dazwischen hängt und Plugin2's Aufrufe logt.
Es ist möglich, die Anwendung zu erweitern, solange es die Richtlinen der Anwendung erlauben.
In Demo 7 ist es so, dass es einen Plugin-Typ gibt (IGUIPlugin), der keine Spezifikationen erfordert.
Allerdings werden solchen Plugins automatisch ein Handle eines TabSheets bereitgestellt, in dem sie ihr Formular anzeigen können.
Es wäre aber auch möglich, ein TabSheet über ein von der Anwendung bereitgestelltes Objekt anzufordern.
Allerdings könnten dann einige Plugins Unsinn treiben.

Zitat:
Ein System, wo keiner keinen kennt...

Um obiges Beispiel aufzugreifen: Wie willst du dann von der Hauptanwendung ein TabSheet anfordern, wenn du gar nicht weißt, wie bzw. ob es überhaupt möglich ist?
Klar, es kann geprüft werden, ob es möglich ist. Aber wenn diese Möglichkeit, TabSheets hinzuzufügen, gar nicht eingeräumt wurde?
Oder wie willst du die Überschrift eines Formulars ändern, wenn das Formular dies schlichtweg nicht unterstützt?

Prinzipiell könnte ich jetzt für Demo 7 ein Plugin schreiben, welches dem Programm ein Tray-Icon hinzufügt.
Ohne das Hauptprogramm anpassen zu müssen.
Prinzipiell könnte ich jetzt für Demo 7 ein Plugin schreiben, welches dem Programm eine Datei-Suchmaschine hinzufügt.
Ohne das Hauptprogramm anpassen zu müssen.
Oder einen Browser. Oder eine Hilfe. Oder einen Virus :twisted: ...
Alles, ohne dass das Hauptprogramm jetzt davon weiß.

Zitat:
für die eine explizite Schnittstelle in der Hauptanwendung oder durch ein Plugin vorgesehen ist.

Das kann aber auch genau als Vorteil benutzt werden: so können Richtlinien für Plugins gestellt werden.

Außerdem können die Schnittstellen so abstrakt gehalten werden, dass sie quasi keine Spezifikationen fordern.

Zitat:
Schau Dir einmal von HelgeLange seine ERP-Komponenten an.

Ja, werde ich mal machen. Schade das es nur eine Trail-Version ist!
Sein System basiert aber auf einer völlig anderen Idee.

P.S: Ich finde solche Diskussionen sehr gut, weil sie mich zwingen, mein Konzept zu überdenken!
Ich habe schon einige Ideen für eine neue Version gesammelt.
HelgeLange
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 735
Erhaltene Danke: 6

Windows 7
Delphi7 - Delphi XE
BeitragVerfasst: Mo 20.07.09 23:40 
user profile iconhenni hat folgendes geschrieben Zum zitierten Posting springen:
Zitat:
Warum nicht ? Vielleicht ist genau das ja gewollt ?

Wie - bei dir ist es gewollt, dass der Anwender ein Plugin schreiben kann, dass deinen Software-Aktivierungsprozess umgeht?? :)
Der Anwender könnte vielleicht sowas wollen, aber du würdest daran dann wenig verdienen ;)

Wie gesagt: die Flexibilität wird durch die Anwendung und Integrierung in das Programm bestimmt.
Du allein bestimmst, was erweiterbar sein soll, und was nicht.


Ja, ich kann mir Situationen vorstellen, wo das sogar sehr erwünscht ist, vom Programmierer der Software. Stichwort : Rechteverwaltung. Normalerweise sieht man das ganze als Rechteverwaltung für Benutzer, aber warum soll es für Code-Funktionen keine Rechte geben ?

user profile iconhenni hat folgendes geschrieben Zum zitierten Posting springen:
Zitat:
Warum ? Wie kannst Du denn ein Plugin kennen was erst in einem jahr geschrieben wird ?

Doch, ich kenne es bereits. Ich garantiere dir, dass es das Interface IPlugin implementieren wird ;)
Es hängt dann nur von dem Programm ab, ob es benutzt wird.
Gegenfrage: wie kann Delphi wissen, was du in einem Jahr programmieren wirst?


Ich sage Dir, Du kennst es nicht. Ausser vielleicht, Du möchtest Deine Basis-System ständig erweitern. Deswegen sage ich ja : Blackbox-System.

user profile iconhenni hat folgendes geschrieben Zum zitierten Posting springen:
Allerdings werden solchen Plugins automatisch ein Handle eines TabSheets bereitgestellt, in dem sie ihr Formular anzeigen können.
Es wäre aber auch möglich, ein TabSheet über ein von der Anwendung bereitgestelltes Objekt anzufordern.
Allerdings könnten dann einige Plugins Unsinn treiben.


Ich sehe das von der anderen Seite bei Plugins. Nehmen wir mal Dein Beispiel des PageControls. Nicht das Fenster fordert ein tabsheet an, auf dem es sich anzeigen kann, sondern das PageControl fragt, wer sich gern hier anzeigen will und setzt dann die Fenster in die neu erzeugten TabSheets.

Ausserdem.. warum soll einem Plugin automatisch ein Tabsheet zur Verfügung gestellt werden ? Solche Generalisierungen sind nie gut, da es ja auch sein kann, dass das Plugin gern was anderes will.

IMHO der Ansatz für Plugins ist, dass das ganze System aus kleinen Funktions-Servern besteht, die der Anwendung Funktionalität zur Verfügung stellt. Dabei gibt es einen Rahmen (zum Bsp das Fenster der MainForm) und die Plugins können sich darin tummeln. EIn Plugin stellt zum Bsp. ein Hauptmenu zur Verfügung und eine Funktion um Menüpunkte hinzuzufügen. Ein anderes Modul baut eine StatusBar ins Hauptfenster und die Möglichkeit, dort den Status zu ändern, neue Bereiche einzufügen etc.
Das ganze dann von der Seite der Funktionsserver gesehen : Die Anforderung läuft ins Leere, wenn niemand das MainMenu zur Verfügung stellt. Aber das ist ok, weil der erste Programmierer, der das feststellt, schreibt sich halt die Funktion, um das Hauptmenü einzufügen.
Im Ganzen sind aber beide Bereiche getrennt (Menü selbst und die Menüpunkte) und können nach Lust und Laune ausgetauscht werden. Das mag Dir seltsam erscheinen aber es macht Sinn, wenn Du ein offenes System bieten willst. Was zum Bsp auch ohne Menu auskommt. Da brauchst Du keine 2 plugins zu schreiben (eins für das System mit Menü, das andere für die ohne Menü), sondern ihre Anforderung sich mit Ihrem Menüpunkt einzutragen läuft einfach in eine Leerfunktion sozusagen.

user profile iconhenni hat folgendes geschrieben Zum zitierten Posting springen:
Zitat:
Ein System, wo keiner keinen kennt...

Um obiges Beispiel aufzugreifen: Wie willst du dann von der Hauptanwendung ein TabSheet anfordern, wenn du gar nicht weißt, wie bzw. ob es überhaupt möglich ist?
Klar, es kann geprüft werden, ob es möglich ist. Aber wenn diese Möglichkeit, TabSheets hinzuzufügen, gar nicht eingeräumt wurde?
Oder wie willst du die Überschrift eines Formulars ändern, wenn das Formular dies schlichtweg nicht unterstützt?


Ist ja kein Fehler in einem Blackbox-System, eine Funktion aufzurufen, die nicht unterstüzt wird. Ist ja auch in Delphi kein Fehler eine solche Funktion aufzurufen :

ausblenden Delphi-Quelltext
1:
2:
3:
4:
procedure IchMacheNichts;
begin
  // zu faul...
end;



user profile iconhenni hat folgendes geschrieben Zum zitierten Posting springen:
Zitat:
für die eine explizite Schnittstelle in der Hauptanwendung oder durch ein Plugin vorgesehen ist.

Das kann aber auch genau als Vorteil benutzt werden: so können Richtlinien für Plugins gestellt werden.

Außerdem können die Schnittstellen so abstrakt gehalten werden, dass sie quasi keine Spezifikationen fordern.


Meiner Meinung nach ist gerade das offene System interesant. Plugins sind für Programmierer, nicht für Anwender. als Programmierer will ich keine Grenzen. Erlaubt ist, was funktioniert. Setzt man mir Grenzen bei dem was ich machen kann, kann ich vielelicht nicht umsetzen, was ich machen will, um das programm zu erweitern. Wo man wieder darauf zurückkommt, dass Du nicht wissen kannst, was für ein Plugin in einem Jahr programmiert wird.
Das optimale Plugin-System baut man einmal und ab dann läuft es. Klar wird es Erweiterungen im System selbst geben durch neue Ideen etc. So zum Beispiel eine Erweiterung, wo vor der Ausführung automatisch getestet wird, ob der augenblickliche Nutzer das Recht hat, diese Funktion auszuführen. Das kann man nur im Plugin-System selbst zentral machen. Aber alle anderen Erweiterungen können auch durch andere Plugins kommen.

user profile iconhenni hat folgendes geschrieben Zum zitierten Posting springen:
P.S: Ich finde solche Diskussionen sehr gut, weil sie mich zwingen, mein Konzept zu überdenken!
Ich habe schon einige Ideen für eine neue Version gesammelt.


Das ist gut.

_________________
"Ich bin bekannt für meine Ironie. Aber auf den Gedanken, im Hafen von New York eine Freiheitsstatue zu errichten, wäre selbst ich nicht gekommen." - George Bernhard Shaw
HelgeLange
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 735
Erhaltene Danke: 6

Windows 7
Delphi7 - Delphi XE
BeitragVerfasst: Mo 20.07.09 23:54 
user profile iconhenni hat folgendes geschrieben Zum zitierten Posting springen:
Zitat:
Schau Dir einmal von HelgeLange seine ERP-Komponenten an.

Ja, werde ich mal machen. Schade das es nur eine Trail-Version ist!
Sein System basiert aber auf einer völlig anderen Idee.


Ja, es ist eine ganz andere Idee, ein wirkliches Blackbox-System. Meine Hauptanwendung besteht aus 77 Zeilen Code (von "unit" bis runter zu "end." und 15 Zeilen davon habe ich selbst geschrieben. Jeglicher anderer Code wird von dem Modulen geliefert. Dait ist jedes GUI Element austauschbar, das Programm selbst hat keine Festlegung, selbst die Datenbank-Anbindung kann ausgetauscht werden, so dass das programm statt mit einer Firebird-DB lieber mit MS SQL arbeitet. Oder Oracle. oder was auch immer. Den Modulen ist die DB egal, auch wenn sie sie benutzen. Man kann aus dem programm mit entsprechenden Modulen ein MS Word nachbasteln oder ein Miranda (Multi-Protocol-Chat-Client) oder eine Finanz-Software.

Ausserrdem ist es halt möglich, den vorhandenen Code zu erweitern, ohne das Module (die Module) anzufassen. Funktionen können sich in vorhandenen Code "einklinken".

Bsp.: Du hast ein Fehler-Log Modul welches die Fehler aus allen modul automatisch in einer Datei loggt. Jetzt willst Du aber auch, dass diese zusätzlich an den Server Deiner Firma senden, damit Du siehst, was für Fehler so auftreten (Stichwort Crash-Report Mozilla Firefox). Jetzt gehst Du nicht mehr in das Modul rein, welches den Report an deine Logger sendet oder gar in den logger, um dort das versenden reinzuschreiben, sondern das schreibst Du als Modul und klinkst Dich in die Logger funktion ein, keine Zeile Code im vorhandenen muss geändert werden dazu, aber die neue Funktion mit dem Versenden wird aufgerufen. Noch einen Schritt weiter gedacht, jetzt willst Du auf dem Rechner eine mini-DB laufen lassen, damit du siehst, wieoft welcher Fehler so auftritt. Und nur wenn der Fehler noch nicht bekannt ist, soll er an die Firma gesendet werden. Du brauchst dann also eine automatische Flusssteuerung, die entscheiden kann, ob eine "unter"-Funktion ausgeführt werden soll...

_________________
"Ich bin bekannt für meine Ironie. Aber auf den Gedanken, im Hafen von New York eine Freiheitsstatue zu errichten, wäre selbst ich nicht gekommen." - George Bernhard Shaw
henni Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 48

Win 7
Delphi 5 Standart, C# (Visual Studio 2008 Express Edition)
BeitragVerfasst: Di 21.07.09 21:49 
Es gibt eine neue Version: 3.1.0!

Changelog:


  • Ein Plugin kann jetzt mehrere Interfaces implementieren. Um zu prüfen, ob ein Plugin ein Interface unterstüzt, kann die Funktion "Supports" der Klasse TPluginClass benutzt werden.
  • LifeTimeTasks: Mithilfe dieser Klasse können (beim Client) Initialisierungs bzw. Finalisierungsaufgaben durchgeführt werden, wie z.B. das Setzten des Handles der Application. Näheres dazu in den Demos
  • Zwei neue Demos (eins über die LifeTimeTasks und das andere über eine Implementierung einer Factory-Class)
  • Hinzufügung aller erforderlichen Units


Leider ist das neue Pluginsystem inkompatibel mit dem alten - da aber niemand das neue benutzen konnte (aufgrund der fehlenden Units), ists quasi egal ;)


Zitat:
selbst die Datenbank-Anbindung kann ausgetauscht werden, so dass das programm statt mit einer Firebird-DB lieber mit MS SQL arbeitet.

Das ist bei meinem System aber ohne weiteres möglich.

Zitat:
EIn Plugin stellt zum Bsp. ein Hauptmenu zur Verfügung und eine Funktion um Menüpunkte hinzuzufügen. Ein anderes Modul baut eine StatusBar ins Hauptfenster und die Möglichkeit, dort den Status zu ändern, neue Bereiche einzufügen etc.

Und wie machst du das ohne die VCL? Oder arbeitest du mit Laufzeitpackages?
Ansonsten müsste man NonVCL programmieren, und dann ist es mit meinem System auch möglich, die GUI beliebig zu erweitern.
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Di 21.07.09 22:50 
Um die VCL über DLL-Grenzen hinweg nutzen zu können, bedarf es nicht wirklich irgendwelcher Laufzeit-Packages, auch wenn die Nutzung der Packages RTL und VCL das Leben stark vereinfacht.

Und selbst dann gibt es immer noch die Möglichkeit, über eine Reihe kleinerer Tricks da bestimmte Funktionalitäten von Delphi auszutauschen ...

Und wo wir grad beim Austauschen sind: Helge's System erlaubt u.a. auch folgendes: Angenommen, du hast eine komplexe Berechnung, in der ein Fehler ist. Aus QA-Gründen darfst Du beim Kunden das zertifizierte Modul nicht anfassen, musst dem Kunden aber trotzdem einen Bugfix liefern. Bei Helge kannst Du dazu einfach sagen, dass du in einem neuen Modul allein die fehlerhafte Funktion korrigiert neu baust und dann dem System bescheid gibst, dass diese Funktion die alte Version ersetzt.

Aber den Spruch
user profile iconhenni hat folgendes geschrieben Zum zitierten Posting springen:
Leider ist das neue Pluginsystem inkompatibel mit dem alten - da aber niemand das neue benutzen konnte (aufgrund der fehlenden Units), ists quasi egal ;)

werd ich mir einrahmen ;-)

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
henni Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 48

Win 7
Delphi 5 Standart, C# (Visual Studio 2008 Express Edition)
BeitragVerfasst: Di 21.07.09 23:11 
Zitat:
Und wo wir grad beim Austauschen sind: Helge's System erlaubt u.a. auch folgendes: Angenommen, du hast eine komplexe Berechnung, in der ein Fehler ist. Aus QA-Gründen darfst Du beim Kunden das zertifizierte Modul nicht anfassen, musst dem Kunden aber trotzdem einen Bugfix liefern. Bei Helge kannst Du dazu einfach sagen, dass du in einem neuen Modul allein die fehlerhafte Funktion korrigiert neu baust und dann dem System bescheid gibst, dass diese Funktion die alte Version ersetzt.

Das ist bei meinem System aber auch möglich: durch Vererbung bzw. Überschreibung.
Alle Methoden, die nicht verändert werden sollen, werden einfach an das ursprüngliche Plugin delegiert.
Es können sogar Objekte überschrieben werden! (siehe letze Demo)

Auf Plugins wird normalerweise nur über Namspace + Name zugegriffen. Gibts ein anderes Plugin im selben Namespace mit selben Namen, so wird das alte überschrieben.
Das neue kennt das alte aber (das geschieht automatisch) und kann entweder die gesamte Funktionalität überschreiben, oder einfach an das alte delegieren.

(Siehe Demo Vererbung, mit dem Primzahl-Test: der ineffiziente Algorithmus wurde durch einen besseren ersetzt)

Viele Grüße,
Henning
HelgeLange
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 735
Erhaltene Danke: 6

Windows 7
Delphi7 - Delphi XE
BeitragVerfasst: Mi 22.07.09 17:07 
user profile iconhenni hat folgendes geschrieben Zum zitierten Posting springen:

Zitat:
EIn Plugin stellt zum Bsp. ein Hauptmenu zur Verfügung und eine Funktion um Menüpunkte hinzuzufügen. Ein anderes Modul baut eine StatusBar ins Hauptfenster und die Möglichkeit, dort den Status zu ändern, neue Bereiche einzufügen etc.

Und wie machst du das ohne die VCL? Oder arbeitest du mit Laufzeitpackages?
Ansonsten müsste man NonVCL programmieren, und dann ist es mit meinem System auch möglich, die GUI beliebig zu erweitern.


Du musst nicht NonVCL programmieren, um dies zu machen.
Als Beispiel, mein Hauptprogramm ist ja nichts weiter als ein Loader, da es selbst keine Funktionen für den user anbietet, sondern nur ein Fenster und eine Start-Komponente, die das Blackbox-System initialisiert. Dieses liegt in einem sogenannten ManagerModul, welches ungleich den normalen Modulen schon vom Hauptprogramm initialisiert werden (da sie die Basis-Funktionen des ERP Frameworks zur Verfügung stellen). Eines der ManagerModule beinhaltet eine Komponente namens TERPHookmanager, welches eine Dynamische Funktionstabelle hat mit allen im System vorhandenen (von Modulen exportierten) Funktionen.
Nachdem also diese ManagerModule geladen worden, ist das Basis-System initialisiert und das Hauptprogramm hat ein leeres (noch unsichtbares) Fenster. Jetzt rufe ich den Initialisierungs-Hook auf, an welches sich Funktionen anmelden können, die sich gern an dieser Stelle initialisieren möchten. Dazu gehören zum Bsp. eine Funktion, die nichts anderes tut, als ein Hauptmenü für das Programm zu erzeugen und einen anderen Hook aufzurufen, der die Menüpunkte erzeugt. An diesen Hook melden sich alle Funktionen, die gern im HauptMenü stehen wollen. Das heisst, wenn ein neues Modul gern dort einen Eintrag haben will, dann hängt es sich einfach an den Hook und wartet, dass dieser aufgerufen wird und liefert dann dem Hauptmenüloader seine Daten. Naja, dazu gibt es jetzt einen ModuleController (eine Komponente), die das automatisiert machen kann, das heisst, Du musst keinen Code mehr schreiben, um solche Enumerierungsdaten zurüuckzuliefern. Aber egal :)
Nachdem also das hauptmenü erstellt wurde, wird die nächste angemeldete Funktion im Initialisierungs-Hook ausgefüuhrt. Die können im System machen, was sie wollen, hängen sich events an die Hauptform, ans Applications-Object etc., erstellen sich eine Statusbar und stellen einen Server zur verfügung, um auf dieser zu schreiben und und und...

Dann am Ende des Programms rufe ich ein De-Initialisierungs-Hook auf, der allen, die es wissen wollen, sagt, dass jetzt das Programm beendet wird. Der Fenstermanager kann daraufhin Fenster schliessen, das Hauptmenü kann freigegeben werden etc. Dabei kann der Programmierer natürlich bestimmen, in welcher Reihenfolge das geschehen soll, ohne eine Zeile Code zu schreiben und kann dies im nachhinein auf dem Rechner des Kunden auch ändern, wenn er das für nötig hält.

Zusätzlich habe ich mittlerweile etwas, das sich Codegroups nennt, das heisst, man kann Code aus verscheidenen Modulen in Gruppen zusammenfassen und für Nutzer/Nutzergruppen freigeben oder sperren. Jede einzelne Funktion aus einem Modul kann sich an eine vorhandene CodeGruppe dranhängen und wird damit Teil des Codes den bestimmte Nutzer ausführen können oder kann sich auch eine neue CodeGruppe erstellen, welche dann natürlich in der Rechte-Verwaltung auftaucht.
Hat ein Nutzer kein Recht, eine CodeGruppe auszuführen, dann existiert dieser Code nicht im System. Das ist ein grosser Vorteil gegenüber herkömmlichen Rechtesystemen in Programmen, da man sich im Programm nicht drum kümmern muss, ob "der das denn jetzt überhaupt darf". Der Loader der Dynamischen Funktiontablle stellt sicher, dass nur Funktionen geladen werden, auf die der augenblickliche Nutzer auch Zugriff hat, da der Rest nicht geladen ist, kann man auch nicht drauf zugreifen und selbst direkte Aufrufe führen ins Nichts (kein Crash, sondern macht nur nichts, da nichts da ist).


Ich habe mir mal angeschaut, was Borland/CodeGear/Embarcadero so treiben in der IDE selbst, wenn man die IOTA nutzen will. Ist ja from prinzip her dasgleiche was Du auch machst. Ich hoffe (als Teilzeit-IOTA-Programmierer) mal, dass Du das gut in komfortable Komponenten packen kannst (ich bezweifle es aber), denn arbeiten mit der IOTA ist "a pain in the ass". Und Du wirst an Grenzen stossen, wenn Du an einen Punkt kommst, wo Du das vielleicht kommerziell nutzen willst. Ich lese häufig, dass man Sachen bei der IDE über die IOTA nicht machen kann, weil man das nicht implementiert hat und man müsse dann wohl ein feature request stellen bei Embracadero (passiert immer dann, wenn man eine nicht-Source-version eines programmes rausgibt). Einer der Gründe für mich gewesen, einen komplett anderen Weg zu gehen.

Das soll im Gesamten keine Kritik sein, ich finde, Du hast Dir gut Gedanken gemacht und auch gut ausgeführt. Ich gebe Dir das alles nur als Anregung, da ich mich mit solchen modularen System seid mind. 10 Jahren beschäftige und mir in den 10 Jahren VIELE Gedanken gemacht habe (woraus ja auch mein System entstanden ist und es ist bei weitem noch nicht fertig)

_________________
"Ich bin bekannt für meine Ironie. Aber auf den Gedanken, im Hafen von New York eine Freiheitsstatue zu errichten, wäre selbst ich nicht gekommen." - George Bernhard Shaw
henni Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 48

Win 7
Delphi 5 Standart, C# (Visual Studio 2008 Express Edition)
BeitragVerfasst: Mi 22.07.09 17:50 
Vielen Dank für deine ausführlichen Antworten!!

Zitat:
Du musst nicht NonVCL programmieren, um dies zu machen.

Aber wie kommst du dann mit der RTTI klar, wenn du einem Formular außerhalb der DLL eine Komponente hinzufügen willst?

Zitat:
Zusätzlich habe ich mittlerweile etwas, das sich Codegroups nennt, das heisst, man kann Code aus verscheidenen Modulen in Gruppen zusammenfassen und für Nutzer/Nutzergruppen freigeben oder sperren.


Ich denke jetzt habe ich auf den größten Unterschied unserer Systeme erkannt: Deines ist für den Entwickler des Hauptprogrammes, meines für den Nutzer.
Meinem System wäre es schwachsinnig eine solche Funktion hinzuzufügen, da der Nutzer sich das Plugin selber programmiert hat ;)

Aber wie stellst du dann sicher, das jemand fremdes deine DLLs nicht ändert, um sich, wie bereits erwähnt, den Registrierungs- bzw. Aktivierungsprozess des Programmes zu schenken?

Zitat:
wo Du das vielleicht kommerziell nutzen willst.

Wo ich was kommerziell nutzen will? Das Plugin-System?
Das soll ja gerade offen sein - jeder soll meine Programme nach seinen Wünschen (natürlich meinen Richtlinien entsprechend) erweitern können!
Z.B. falls er ein Tray-Icon vermisst, oder mein Programm für sein System anpassen will.
Oder falls es Programme, die ich nicht mehr unterstützte, für neuere Betriebssysteme flott machen will.

Zitat:
seid mind. 10 Jahren

Oh, da war ich grad mal 5 Jahre alt :D

Zitat:
Das soll im Gesamten keine Kritik sein

Ich will und brauche aber Kritik, um dieses System zu verbessern.
Denn wenn ich es erstmal fertig gestellt habe, darf ich daran auch nichts mehr ändern...
Zitat:
ich finde, Du hast Dir gut Gedanken gemacht und auch gut ausgeführt.

Danke!
HelgeLange
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 735
Erhaltene Danke: 6

Windows 7
Delphi7 - Delphi XE
BeitragVerfasst: Mi 22.07.09 18:37 
user profile iconhenni hat folgendes geschrieben Zum zitierten Posting springen:
Zitat:
Du musst nicht NonVCL programmieren, um dies zu machen.

Aber wie kommst du dann mit der RTTI klar, wenn du einem Formular außerhalb der DLL eine Komponente hinzufügen willst?


hat ja die RTTI nix mit zu tun. VCL.bpl und RTL.bpl werden natürlich dynamisch gelinkt, dadurch hast du a) kleinere DLLs da der RTL/VCL-Code geshared wird und b) Zugriff auf die gleichen System-Variablen anstatt auf Kopien. Was ich auch oft nutze ist das VCL-Message-System, besonders dann, wenn ich verschiede Componenten in einem Wusch was erzählen will.

user profile iconhenni hat folgendes geschrieben Zum zitierten Posting springen:
Zitat:
Zusätzlich habe ich mittlerweile etwas, das sich Codegroups nennt, das heisst, man kann Code aus verscheidenen Modulen in Gruppen zusammenfassen und für Nutzer/Nutzergruppen freigeben oder sperren.


Ich denke jetzt habe ich auf den größten Unterschied unserer Systeme erkannt: Deines ist für den Entwickler des Hauptprogrammes, meines für den Nutzer.
Meinem System wäre es schwachsinnig eine solche Funktion hinzuzufügen, da der Nutzer sich das Plugin selber programmiert hat ;)


Plugin-Systeme werden in 2 Bereichen eingesetzt :

1.) Modulare kommerzielle Anwendungen, die es der Firma möglich machen, ohne viel Aufwand, speziell zugeschnittene Programme Ihren Kunden anbieten zu können.

2.) Kommerzielle/Nicht-Kommerzielle Programme, wo die Firma/Programmier-Community will, dass sich die Leute eigene Erweiterungen basteln können (Kommerziell z.B. Delphi, nicht-kommerziell z.B. Miranda)

Beide Systeme brauchen Programmierer um Erweiterungen zu bauen, da wir beide keine Scriptsprache anbieten (obwohl ich das mit einer Zeile Code so ändern könnte, dass alle meine Komponenten scriptbar sind, hab das nämlich schon gebaut).

Mein System funktioniert für den user, der sich eine Erweiterung bauen will so gut wie Dein System, wie gesagt, Plugin-Systeme sprechen ja eh Programmierer an. Für nicht-kommerzielle Zwecke wird es mit der Version 2.0 der ERP Framework Components auch frei zu nutzen sein. Heisst, wer gern ein Miranda mit Delphi bauen will, kann mein System dazu ohne Probleme nutzen. Und Erweiterungen können dann durchaus von einer Programmierr-Community bereitgestellt werden, obwohl etwas Koordinationsarbeit nötig sein wird (heisst, gute Dokumentation im Versionkontroll-System imer auf dem aktuellen Stand). Der Lernaufwand ist allerdings sehr gering, da 99% der Programmierung unterscheidet sich nicht von herkömmlicher Delphi-Programmierung, man muss sich nicht mit Interfaces etc. rumschlagen. Wenn Du Dir den Code von meiner Demo mal ansiehst, dann wirst Du feststellen, dass das ganz "normale" Programmierung ist. Man muss halt nur etwas umdenken ins Richtung modular und so offen, dass man später erweitern/ändern kann. So wird im Bsp. Miranda der Code nicht so geschrieben (ich lass mal Variablen etc weg) :

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
procedure SendMessage;
begin  
  SendeNachricht;
  UpdateMessageWindow;
  LeereEditZeile;
  SchreibeNachrichtInDatenbank;
end;


das wird dann zu :

ausblenden Delphi-Quelltext
1:
2:
3:
4:
procedure SendMessage;
begin  
  HookClient1.ExecuteHook(HM_SendMessage, 0);
end;


die oben genanten Funktionen melden sich einfach am Hook "SendMessage" an und wenn mal jemand per Plugin Sound beim Absenden einfügen möchte, fügt dann halt zum Bsp. nach "SendeNachricht" noch "SpieleSound" ein.
Während man beim herkömmlichen Programm das halt im oberen Code dazwischen schreibt, meldet man bei mir halt eben die Funktion selbst einfach an für "SendMessage" und legt die Position fest (wenn man will, ansonsten kommt es ans Ende).

user profile iconhenni hat folgendes geschrieben Zum zitierten Posting springen:
Aber wie stellst du dann sicher, das jemand fremdes deine DLLs nicht ändert, um sich, wie bereits erwähnt, den Registrierungs- bzw. Aktivierungsprozess des Programmes zu schenken?


Indem ich Funktionen schütze. Das heisst, nur bestimmte Personen können sich in bestimmte CodeGruppen schreiben. Man kann ja einfach mal festlegen, dass zwar jede Benutzergruppe in Deinem Programm sich Plugins installieren kann, diese Plugins aber entsprechend der Benutzerrechte nur in bestimmte Codegruppen schrieben dürfen (für die sie freigegeben sind). Ein Aktivierungsprozess liegt wohl noch über dem Admin, wahrschenlich beim Entwickler und somit kann nichtmal der Admin eine Funktion anmelden oder umlenken, die in der Codegruppe ist. Zusätzlich könnte man den DFT mit der Lizenznummer verschlüsseln, das kann man schon im Installer machen. Und ohne DFT ist das programm nur ein leeres Fenster ;)
Da gibt es viele Möglichkeiten, ist allerdings nicht unbedingt meine Aufgabe, dies zu machen, ich stelle ja prinzipiell erstmal die Tools zur Verfügung, wie Embarcadero Delphi zur verfügung stellt und sich nicht drum kümmert, wie man in seinem programm dann eine Funktion baut, die einem den Aktivierungsprozess schützt.

user profile iconhenni hat folgendes geschrieben Zum zitierten Posting springen:
Zitat:
wo Du das vielleicht kommerziell nutzen willst.

Wo ich was kommerziell nutzen will? Das Plugin-System?
Das soll ja gerade offen sein - jeder soll meine Programme nach seinen Wünschen (natürlich meinen Richtlinien entsprechend) erweitern können!
Z.B. falls er ein Tray-Icon vermisst, oder mein Programm für sein System anpassen will.
Oder falls es Programme, die ich nicht mehr unterstützte, für neuere Betriebssysteme flott machen will.


Spricht ja nichts dagegen, damit Geld zu verdienen, wenn es gut ist. Macht Borland ja auch, den ToolsApi Code gibt es bei Delphi dazu, man kann sich eigene Plugins für die IDE schreiben.

_________________
"Ich bin bekannt für meine Ironie. Aber auf den Gedanken, im Hafen von New York eine Freiheitsstatue zu errichten, wäre selbst ich nicht gekommen." - George Bernhard Shaw
Lutex
Hält's aus hier
Beiträge: 4



BeitragVerfasst: Do 07.04.11 23:16 
Klingt alles sehr interessant, nur funktioniert der Download-Link inwischen nicht mehr. Kann man das Plugin-System im Jahr 2011 noch irgendwo herunterladen, oder ist es inzwischen schon kommerziell?
cocce
Hält's aus hier
Beiträge: 1



BeitragVerfasst: Do 01.12.11 23:57 
Hi all, the download link is broken..

Is it possible to receive the new link.

Thanks in advance.
Cocce