![]() |
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? |
Re: Plug-ins realisieren für (D)COM Server
Zitat:
|
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
|
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:
Die implementierung sieht so aus:
type
TLogServerObjectFactory = class(TAutoObjectFactory) public procedure UpdateRegistry(Register: Boolean); override; end;
Delphi-Quellcode:
Im Initalization teil muss man nun die Standard Factory mit der eigenen Klasse ersetzen:
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;
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:
Um die Funktionen der Plugins aufzurufen iteriere ich durch meine Interface liste, speichere das Interface in einem OleVariant und rufe die Funktion auf
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; ( 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:
Ich hoffe ich habs einigermassen verständlich rübergebracht. Vielleicht hilft es ja jemandem.
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); Gruss |
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. |
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 05:21 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz