AGB  ·  Datenschutz  ·  Impressum  







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

COM-Server als Singleton umsetzen

Ein Thema von crypti · begonnen am 4. Jan 2009 · letzter Beitrag vom 9. Jan 2009
Antwort Antwort
Seite 1 von 2  1 2      
crypti

Registriert seit: 12. Feb 2005
43 Beiträge
 
#1

COM-Server als Singleton umsetzen

  Alt 4. Jan 2009, 11:37
Hallo Leute!

Ich hoffe auch ihr seit gut ins Jahr 2009 gerutscht.

Ich versuche mich hier gerade an der Umsetzung einer ActiveX Bibliothek die über die von Delphi bekannten Automatisierungsobjekte enthält. Soweit alles ok, funktioniert auch super. Da ich jedoch in der Bibliothek eine Datenbank verwenden will, muss der Einstieg den die Anwendungen über COM nutzen ein Singleton sein. Also alle bekommen die gleiche Instanz der Anwendung zugeteilt.

Delphi-Quellcode:
unit COM_MyServer;

{$WARN SYMBOL_PLATFORM OFF}

interface

uses
  ComObj, ActiveX, MyServerLib_TLB, StdVcl, Windows;

type
  TSingletonAutoObjectFactory = class(TAutoObjectFactory)
  private
    FCOMObj : TComObject;
  protected
    { Protected-Deklarationen }
    function CreateComObject(const Controller: IUnknown): TComObject; override;
    destructor Destroy; override;
  end;

type
  TMyServer = class(TAutoObject, IMyServer)
  private
    bIsLoaded : Boolean;
  protected
    procedure TestServer; safecall;
    function InitDB: Integer; safecall;
  end;

implementation

uses ComServ;

{ TMyServer }

procedure TMyServer.TestServer;
begin
     windows.OutputDebugString(PCHAR('TMyServer.TestServer: erfolgreich ausgeführt'));
end;

function TMyServer.InitDB: Integer;
begin
     if (bIsLoaded = true) then
     begin
          windows.OutputDebugString(PCHAR('TMyServer.InitDB: DB allready loaded'));
     end
     else
     begin
          bIsLoaded:=true;
     end;
end;


{ TSingeltonAutoObjectFactory }

function TSingletonAutoObjectFactory.CreateComObject(const Controller: IInterface): TComObject;
begin
     if FCOMObj = nil then
          FCOMObj := inherited CreateComObject(Controller);

     result := FCOMObj;
end;

destructor TSingletonAutoObjectFactory.Destroy;
begin
     FCOMObj := nil;
     inherited;
end;


initialization
// TAutoObjectFactory.Create(ComServer, TMyServer, Class_MyServer,
// ciMultiInstance, tmApartment);
  TSingletonAutoObjectFactory.Create(ComServer, TMyServer, Class_MyServer,
    ciMultiInstance, tmApartment);

end.
Der zugehörige Client sieht ganz einfach aus. Dieser importiert die TLB und greift dann auf den Server zu.

Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
begin
    MyServer:=CoMyServer.Create;

    MyServer.TestServer();

    MyServer.InitDB();
end;
Nun ist mein Problem, dass diese Singleton-Umsetzung nicht ganz funktioniert. Wenn ich in in EINER Anwendung den ButtonClick mehrfach ausführe, dann erhalte ich im COM-Server auch die Meldung, dass die DB bereits initialisiert wurde. Klappt also wunerbar, ist ein Singleton.
Wenn ich jedoch diese Clientanwendung parallel ein zweites (drittes...) Mal starte und die Aktion ausführe, dann verhalten sich diese genauso wie die erste. Beim ersten Klick wird die DB initialisiert und dann nicht mehr.

Was ich nun gern hätte ist ein übergreifendes Singleton. Egal wie viele Programme darauf zugreifen, alle bekommen die gleiche Instanz. Momentan scheint das Singleton nur an die aufrufende Programminstanz gebunden zu sein.

Hat jemand da eine (oder mehrere) Ideen? Schon mal Danke im Voraus!
  Mit Zitat antworten Zitat
Benutzerbild von sakura
sakura

Registriert seit: 10. Jun 2002
Ort: Unterhaching
11.412 Beiträge
 
Delphi 12 Athens
 
#2

Re: COM-Server als Singleton umsetzen

  Alt 4. Jan 2009, 11:48
Du musst den COM-Server entweder als Out-Of-Proces-Server (EXE-Anwendung) realisieren oder mithilfe der Komponentenbibliothek (anstatt regsvr32.exe) registrieren. Ich würde Dir die EXE-Variante empfehlen, da so die Verteilung (Installation) leichter ist.

......
Daniel Lizbeth
Ich bin nicht zurück, ich tue nur so
  Mit Zitat antworten Zitat
crypti

Registriert seit: 12. Feb 2005
43 Beiträge
 
#3

Re: COM-Server als Singleton umsetzen

  Alt 4. Jan 2009, 12:10
Danke für die schnelle Antwort!

Ist es möglich einen solchen Out-Of-Process-Server auch innerhalb eines Windows Dienstes umzusetzen? Oder gibt es dann Probleme mit anderen Restriktionen? Denn dann hätte ich einen "anfassbaren" Dienst, den ich von außen durch andere Dienste und Anwendungen nutzen kann.


Auch wenn es an dieser Stelle etwas off-Topic ist. Wie kommunizieren Windows Dienste normalerweise mit der Außenwelt bzw. wie stellen diese ihre Funktionalitäten Anwendungen bereit? WM, Pipes, COM?
  Mit Zitat antworten Zitat
crypti

Registriert seit: 12. Feb 2005
43 Beiträge
 
#4

Re: COM-Server als Singleton umsetzen

  Alt 4. Jan 2009, 15:04
Ich habe das jetzt mal innerhalb eines Services ausprobiert. Also ein Windows Dienst mit integrierten COM-Server. Klappt soweit ganz gut, nur habe ich nun ein neues Problem. Nämlich wenn der Dienst läuft und eine Anwendung per CoMyServer.Create; zugreift, dann wird die Service.exe noch einmal gestartet und zwar unter dem Benutzer der gerade angemeldet ist. Wieso wird nicht der laufende Service und damit integrierte COM-Server verwendet? Muss man noch spezielle Einstellungen tätigen, damit die Anwendung den Dienst erkennt?
  Mit Zitat antworten Zitat
Benutzerbild von Ralf Kaiser
Ralf Kaiser

Registriert seit: 21. Mär 2005
Ort: Wuppertal
932 Beiträge
 
Delphi 10.3 Rio
 
#5

Re: COM-Server als Singleton umsetzen

  Alt 4. Jan 2009, 18:40
Halli Hallo,

versuch mal deinen COM Server mittels "RegisterActiveObject" in die ROT einzutragen (ROT = Running Objects Table).

Siehe hier

Auf diese Weise kannst du von aussen immer auf eine (und nur auf eine) Instanz eines COM-Servers zugreifen. Am besten registriert man die laufende Instanz im Eventhandler für "AfterConstruction" des Serverobjektes.

Wir betreiben bei unserer Software mehrere COM server auf diese Weise und arbeiten mit Einzelinstanzen dieser Server aus verschiedensten Situationen heraus (normale Anwendung, Word-Addin, Deskband, IE Addin) Dabei werden die Server nur vom ersten der zugreift erzeugt. Die anderen Softwareteile benutzen dann die laufenden Instanzen der Server.

Im Umfeld eines Service hab ich das allerdings noch nicht getestet!!

Ciao,
Ralf
Ralf Kaiser
  Mit Zitat antworten Zitat
crypti

Registriert seit: 12. Feb 2005
43 Beiträge
 
#6

Re: COM-Server als Singleton umsetzen

  Alt 5. Jan 2009, 21:29
Danke Alfi001 für die Infos. Die ROT wäre eine Lösung, wenn ich bei der DLL Umsetzung bleiben würde.

Die Umstellung auf einen Service kommt mir allerdings ganz gelegen, da ich damit für mich noch weitere Vorzüge erhalte. So bin ich nun dabei einen Service mit COM Server zu realisieren.

Hier bin ich auch schon einen großen Schritt weiter gekommen. Denn nach der Erstellung des Services, der Integration der Typenbibliothek un der Automatisierungsobjekte habe ich eine exe. Diese wird als erstes als Service installiert (Parameter /install) und anschließend die Typenbibliothek registiert (Parameter /RegServer).

Wenn man nun durch einen Client darauf zugreifen will, dann erhält man das Problem was ich weiter oben schon beschrieben habe. Der COM Server wird nicht mit dem laufenden Service assoziiert und deshalb wird versucht die EXE im Usermode zu starten. Hier schaffte ein wenig googlen und die MSDN Doku Abhilfe. Man muss den Service noch einmal anlegen und dann unter der CLASS GUID als AppID (welche durch den /RegServer Befehl in die Registry gefügt wurden) eintragen.

Delphi-Quellcode:
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\AppID\MeinService.exe]
"AppID"="{D3FEF3C6-5F1B-42DC-A9CB-246BD681CA2D}"

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\AppID\{D3FEF3C6-5F1B-42DC-A9CB-246BD681CA2D}]
@="MeinService"
"LocalService"="MeinService"
"ServiceParameters"=""


[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{CLASS GUID DER TLB}]
"AppID"="{D3FEF3C6-5F1B-42DC-A9CB-246BD681CA2D}"
Sobald dies drin ist versucht auch der Client nicht mehr den Service noch einmal unter dem UserMode zu starten. Wenn der Dienst nicht läuft dann wird er gestartet, wenn er läuft wird er nicht erneut gestartet. Also so wie es erwartet wird.

Jedoch habe ich nun ein neues Problem. Denn wenn der Client das MyServer:=CoMyServer.Create; ausführt, dann erhalte ich die Meldung "Zugriff verweigert". Muss man für den Zugriff auf COM Server die innerhalb des Service Modes laufen noch irgendwelche Security Descriptoren beachten? Die MSDN Doku ist hier eher etwas mau...

Meine bisherigen Quellen...

http://msdn.microsoft.com/en-us/library/ms809975.aspx
http://msdn.microsoft.com/en-us/library/ms693774(VS.85).aspx

Kennt sich jemand in diesem Bereich aus und kann mir weiterhelfen? Oder bin ich der erste auf der Welt der sowas machen will und Probleme hab... *glaub ich aber nicht*
  Mit Zitat antworten Zitat
chipNET

Registriert seit: 28. Mär 2004
5 Beiträge
 
#7

Re: COM-Server als Singleton umsetzen

  Alt 8. Jan 2009, 12:55
Gibt es da nicht tools die die Registrierung für dich übernimmt. Bei .NET gibts doch glaube ich sowas wie Regsvcs.exe und ComSvcConfig.exe. Gibts sowas nicht auch im Standard WinAPI Bereich für C++ und damit auch für Delphi.
  Mit Zitat antworten Zitat
Benutzerbild von spaxxn
spaxxn

Registriert seit: 19. Nov 2004
253 Beiträge
 
Delphi XE2 Enterprise
 
#8

Re: COM-Server als Singleton umsetzen

  Alt 8. Jan 2009, 13:39
Du brauchst 2 COM-Server für das was du da machen willst...

Der Server, der mit der Datenbank kommuniziert wird mit den Parametern ciInternal und tmApartment initialisiert.

Der Server, der mit der Anwendung kommuniziert wird mit ciMultiInstance und tmApartment initialisiert. Zudem hat dieser Server, ich nenne ihn einmal Manager, eine Property vom Typ des Interfaces vom DB-COM-Server. Beim Zugriff auf die Property wird geprüft, ob der Server schon läuft, ansonsten wird er gestartet:

Delphi-Quellcode:
function TCallbackManager.Get_CallbackServer : ICallbackServer;
begin
  if (CallbackServer = nil) then
    CallbackServer := TCallbackServer.Create;
  Result := CallbackServer;
end;
Damit läuft der Server für die DB innerhalb des Out-Of-Process Servers genau einmal.

Das muss so sein, da jede Anwendung, egal ob späte oder frühe Bindung, ihr eigenes COM-Objekt braucht, so meine Erfahrungen.
"Hey Süße,
hol mir mal was zu trinken! Du wirst schon wieder hässlich!"

Zitat eines Betrunkenen
  Mit Zitat antworten Zitat
chipNET

Registriert seit: 28. Mär 2004
5 Beiträge
 
#9

Re: COM-Server als Singleton umsetzen

  Alt 8. Jan 2009, 13:47
So wie ich das verstanden habe hat er aber wohl schon Probleme den ersten COM Server - der als Service läuft - mit der Anwendung anzusprechen.


Zitat von crypti:
Sobald dies drin ist versucht auch der Client nicht mehr den Service noch einmal unter dem UserMode zu starten. Wenn der Dienst nicht läuft dann wird er gestartet, wenn er läuft wird er nicht erneut gestartet. Also so wie es erwartet wird.

Jedoch habe ich nun ein neues Problem. Denn wenn der Client das MyServer:=CoMyServer.Create; ausführt, dann erhalte ich die Meldung "Zugriff verweigert". Muss man für den Zugriff auf COM Server die innerhalb des Service Modes laufen noch irgendwelche Security Descriptoren beachten? Die MSDN Doku ist hier eher etwas mau...
  Mit Zitat antworten Zitat
Benutzerbild von spaxxn
spaxxn

Registriert seit: 19. Nov 2004
253 Beiträge
 
Delphi XE2 Enterprise
 
#10

Re: COM-Server als Singleton umsetzen

  Alt 8. Jan 2009, 13:50
Das ist ja nun wieder ein anderes Problem, wie das, auf das ich geantwortet habe und gehört demzufolge auch in einen neuen Thread
"Hey Süße,
hol mir mal was zu trinken! Du wirst schon wieder hässlich!"

Zitat eines Betrunkenen
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


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:31 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