Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi Welches Objekt für COM-Server mit AktivX-Schnittstelle verwe (https://www.delphipraxis.net/46775-welches-objekt-fuer-com-server-mit-aktivx-schnittstelle-verwe.html)

tgoessi 31. Mai 2005 13:50


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

Memo 31. Mai 2005 14:10

Re: Welches Objekt für COM-Server mit AktivX-Schnittstelle v
 
Zitat:

Zitat von tgoessi
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?

Müsste über CoAddRefServerProcess funktionieren.

shmia 31. Mai 2005 14:38

Re: Welches Objekt für COM-Server mit AktivX-Schnittstelle v
 
Zitat:

Zitat von tgoessi
Wie kann ich das machen, dass die Collection nach dem externen Zugriff nicht zerstört wird. Muss ich ein anderes Objekt verwenden?

Du musst die Collection in einer Variablen zwischenspeichern.
Also angenommen, dein Haupt- oder Einstiegsinterface sieht so aus:
Delphi-Quellcode:
IApplication = interface(IDispatch)
    ['{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}']
   function GetMyCollection:IMyCollection;safecall;
end;
Dann sieht die Implementierung ungefähr so aus:
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:

Zitat von tgoessi
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?

Grundsätzlich gilt für Automatisierungsobjekte:
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.

tgoessi 31. Mai 2005 16:46

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:
IApplication = interface(IDispatch)
    ['{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}']
   function GetMyCollection:IMyCollection;safecall;
end;
Dann sieht die Implementierung ungefähr so aus:
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;

shmia 31. Mai 2005 17:11

Re: Welches Objekt für COM-Server mit AktivX-Schnittstelle v
 
Zitat:

Zitat von tgoessi
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.

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:

Zitat von tgoessi
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?

Das Collection-Objekt wurde einaml erzeugt und sollte weiter leben; das Laden der Konfigurationsdaten
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;

tgoessi 1. Jun 2005 09:02

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:

Zitat von tgoessi
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?


shmia 1. Jun 2005 09:34

Re: Welches Objekt für COM-Server mit AktivX-Schnittstelle v
 
Zitat:

Zitat von tgoessi
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.

Doch, ein 2. Interface wäre der richtige Weg.
Dieses [private] Interface wird aber nicht im TLB-Editor, sondern direkt im Sourcecode deklariert:
Delphi-Quellcode:
IMyCollectionSetup = Interface(IUnknown)
['{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}']
   procedure SetConfig(const filename:string);
end;
Da dieses Interface von IUnknown abgeleitet ist, kannst alle Delphi-Datentypen benutzen und brauchst kein SafeCall.
Du solltest eine GUID im Interface angeben, damit die Umwandlung mit as klappt:
Delphi-Quellcode:
   (FISetupData as IMyCollectionSetup).SetConfig(...);

tgoessi 1. Jun 2005 10:13

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:

Zitat von shmia
Zitat:

Zitat von tgoessi
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.

Doch, ein 2. Interface wäre der richtige Weg.
Dieses [private] Interface wird aber nicht im TLB-Editor, sondern direkt im Sourcecode deklariert:
Delphi-Quellcode:
IMyCollectionSetup = Interface(IUnknown)
['{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}']
   procedure SetConfig(const filename:string);
end;
Da dieses Interface von IUnknown abgeleitet ist, kannst alle Delphi-Datentypen benutzen und brauchst kein SafeCall.
Du solltest eine GUID im Interface angeben, damit die Umwandlung mit as klappt:
Delphi-Quellcode:
   (FISetupData as IMyCollectionSetup).SetConfig(...);


shmia 1. Jun 2005 10:58

Re: Welches Objekt für COM-Server mit AktivX-Schnittstelle v
 
Zitat:

Zitat von tgoessi
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.

Es muss natürlich ein neue, noch nicht verwendete GUID sein.
(Shift+Strg+G innerhalb der Delphi-IDE drücken.)
Ausserdem muss das Interface auch implementiert werden:
Delphi-Quellcode:
TMyCollection = class(TAutoIntfObject, IMyCollection, IMyCollectionSetup)

tgoessi 1. Jun 2005 11:13

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:

Zitat von shmia
Zitat:

Zitat von tgoessi
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.

Es muss natürlich ein neue, noch nicht verwendete GUID sein.
(Shift+Strg+G innerhalb der Delphi-IDE drücken.)
Ausserdem muss das Interface auch implementiert werden:
Delphi-Quellcode:
TMyCollection = class(TAutoIntfObject, IMyCollection, IMyCollectionSetup)



Alle Zeitangaben in WEZ +1. Es ist jetzt 23:21 Uhr.
Seite 1 von 2  1 2      

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