AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

DLL Parser Plugins

Ein Thema von Alaitoc · begonnen am 15. Dez 2009 · letzter Beitrag vom 29. Dez 2009
Antwort Antwort
Seite 2 von 3     12 3      
Benutzerbild von Mithrandir
Mithrandir
(CodeLib-Manager)

Registriert seit: 27. Nov 2008
Ort: Delmenhorst
2.379 Beiträge
 
#11

Re: DLL Parser Plugins

  Alt 21. Dez 2009, 12:05
Zitat von Elvis:
[1]und das willst du weil platte C-kompatible DLLs bestenfalls als menschenverachtende Folter in Den Haag verhandelt werden sollten
Genau das hatte ich vor. Nun stolpere ich aber alle Nase lang über Interfaces und bekomme ein schlechtes Gewissen. (Auch wenn ich die Idee mit einem generischen Pointer und einer einfach Konstante, damit die DLL weiß, was da für ein Typ hinter dem Pointer steckt, reizvoll finde.. ).

Ich raffe irgendwie den C#-Teil noch nicht so ganz. Nehmen wir mal folgendes Beispiel:

Das Programm soll modular aufgebaut sein. Das heißt, ich soll nach belieben Plugins hinzufügen und wegnehmen können. Nehmen wir mal an, dass das Programm eine Klasse hat, die so aufgebaut ist:

Delphi-Quellcode:
  Type
    Tst_mmclass = class
      private
        (* Path of the file being played *)
        fMediaFile : AnsiString;
        (* Handle of the current audio stream *)
        fCurrentStream : HSTREAM;
        (* Handle of the application *)
        fAppHandle : HWND;
        (* Stream is playing *)
        fStreamIsPlaying: Boolean;
        (* We need the Plugin Observer, so this class can adress plugins *)
        fPluginObserver: TPluginObserver;
        (* Assign Channel to new Media File *)
        procedure NewMediaFile(const Value: AnsiString);
        procedure SetPluginObserver(const Value: TPluginObserver);
      public
        property MediaFile : AnsiString read fMediaFile write NewMediaFile;
        property AppHandle : HWND read fAppHandle write fAppHandle;
        property CurrentStream : HSTREAM read fCurrentStream write fCurrentStream;
        property StreamIsPlaying : Boolean read fStreamIsPlaying write fStreamIsPlaying;
        property PluginObserver : TPluginObserver read fPluginObserver write SetPluginObserver;
        (* Playback Control *)
        procedure Play;
        procedure Pause;
        procedure NextTrack;
        procedure PrevTrack;
        (* Initialization of Bass.dll *)
        procedure InitBass(Path: AnsiString);
        (* Deinitialization of Bass.dll *)
        procedure DeInitBass;
        (* Con- & Destructor *)
        Constructor Create;
        Destructor Destroy; override;
    end;
Ferner gibt es eine Klasse, TPluginObserver, die eine Liste aller geladenen Plugins verwaltet. Außerdem soll sie eigentlich auch die Aufrufe der Plugins und die Nachrichten der Plugins an die Anwendung verwalten. (Ja, mit meinem System hätte ich mit SendMessage Application-interne Nachrichten verschickt, mit entsprechenden Pointer garniert.) Meine Hoffnung an Interfaces ist, dass ich das gar nicht machen muss.

Angenommen, ich möchte jetzt, dass ein Plugin eine Playlist bereitstellt. Wie würde jetzt ein Beispiel mit Interfaces aussehen, in dem das Plugin dem Hauptprogramm den Dateipfad übergibt (soll in die Property "MediaFile" geschrieben werden) und anschließend die Prozedur "Play" ausführt. Und wie würde man in die andere Richtung kommunizieren? Denn wenn der Anwender auf "Next Track" klickt, muss ich dem Plugin ja mitteilen können, dass ich jetzt den nächsten Eintrag aus der Liste brauche...

Oder sollte ich zur Kommunikation meine Observer-Klasse ausbauen?

Würde mich über ein Beispiel zu diesem Anwendungsfall freuen, ich stehe gerade etwas auf dem Schlauch...
米斯蘭迪爾
"In einer Zeit universellen Betruges wird das Aussprechen der Wahrheit zu einem revolutionären Akt." -- 1984, George Orwell
  Mit Zitat antworten Zitat
Benutzerbild von MyRealName
MyRealName

Registriert seit: 19. Okt 2003
Ort: Heilbronn
675 Beiträge
 
