![]() |
Welches Objekt für COM-Server mit AktivX-Schnittstelle verwe
Hallo
In einer Applikation muss ich einem anderen Programm eine Active-X Schnittstelle zur Verfügung stellen. Verwendet wird ein IDispatch-Interface. Es sollen auch Events gefeuert werden können. Ich habe nun mal einen Automation-Server programmiert und dazu das Objekt TAutoObject verwendet. In der Schnittstelle wird eine Collection verwendet, für die ich das Objekt TAutoIntfObject verwendet habe. Wenn ich nun die Applikation starte und anschliessend den Prozess, der auf die Active-X Schnittstelle zugreift, wird das TAutoObject erzeugt. Vom TAutoObject wird anschliessend auch automatisch die Collection erzeugt und die zu exportierenden Werte eingefüllt, soweit OK. Wenn ich vom externen Prozess aber auf die Collection zugreife, kann ich zwar die Werte auslesen. Nach dem Ende des Auslesens wird aber das TAutoIntfObject der Collection zerstört. Bei einem weiteren Zuggriff erhalte ich eine Exception. Wie kann ich das machen, dass die Collection nach dem externen Zugriff nicht zerstört wird. Muss ich ein anderes Objekt verwenden? Eine Zusatzfrage: Mit dem TAutoObject wird die Applikation automatisch gestartet, falls von Extern ein Zugriff auf die Active-X Schnittstelle erfolgt. Ich möchte das aber so haben, dass ich die Applikation manuell starten muss und erst dann der Zugriff auf die Daten über Active-X möglich sind. Wie muss ich das machen? Muss ich ein anderes Objekt als TAutoObject verwenden? welches? Danke für Eure Hilfe Tom |
Re: Welches Objekt für COM-Server mit AktivX-Schnittstelle v
Zitat:
|
Re: Welches Objekt für COM-Server mit AktivX-Schnittstelle v
Zitat:
Also angenommen, dein Haupt- oder Einstiegsinterface sieht so aus:
Delphi-Quellcode:
Dann sieht die Implementierung ungefähr so aus:
IApplication = interface(IDispatch)
['{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}'] function GetMyCollection:IMyCollection;safecall; end;
Delphi-Quellcode:
T_Application = class(TAutoObject, IConnectionPointContainer, IApplication)
private FMyCollection : IMyCollection; protected function GetMyCollection:IMyCollection;safecall; end; function T_Application.GetMyCollection:IMyCollection;safecall; begin // die Collection wird beim 1. Mal erzeugt und "lebt" dann weiter bis zum Ende // oder bis FMyCollection auf nil gesetzt wird if not Assigned(FMyCollection) then FMyCollection := TMyCollection.Create(ComServer.TypeLib, IMycollection); Result := FMyCollection; end; Zitat:
Objekte, die von Aussen erzeugt werden dürfen, haben in der TLB eine CoClass und werden durch TAutoObject repräsentiert. Andere Objekte, die erst später erzeugt werden, werden durch TAutoIntfObject repräsentiert. Wenn du nicht willst, dass dein Objekt von aussen erzeugt werden kann, gibt es 2 Möglichkeiten: - CoClass in der TLB (und in der Projektdatei) löschen. TAutoIntfObject verwenden. bei Initialization das TAutoObjectFactory.Create löschen - in der TLB bei der CoClass das Flag "Erzeugen möglich" entfernen Danach geht von "Aussen" aber zunächst gar nichts mehr. Du musst nun dein Objekt in der Anwendung selbst erzeugen und in der ROT (Running Object Table) registrieren. Der Client kann nun mit GetActiveOleObject() Zugriff auf dein Objekt erhalten; allerdings nur, wenn deine Anwendung schon läuft. |
Re: Welches Objekt für COM-Server mit AktivX-Schnittstelle v
Hallo
Danke für den Tip aber so funktioniert es bei mir auch nicht. Die Collection ist bei mir schon in einer Variable zwischengespeichert, da sie an einem Hauptobjekt angebunden ist. Der Typ des Hauptobjekts ist TAutoObject, welches automatisch erzeugt wird. Beim Initialisieren des Hauptobjekts (Initialize) wird die Collection vom Typ TAutoIntfObject erzeugt und in der internen Variablen FSetupData zwischengespeichert. Beim Aufruf von GetMyCollection wird nur die interne Variable FSetupData zurückgegeben. Der Grund. In der Collection werden Konfigurationsdaten gespeichert, die beim Erzeugen des Hauptobjekts da hineingeschrieben werden. Wird die Collection nach einem Zugriff gelöscht, sind die Daten auch weg. Liege ich hier falsch oder funktioniert das dynamisch, d.h. bei jedem Aufruf der Collection müssen die Konfigurationsdaten neu geladen werden? Gruss Tom Du musst die Collection in einer Variablen zwischenspeichern. Also angenommen, dein Haupt- oder Einstiegsinterface sieht so aus:
Delphi-Quellcode:
Dann sieht die Implementierung ungefähr so aus:
IApplication = interface(IDispatch)
['{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}'] function GetMyCollection:IMyCollection;safecall; end;
Delphi-Quellcode:
T_Application = class(TAutoObject, IConnectionPointContainer, IApplication)
private FMyCollection : IMyCollection; protected function GetMyCollection:IMyCollection;safecall; end; function T_Application.GetMyCollection:IMyCollection;safecall; begin // die Collection wird beim 1. Mal erzeugt und "lebt" dann weiter bis zum Ende // oder bis FMyCollection auf nil gesetzt wird if not Assigned(FMyCollection) then FMyCollection := TMyCollection.Create(ComServer.TypeLib, IMycollection); Result := FMyCollection; end; |
Re: Welches Objekt für COM-Server mit AktivX-Schnittstelle v
Zitat:
Optional könnte man die Collection erst bei 1. Aufruf von GetMyCollection erzeugt und befüllen; muss man aber nicht. Wichtig ist auch, dass die Variable FSetupData ein Interfacepointer ist, da nur so die Referenzzählung richtig funkt.
Delphi-Quellcode:
FSetupData : TMycollection; // Falsch, kein Interfacepointer
FSetupData : IMyCollection; // Richtig Zitat:
braucht nur einmal durchgeführt werden. Jetzt muss man natürlich weiter in die Tiefe gehen. Ich würde mal die Funktionen _AddRef und _Release ersetzen und so die Referenzzählung beobachten:
Delphi-Quellcode:
TMyCollection = class(TAutoIntfObject, IMyCollection)
.... function _AddRef: Integer; stdcall; function _Release: Integer; stdcall; end; function TMyCollection._AddRef: Integer; begin Result := InterlockedIncrement(FRefCount); OutputDebugString(PChar('TMyCollection._AddRef='+IntToStr(Result))); end; function TMyCollection._Release: Integer; begin Result := InterlockedDecrement(FRefCount); OutputDebugString(PChar('TMyCollection._Release='+IntToStr(Result))); if Result = 0 then Destroy; end; |
Re: Welches Objekt für COM-Server mit AktivX-Schnittstelle v
Danke, so funktioniert es mal richtig. :-D
Nun hab ich aber das Problem, dass ich nicht mehr auf die Funkion SetConfig zugreifen kann, mit der ich das Objekt mit den Konfigurationsdaten befülle, da diese von intern befüllt und daher nicht über ein Interface verfügt. Ich versuchte es mal so: FSetupData : TMyCollection; FISetupData : IMyCollection; und Create FISetupData := Create.MyCollection; aber ich kann dann FSetupData := FISetupData as TMyCollection nicht zuweisen. :x und FISetupData.SetConfig kennt der Compiter logischerweise nicht. Im Prinzip müsste ich ja nur den Pointer des MyCollection Objekts an FSetupData zuweisen, aber da spielt mir die Compilereinschränkung einen Streich. :roll: Natürlich könnte ich auch ein Interface für diese Funktion definieren, aber dies macht keinen Sinn, da die Funktion nicht von Extern aufgerufen werden soll. Tom Das ist soweit alles richtig. :thumb: Optional könnte man die Collection erst bei 1. Aufruf von GetMyCollection erzeugt und befüllen; muss man aber nicht. Wichtig ist auch, dass die Variable FSetupData ein Interfacepointer ist, da nur so die Referenzzählung richtig funkt.
Delphi-Quellcode:
FSetupData : TMycollection; // Falsch, kein Interfacepointer
FSetupData : IMyCollection; // Richtig Zitat:
|
Re: Welches Objekt für COM-Server mit AktivX-Schnittstelle v
Zitat:
Dieses [private] Interface wird aber nicht im TLB-Editor, sondern direkt im Sourcecode deklariert:
Delphi-Quellcode:
Da dieses Interface von IUnknown abgeleitet ist, kannst alle Delphi-Datentypen benutzen und brauchst kein SafeCall.
IMyCollectionSetup = Interface(IUnknown)
['{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}'] procedure SetConfig(const filename:string); end; Du solltest eine GUID im Interface angeben, damit die Umwandlung mit as klappt:
Delphi-Quellcode:
(FISetupData as IMyCollectionSetup).SetConfig(...);
|
Re: Welches Objekt für COM-Server mit AktivX-Schnittstelle v
Das Funktioniert bei mir nicht richtig. Ich erhalte einen EIntfCastError, Interface not supported.
Eine GUID habe ich allerdings beim Private-Interface angegeben. Fehlt da noch etwas. Die Datentypen sollte ja kein Problem sein. Tom Zitat:
|
Re: Welches Objekt für COM-Server mit AktivX-Schnittstelle v
Zitat:
(Shift+Strg+G innerhalb der Delphi-IDE drücken.) Ausserdem muss das Interface auch implementiert werden:
Delphi-Quellcode:
TMyCollection = class(TAutoIntfObject, IMyCollection, IMyCollectionSetup)
|
Re: Welches Objekt für COM-Server mit AktivX-Schnittstelle v
Danke, der Fehler war, dass ich das Interface nicht in der Class angegeben haben. Nun funktioniert's.
Danke für Deine Hilfe Tom Zitat:
|
Re: Welches Objekt für COM-Server mit AktivX-Schnittstelle v
Zitat:
ich beschäftige mich gerade mit Com und möchte genau sowas realisieren. Ich hab mir ein Object mit dem Assistenten erzeugt und das Flag "Erzeugen möglich" entfernt. In meiner Anwendung erzeuge ich nun das Object, aber das ist an sich scheinbar noch nicht ausreichend... Wie schon angesprochen, muss es noch in der ROT (Running Object Table) registriert werden... Aber wie mach ich das? Und wie rufe ich es dann mit GetActiveOleObject() auf? die Funtion erwartet ja einen Klassennamen, welchen ich sicher erst beim registrieren mit angebe oder? Was passiert, wenn ich meine Anwendung wieder beende, dann muss ich das Object sicher wieder entfernen oder? Bye Christian |
Re: Welches Objekt für COM-Server mit AktivX-Schnittstelle v
Zitat:
Dein (Server-)Objekt registriert sich selbst in der ROT im RegisterActiveObject() und bekommt bei Erfolg ein Cookie zurück. Das Cookie wird in eine privaten Variable gespeichert. Im Destruktor wird RevokeActiveObject() aufgrufen und das Cookie mitgegeben. Der Client ruft GetActiveOleObject() um das Objekt aus der ROT zu erhalten. Falls das nicht klappt wird mit CreateOleObject() ein neues Objekt erzeugt. Siehe: ![]() |
Alle Zeitangaben in WEZ +1. Es ist jetzt 20:57 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