Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Plug-ins realisieren für (D)COM Server (https://www.delphipraxis.net/117213-plug-ins-realisieren-fuer-d-com-server.html)

SyntaxError 14. Jul 2008 11:47


Plug-ins realisieren für (D)COM Server
 
Hallo,

Ich entwickle gerade ein Logging mechanismus als DCOM Server, damit ich eine generelle Schnittstelle habe für ggf. zukünftige Anwendungen. Das Interface ist sehr einfach gehalten: start,stop,log(message)
Funktioniert auch alles prima, nur möchte ich den Server erweiterbar machen, d.h. logs werden nicht nur in textfiles geschrieben, sondern können auch (durch implementieren eines Interfaces) in beliebige Orte gespeichert werden. Weiss jemand wie ich das realisieren könnte?Ich hatte daran gedacht eine Library pro Ziel typ zu erstellen (als z.b XMLplugin.dll, EmailPlugin.dll, MSEventsPlugin.dll etc).
Wie weiss aber der Server welche plugins vorhanden sind?

alzaimar 14. Jul 2008 12:58

Re: Plug-ins realisieren für (D)COM Server
 
Zitat:

Zitat von SyntaxError
Wie weiss aber der Server welche plugins vorhanden sind?

Am Server registrieren oder in ein bestimmtes Verzeichnis packen.

Codewalker 14. Jul 2008 13:58

Re: Plug-ins realisieren für (D)COM Server
 
Ich habe das (zwar nicht für DCOM) mit TJvPlugin gemacht. Das klappt wunderbar - wollte schon immer ein Tutorial schreiben .... wäre mal ein Anlass

SyntaxError 14. Jul 2008 16:11

Re: Plug-ins realisieren für (D)COM Server
 
Also ich habs jetzt "einigermassen" hingekriegt ;) weiss zwar nicht wie effizient das ganze ist (und ausführlich getestet habs ich auch noch nicht) aber es funktioniert bis jetzt gut, darum hab ich gedacht ich share mal code ausschnitte für diejenigen die ein ähnliches problem haben:

Kurzfassung:
Man erstellt ein Automations objekt für den Server, in diesem Beispiel LogServer (bzw. ILogServer) PLUS ein Interface ILogServerPlugin.
In meinem beispiel enthält ILogServerPlugin ein readonly property "PluginName" und eine methode "OnLog(AMessage:WideString);

Um ein eigenes Plugin zu erstellen müssen Automations objekte das Interface "ILogServerPlugin" implementieren und ihre ProgID im Schlüsse des Server objekts in der Registry eintragen.
( ich habe die Registry gewählt, man kann natürlich auch ein IniFile nutzen oder sonstwas, wichtig ist, dass Server die ProgID der Plugins von irgendwo her bekommt)


Die Interfaces sehen grob so aus (aufs minimum reduziert):

Delphi-Quellcode:
  ILogServer = interface(IDispatch)
    procedure Log(const AMessage: WideString); safecall;
    function Get_InstalledPlugIns: WideString; safecall;
    property InstalledPlugIns: WideString read Get_InstalledPlugIns;
  end;

  ILogServerPlugin = interface(IDispatch)
    function Get_PluginName: WideString; safecall;
    procedure OnLog(const AMessage: WideString); safecall;
    property PluginName: WideString read Get_PluginName;
  end;

Die Implementierung des Server Objekts sieht grob so aus:

Delphi-Quellcode:
  TLogServer = class(TAutoObject, ILogServer)
  private
    FPlugIns: TInterfaceList;
    procedure UnloadPlugIns();
  protected
    procedure Log(AMessage: WideString); safecall;
    function Get_InstalledPlugIns: WideString; safecall;
  public
    procedure Initialize; override;
    destructor Destroy; override;
  end;

Bei der Server implementierung habe ich eine eigene Factory von TAutoObjectFactory abgeleitet um die UpdateRegistry methode zu überschreiben.
Zweck davon ist, in der Registry einen neuen Schlüssel anzulegen der die ProgID's der installierten Plugins enthält.


Delphi-Quellcode:
 type
  TLogServerObjectFactory = class(TAutoObjectFactory)
  public
    procedure UpdateRegistry(Register: Boolean); override;
  end;
Die implementierung sieht so aus:

Delphi-Quellcode:
procedure TLogServerObjectFactory.UpdateRegistry(Register: Boolean);
var
  R: TRegistry;
begin
  inherited;

  if Register then // beim registrieren des DCOM Servers schlüssel anlegen
  begin
    R := TRegistry.Create;
    try
      R.CreateKey('\Software\LogServer\PlugIns');
    finally
      R.Free;
    end;
  end else
  begin // schlüssel löschen beim "unregistrieren"
    R := TRegistry.Create;
    try
      R.DeleteKey('\Software\LogServer\PlugIns');
    finally
      R.Free;
    end;
  end;
end;
Im Initalization teil muss man nun die Standard Factory mit der eigenen Klasse ersetzen:

Delphi-Quellcode:
initialization
  TLogServerObjectFactory.Create(ComServer, TLogger, CLASS_Logger,
    ciMultiInstance, tmApartment);