Delphi 10.4 Sydney
 
#12

Re: DLL Parser Plugins

  Alt 21. Dez 2009, 19:40
Schau Dir doch mal meine Modular Application Framework Components an, die sind für den Hausgebrauch und Freeware kostenlos. Die bieten ein plugin-interface, welches Du ohne code zu schreiben einbinden kannst und während der Laufzeit des programms neue plugins installieren oder de-installieren, code in DLLs aktivieren und vieles mehr.

Zu finden mit tutorials und einer grösseren Beispiel-Anwendung unter www.maf-components.com
  Mit Zitat antworten Zitat
Benutzerbild von Mithrandir
Mithrandir
(CodeLib-Manager)

Registriert seit: 27. Nov 2008
Ort: Delmenhorst
2.379 Beiträge
 
#13

Re: DLL Parser Plugins

  Alt 21. Dez 2009, 21:30
Danke für das Angebot, aber du hast vermutlich die großen VCL/RTL-Units ala Classes und SysUtils drinne, oder? Außerdem handelt es sich um eine Open-Source App.
米斯蘭迪爾
"In einer Zeit universellen Betruges wird das Aussprechen der Wahrheit zu einem revolutionären Akt." -- 1984, George Orwell
  Mit Zitat antworten Zitat
Benutzerbild von MyRealName
MyRealName

Registriert seit: 19. Okt 2003
Ort: Heilbronn
675 Beiträge
 
Delphi 10.4 Sydney
 
#14

Re: DLL Parser Plugins

  Alt 21. Dez 2009, 21:52
Wenn Du mit VCL/RTL arbeiten willst/musst, dann brauchst Du die wohl.
Und leider kann ich opensource nicht mit meinem Source unterstützen, sonst verkauf ich ja nichts mehr und in 3 Wochen gibt es 3 chinesische/indische/pakistanische Anbieter von meinem System, hehe

Ansonsten lass VCL/RTL als dynamische Laufzeitbibliothek laufen, dann kann Dein System auf mehreren Delphi-Versionen übersetzt werden und die DLLs können sich klein halten. Spätestens wenn Du Formulare etc in DLLs auslagerst (Config-Dialoge für Plugins zum Bsp.) dann brauchst Du die eh dort und kannst/musst eine shared Version der VCL/RTL nutzen.
  Mit Zitat antworten Zitat
Benutzerbild von Mithrandir
Mithrandir
(CodeLib-Manager)

Registriert seit: 27. Nov 2008
Ort: Delmenhorst
2.379 Beiträge
 
#15

Re: DLL Parser Plugins

  Alt 21. Dez 2009, 21:55
Zitat von MyRealName:
Wenn Du mit VCL/RTL arbeiten willst/musst, dann brauchst Du die wohl.
Da ich aber ohne die VCL arbeite (aka Non-VCL ), stören mich die Units. Aber dennoch danke für dein Angebot.
米斯蘭迪爾
"In einer Zeit universellen Betruges wird das Aussprechen der Wahrheit zu einem revolutionären Akt." -- 1984, George Orwell
  Mit Zitat antworten Zitat
Elvis

Registriert seit: 25. Nov 2005
Ort: München
1.909 Beiträge
 
Delphi 2010 Professional
 
#16

Re: DLL Parser Plugins

  Alt 21. Dez 2009, 23:21
Das ist gar nicht so schlimm.
Du musst allerdings ein bissel umdenken.
Du kannst du nicht diese blödsinnigen Methodpointer-Properties nehmen, die Delphi "Events" nennt,
Denn die haben ja immer nur einen Subscriber, wobei die Worte "Subscriber" oder "Event" bei der saubilligen Implementierung wie sie die VCL nutzt wohl maßlos übertrieben sind.
Da es keine interoperablen Multicast-Methodpointer gibt, musst du dir halt ein Interface bauen, was du wie einen Delegate nutzt.
Delphi-Quellcode:
type
  IEventHandler = interface
  ['']
     procedure Invoke; safecall;
  end;
Du kannst dir dann einen EventManager, Eventsink, Listener , Observer oder wie auch immer du es nennen magst, bauen, der solche IEventHandler in einer InterfaceList verwaltet und nach außen nur Add und Remove zur Verfügung stellt.
Das heißt, Plugins können nur einen Handler hinzufügen, oder exakt ihren wieder entfernen. (Sich also nicht in die Quere kommen)
Es gibt dann ein weiteres Interface, was von dem IEventManager ableitet, und ihm die Methoden Clear und Raise gibt.
Den einen um alle Handler loszuwerden, den anderen um alle zu feuern.
Dieses 2. Interface ist nur innerhalb der App zu benutzen.

