Zitat von
Blup:
Ich könnte mir das etwa so vorstellen:
Delphi-Quellcode:
type
IExport = interface
procedure Export({...});
function GetParams: TStringList;
procedure SetParams(AValue: TStringList);
property Params: TStringList read GetParams write SetParams;
end;
Das geht so aber gar nicht.
TStringList ist eine Delphiklasse und würde es erzwingen dass Exe und
DLL mit gleichen Runtime-Packages ausgeliefert werden.
Und wie wir das schon letztlich hatten, kann man sich dann die
DLL gleich schenken. Die Zeit für dieses Pseudo-Modularisieren kann auch sinnvoller verschwenden. Mit Däumchendrehen zum Beispiel.
IMO macht würde es mehr Sinn machen, wenn das Interface eine Methode zum Setup eines Exports anbietet.
also sowas
Delphi-Quellcode:
type
IExport = interface(IUnknown)
['...']
function ExecuteModal({...}) : TModalResult; safecall;
procedure ExecuteFromSettings({...}); safecall;
procedure Initialize(const host : IHost); safecall;
end;
Die jeweilige Export Implementierung könnte jetzt zum Beispiel einen Dialog zum Speichern der Datei anbieten, oder fragen in welchen Characterset der Export erfolgen soll.
Wenn das ganze automatisierbar und wiederholbar sein sollte, sollte es zusätzlich neben den reinen Benutzer-getriebenen Modus auch die Möglichketi geben, dass er die Werte ablegt.
Allerdings machtes IMO wenig Sinn das von außen durch den Host anzustoßen (die Stringlist). Der host soltle dem Plugin viel mehr einen Weg geben um Settings ablegen zu können.
Das könnte ein IXmlDocument sein. Welches vom Host erzeugt und auch wieder gespeichert wird.
Es gibt verschiedene Mittel mit denen der Host Funktionalität (nennen wir das mal einfach "Services") den PlugIns zur Verfügung stellen kann.
Das erste (und simpelste) wäre, das es direkt Methoden und Properties des IHost interfaces sind.
Delphi-Quellcode:
type IHost = interface(IUnknown)
['...']
procedure GetSettings(out settings : IXmlDocument); safecall;
procedure SaveSettings(const settings : IXmlDocument); safecall;
end;
Die Host-Anwendung würde für jedes Plugin solche eine IHost-Referenz anlegen, so dass ein Plugin nicht aus Versehen in den Sachen eines anderen rumschreibt.
Das ganze ist aber extrem unflexibel und führt fast zwangsläufig dazu, dass irgendwann das IHost-Interface erweitert werden muss, wodurch man entweder ein IHost2-Interface einführen müsste, oder bestehende Plugins würden nicht mehr laufen.
Das wäre schlecht!
Besser ist es die Services, die der Host (oder andere Plugins) zur verfügung stellen will auch als solche zu schreiben.
Zum Biespiel der Service, für die Settings zuständig wäre:
Delphi-Quellcode:
type
ISettingsProvider = interface(IUnknown)
['...']
procedure GetSettings(out settings : IXmlDocument); safecall;
procedure SaveSettings(const settings : IXmlDocument); safecall;
end;
IHost = interface(IUnknown)
['...']
function GetService(const serviceID : TGuid; out service : IUnknown) : Boolean; safecall;
function RegisterService(const serviceID : TGuid; const service : IUnknown) : Boolean; safecall;
end;
Jetzt würde das Plugin so seine Settings holen:
Delphi-Quellcode:
var
settingsService : ISettingsService;
settings : IXmlDocument;
tmp : IUnknown;
begin
if host.GetService(ISettingsService, out tmp)
and Supports(tmp, ISettingsService, settingsService) then
settingsService.GetSettings(settings)
else
settings := nil;
if assigned(settings) then
begin
...
settingsService.SaveSettings(settings);
end;
end;
Du könntest aber die Anwendung erweitern und neue Services hinzufügen, ohne, dass dir rgendein Plugin um die Ohren fliegt, egal ob es 1 Tag oder 5 Jahre alt ist.
Sogar andere Plugins könnten Services registrieren, die alle anderen PlugIns nutzen könnten.
Plugins könnten auf die Weise in unterschiedlichen Delphiversionen oder sogar in C++ oder C# geschrieben werden.
Du könntest also in C# einen Service schreiben, der allen Plugins deiner App RegExes zur Hand gibt, oder die Crypto APIs aus .Net, etc.