Um die PlugIns zu laden iteriere ich durch die Registry schlüssel, kreiere ein Objekt anhand des Schlüsselnamens(=ProgID),
und lege das Objekt in eine TInterfaceList (=FPlugIns).
(LoadPlugins wird im Create bzw. Initialization Aufruf des ServerObjekte aufgerufen),


Delphi-Quellcode:
procedure TLogServer.LoadPlugIns;
var
  i: integer;
  r: TRegistry;
  pList: TStringList;
  P: IInterface;
begin
 r := TRegistry.Create;
  try
    if r.OpenKeyReadOnly('\Software\LogServer\PlugIns') then
    begin
      if r.HasSubKeys then
      begin
        pList := TStringList.Create;
        r.GetKeyNames(pList);
        for I:=0 to pList.Count-1 do
        begin
          P := CreateOleObject(pList[I]); // kreiere Plugin Objekt anhand der ProgID (bsp: 'MyPlugin.MyPlugin')
          FPlugIns.Add(P);
        end;
      end;
    end;
  finally
    R.Free;
  end;
end;
Um die Funktionen der Plugins aufzurufen iteriere ich durch meine Interface liste, speichere das Interface in einem OleVariant und rufe die Funktion auf
( Dieser Teil ist zugegebenermassen nicht so elegant, da ich späte bindung nutze. Habe es mit casten des Interfaces zu ILogServerPlugin versucht, aber kriegte immer Fehlermeldung mit
"Schnittstelle nicht unterstützt", vielleicht hat einer von euch ja einen Tip?)
In dieser Funktion gebe ich die namen aller installierten plugins zurück. Die Methode OnLog funktioniert auf die gleiche weise (iterieren, aufrufen).

Delphi-Quellcode:
function TLogServer.Get_InstalledPlugIns: WideString;
var
  I: Integer;
  PlugInObj: OleVariant;
begin
  if FPlugIns.Count > 0 then
  begin
    for I:=0 to FPlugIns.Count-1 do
    begin
      try
        PlugInObj := FPlugIns.Items[I] as IDispatch;
        Result := Result + PlugInObj.PlugInName+#13;
        VarClear(PlugInObj);
      except
        //
      end;
    end;
  end;
end;

// CLIENT bzw. PLUGIN

Die Implementierung des Plugins ist ziemlich einfach. Neues Automationsobjekt erstellen das von ILogServerPlugin ableitet, es registrieren (dem Server bekannt machen) und Methoden implementieren.
Dazu auch hier eine neue Klasse von TAutoObjectFactory (TPluginFactory) ableiten und UpdateRegistry überschreiben:

Delphi-Quellcode:
procedure TPlugInFactory.UpdateRegistry(Register: Boolean);
var
  R: TRegistry;
begin
  inherited;
  if Register then // beim registrieren der activex library progid dem Server bekanntmachen
  begin
    R := TRegistry.Create;
    R.OpenKey('\Software\LogServer\PlugIns\'+ProgID),True);
    R.Free;
  end else
  begin
    R := TRegistry.Create; // schlüssel löschen bei "unregistrierung"
    try
      R.DeleteKey('\Software\LogServer\PlugIns\'+ProgID));
    finally
      R.Free;
    end;
  end;
end;

...

initialization
  TPlugInFactory.Create(ComServer, TFileLogPlugin, Class_FileLogPlugin,
    ciMultiInstance, tmApartment);
Ich hoffe ich habs einigermassen verständlich rübergebracht. Vielleicht hilft es ja jemandem.

Gruss

shmia 14. Jul 2008 17:30

Re: Plug-ins realisieren für (D)COM Server
 
Liste der Anhänge anzeigen (Anzahl: 1)
Das was du da gemacht hast, ist zwar nicht falsch, aber Microsoft hat für den Zweck der Plugins extra sogenanne COM-Categories vorgesehen.
Ein Plugin registiert sich (also seine GUID) in einer bestimmten COM-Categorie.
Sowohl der Anwendung, als auch dem Plugin muss die GUID der COM-Categorie bekannt sein.
Die COM-Categorie hat neben der GUID auch eine Bezeichnung (auf Wunsch auch in versch. Sprachen).

In einer DLL können durchaus mehrere Plugin Co-Klassen enthalten sein und sich für eine oder auch mehrere COM-Categorien registrieren.
Wenn man's richtig macht, dann wird beim Registieren einer ActiveX-DLL nicht nur die DLL und deren Co-Klassen registiert sondern auch die Plugin-Klassen werden registriert.
Beim EntRegistrieren wird dies automatisch rückgängig gemacht.

Wenn man dieses System benützt, braucht man selbst in der Registry gar nichts eintragen.
Das Tool OLEView kann übrigens alle COM-Categorien und damit registrierte Co-Klassen anzeigen.
Die "Desktop Bands" und "Interner Explorer Browser Bands" basieren z.B. auch auf COM-Categorien.

SyntaxError 14. Jul 2008 17:58

Re: Plug-ins realisieren für (D)COM Server
 
Danke für die Unit und den Tip mit den Categories. Ich werde mir das in dem Fall genauer anschauen.


Alle Zeitangaben in WEZ +1. Es ist jetzt 17:26 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