Deine App könnte den Teil, der das Playback abbildet als einen Service zur Verfügung stellen:
Delphi-Quellcode:
IPlaybackEventHandler = interface
  procedure Invoke(aState : TPlaybackState); safecall; //halt irgendein enum
end;

IPlaybackEvent = interface
  procedure AddHandler(const aHandler : IPlaybackEventHandler); safecall;
  procedure RemoveHandler(const aHandler : IPlaybackEventHandler); safecall;
end;

IPlaybackProvider = interface
  procedure Play; safecall;
  procedure Stop; safecall;
  procedure Next; safecall;
  ...
  property StateChanges : IPlaybackEvent read ...; // der Manager
  property StateChanged : IPlaybackEvent read ...; // der Manager
end;
Ein Plugin könnte den Host (aus seiner Sicht: die App) nach dem Playback-Service erfragen und dort einen Handler reinwerfen, der es über Änderungen informiert.

Willst du deine App wirklich ernsthaft erweiterbar machen, dann solltest du auch innerhalb der App alles so lösen.
Dann merkst du wenn deine API, der Teil, den auch die Plugins nutzen können, nicht mächtig genug ist.

Es ist Blödsinn Dinge innerhalb der App anders zur Verfügung zu stellen, als für Plugins. (Warum darf die App direkt ins Menü pfuschen?)
Und direkten zugriff auf Dinge wie Controls oder Menus kannsu schonmal komplett vergessen, da du sonst keine Benachrichtigungen abfangen und in einem Plugin auswerten könntest, richtig?
Robert Giesecke
I’m a great believer in “Occam’s Razor,” the principle which says:
“If you say something complicated, I’ll slit your throat.”
  Mit Zitat antworten Zitat
Benutzerbild von Mithrandir
Mithrandir
(CodeLib-Manager)

Registriert seit: 27. Nov 2008
Ort: Delmenhorst
2.379 Beiträge
 
#17

Re: DLL Parser Plugins

  Alt 22. Dez 2009, 11:01
Waaaah, ich raffs immer noch nicht... Ich habe noch nie (also, nicht direkt ) selbst interfaces implementieren müssen. (Durchgearbeitet: Dit hier, dit und dit och. )

Also, janz langsam, damit ich das auch verstehe:
(ich wiederhole es quasi nochmal, mit ein paar Anmerkungen, wo ich was nicht verstanden habe...)

Ich komme weg von den Klassen mit ihren Methoden. (Klassen pöhse! ) Ich brauch die Klassen nur noch, um die Interfaces implementieren zu können. Zuerst baue ich mir für meine benötigen Funktionen Interfaces. Jetzt kann ich das Kind ja bei Namen nennen: Es geht natürlich um SmallTune. Daher auch meine Abneigung gegenüber Closed Source, Sysutils, Classes usw...

Was kann der Audioplayer? Er kann Mediadateien wiedergeben (Playback), und er stellt ein TNA-Menü bereit (ContextMenu). Nach langem Überlegen beim Schreiben dieses Beitrags bin ich zu der Überzeugung gekommen, dass das die Grundfunktionen sind.
Es gibt dann ja auch noch ein "Display", welches der Player zum Anzeigen nutzt. Ich wüsste aber jetzt nicht, ob es gut wäre, die Klasse in ein Interface umzuwandeln, da ich zum Einen dran mit-, sie aber nicht selbst geschrieben habe, und zum Anderen vielleicht auch gar nicht möchte, das Plugins auf das Design zugreifen können...

Ich bräuchte also (mindestens) zwei EventHandler:

Delphi-Quellcode:
  
  (* Playback State *)
  TPlaybackState = ( stPlaying, stStopped, stNewTrack, stPreviousTrack, stNextTrack );

  IPlaybackEventHandler = interface
    ['{00000000-0000-0000-0000-000000000000}']
    procedure Invoke(SomeState: TPlaybackState);
  end;

  IPlaybackEvent = interface
    ['{00000000-0000-0000-0000-000000000001}']
    procedure AddEvent(const Ev: IPlaybackEventHandler);
    procedure DeleteEvent(const Ev: IPlaybackEventHandler);
  end;

  IPlaybackProvider = interface
    procedure Play; safecall;
    procedure Stop; safecall;
    procedure Next; safecall;
    {...}
    property StateChanges : IPlaybackEvent {read ...}; // der Manager
    property StateChanged : IPlaybackEvent {read ...}; // der Manager
  end;

  (* ContextMenu *)
  type
    TMenuItem = packed record
      ID : Cardinal;
      Caption : WideString;
    end;

  IContextMenu = interface
    (* Getter *)
    function GetMenuHandle: HMENU;
    (* Setter *)
    procedure SetMenuHandle(Value: HMENU );
    procedure AppendMenuItem(Itm : TMenuItem );
    procedure DeleteMenuItem(ItmID : Cardinal );
    property MenuHandle: HMENU read GetMenuHandle write SetMenuHandle;
  end;

  IContextMenuEventHandler = interface
    ['{00000000-0000-0000-0000-000000000002}']
    procedure Invoke({?}); //Event wird ausgelöst, wenn ein Item angeklickt wird.
  end;

  IContextMenuEvent = interface
    ['{00000000-0000-0000-0000-000000000003}']
    procedure AddEvent(const Ev: IContextMenuEventHandler);
    procedure DeleteEvent(const Ev: IContextMenuEventHandler);
  end;
Ein paar Verständnisfragen:

Angenommen, ich möchte jetzt das Menü erstellen. Wenn ich das richtig verstanden habe, darf ich das nicht in der Anwendung im Abschnitt WM_CREATE direkt tun, sondern sollte eine Eigenschaft der Klasse TContextMenu ( die ich von IContextMenu ableite ) nutzen, oder?

Alle Plugins, die entsprechende EventHandler für das ContextMenu registriert haben, sollen benachrichtigt werden, sobald ein Eintrag angeklickt wird. Ziehe ich das System so durch, muss die Anwendung selbst auch Events registrieren, oder? Denn Punkte wie "Schließen", "Info", "Hilfe" sollen ja nicht durch Plugins eingetragen werden, sondern durch die Anwendung.
Die Nachricht, dass ein Eintrag angeklickt wurde, bekommt ja immer das Parent des Menüs. Das wäre in diesem Fall meine Anwendung, also alles wie bisher. Die Anwendung würde dann alle WM_COMMAND-Nachrichten vom Typ WM_BUTTON an das IContextMenu weiterleiten, welches seinerseits ein Event an alle registrierten Plugins auslösen würde. Die müssten dann gucken, ob das Event für sie gedacht ist.

Damit alle Plugins angesprochen werden können, bastel ich mir einen EventManager. Hier melden sich alle Plugins an. Dafür müssen die Plugins von sich aus ein Interface bereitstellen, bspw. IPlugin:

Delphi-Quellcode:
  Type
    TPluginType = (ptPlayback, ptContextMenu (* usw? *) );

  IPlugin = interface
    ['{00000000-0000-0000-0000-000000000004}']
    (* Getter *)
    function GetPluginMajorVersion: Cardinal;
    function GetPluginMinorVersion: Cardinal;
    function GetName: WideString;
    function GetAuthor: WideString;
    function GetAuthorURL: WideString;
    function GetPluginType: WideString;

    property PluginMajorVersion : Cardinal read GetPluginMajorVersion;
    property PluginMinorVersion : Cardinal read GetPluginMinorVersion;
    property Name : WideString read GetName;
    property Author : WideString read GetAuthor;
    property AuthorURL : WideString read GetAuthorURL;
    property PluginType : TPluginType read GetPluginType;
  end;
Die Frage ist, wie bekomme ich es hin, eine Interface Liste aufzubauen, ohne die Classes.pas zu nutzen?
Die Plugins können ja jetzt daherkommen, und die Interfaces, die sie brauchen, implementieren. Und dann bräuchte ich ja auch noch so eine Art "Handshake", oder? Denn irgendwie muss ja bspw. auf die Instanz des Playback Services zugreifen, den die Anwendung erstellt hat, damit das Plugin "Play" aufrufen kann, oder?

Sorry, aber ich betrete gerade komplettes Neuland und fühl mich etwas unsicher dabei. Daher kommt das alles etwas "stackselig" daher.

//Edit: Oder mache ich mir das Leben gerade unnötig schwer?
米斯蘭迪爾
"In einer Zeit universellen Betruges wird das Aussprechen der Wahrheit zu einem revolutionären Akt." -- 1984, George Orwell
  Mit Zitat antworten Zitat
Elvis

Registriert seit: 25. Nov 2005
Ort: München
1.909 Beiträge
 
Delphi 2010 Professional
 
#18

Re: DLL Parser Plugins

  Alt 22. Dez 2009, 11:55
Sorry, wenn ich kurz angebunden bin, aber wir müssen gleich los und einen Weinaxbaum holen.
Ich habe für das Menuzeugs letzlich ein Sample geschrieben, das liegt auf dem Firmenrechner, und auf den werde ich mich heute Abend wohl sowieso nochmal einklinken müssen.
Wie du Funktionalität den Plugins zur Verfügung stellst habe ich hier kurz angerissen.
Zur TInterfaceList, die macht ja keine Zauberei, das geht auch ohne Classes.pas. Wenn du die nämlich nicht nimmst, hast da ja sowieso sicherlich schon eine eigene Basisliste, auf der du die InterfaceList aufbauen könntest. Der Sinn davon ist, nur dass der Referenzzähler schon gepflegt wird, ohne dass du dir da ein Bein abbrechen musst.

Oh und eins noch: Records sind WERTE, keine Objekte und erst Recht keine Entitäten.
Du kannst nichts damit modellieren ohne auf die *piep* zu fliegen. Deshalb kann ein Record auch kein Menuitem sein.
Mühe dich mit dem Menu erstmal nicht ab, ich habe da ein schönes Beispiel (zumindest fast fertig), dass ich nur holen und polieren müsste.
Robert Giesecke
I’m a great believer in “Occam’s Razor,” the principle which says:
“If you say something complicated, I’ll slit your throat.”
  Mit Zitat antworten Zitat
Benutzerbild von Mithrandir
Mithrandir
(CodeLib-Manager)

Registriert seit: 27. Nov 2008
Ort: Delmenhorst
2.379 Beiträge
 
#19

Re: DLL Parser Plugins

  Alt 22. Dez 2009, 11:58
Zitat von Elvis:
Sorry, wenn ich kurz angebunden bin, aber wir müssen gleich los und einen Weinaxbaum holen.
Den hamma Gott sei dank schon.
Zitat von Elvis:
Ich habe für das Menuzeugs letzlich ein Sample geschrieben, das liegt auf dem Firmenrechner, und auf den werde ich mich heute Abend wohl sowieso nochmal einklinken müssen.
Wie du Funktionalität den Plugins zur Verfügung stellst habe ich hier kurz angerissen.
Zur TInterfaceList, die macht ja keine Zauberei, das geht auch ohne Classes.pas. Wenn du die nämlich nicht nimmst, hast da ja sowieso sicherlich schon eine eigene Basisliste, auf der du die InterfaceList aufbauen könntest. Der Sinn davon ist, nur dass der Referenzzähler schon gepflegt wird, ohne dass du dir da ein Bein abbrechen musst.
Zitat von Elvis:
Mühe dich mit dem Menu erstmal nicht ab, ich habe da ein schönes Beispiel (zumindest fast fertig), dass ich nur holen und polieren müsste.
Cool, danke...
米斯蘭迪爾
"In einer Zeit universellen Betruges wird das Aussprechen der Wahrheit zu einem revolutionären Akt." -- 1984, George Orwell
  Mit Zitat antworten Zitat
Benutzerbild von Mithrandir
Mithrandir
(CodeLib-Manager)

Registriert seit: 27. Nov 2008
Ort: Delmenhorst
2.379 Beiträge
 
#20

Re: DLL Parser Plugins

  Alt 23. Dez 2009, 11:10


Ich möcht' ja nicht unhöflich, aufdringlich, verlangend, fordernd oder gar ausfallend wirken (vor allem, nachdem ich diesen Thread mittlerweile gekapert habe ), aaaaaber:

Postest du das Beispiel noch vor den Feiertagen? Werde mir vermutlich bis Dienstag eine (Online-)Auszeit nehmen (müssen), da wäre es ganz schön, wenn man für die Zeit Spiel, Spaß und Spannung hätte.

米斯蘭迪爾
"In einer Zeit universellen Betruges wird das Aussprechen der Wahrheit zu einem revolutionären Akt." -- 1984, George Orwell
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 2 von 3     12 3      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 18:39 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