Service: Visual-Basic 6.0 Tipps:

Mehrfache Verwendung von Objektinstanzen eines ActiveX-Servers


Eine immer wieder gestellte Frage bei der objektorientierten Programmierung mit COM bzw. ActiveX lautet:

Wie kann ich dieselbe Instanz eines ActiveX-Servers durch verschiedene Clients mehrfach verwenden? Dabei ist dies kein reines VB-Problem. Egal ob Sie ActiveX Komponenten mit C++, Java, VB oder irgend einer anderen Programmiersprache erstellen: Das Problem ist immer das gleiche.

VB-Programmierer glauben meistens, dass sie dieses Ziel schnell und einfach erreichen, indem sie für die Klasse, die den ActiveX-Server repräsentiert, die Eigenschaft 'Instancing' auf 'GlobalMultiUse' setzen - und erleiden damit Schiffbruch.

Warum das so ist, wird unter Warum DLL Objekte nie global sind grundlegend erklärt.

Die pragmatische Lösung habe ich an einem Beispiel erläutert. Laden Sie den VB-Code hier herunter.

Nachdem Sie das ZIP-Archiv entpackt haben, finden Sie drei Projekte:

  Projekt   Erläuterung
  MehrfVerwObjektInst.vbp   Der ActiveX-Server, der die mehrfache Verwendung von Objektinstanzen demonstriert
  BeweisTesten1.vbp   Ein Beispielprogramm, das den ActiveX-Server verwendet
  BeweisTesten2.vbp   Ein anderes Beispielprogramm, das den ActiveX-Server verwendet

Um das Beispiel zu testen, gehen Sie folgendermaßen vor:

  • Laden und starten Sie das erste Projekt (den ActiveX-Server)
  • Laden Sie das zweite Projekt
  • Prüfen Sie, ob die Referenz auf den ActiveX-Server verfügbar ist (Projekt --> Verweise --> Eintrag 'Beispiel für die mehrfache Verwendung von Objektinstanzen' aktivieren)
  • Starten Sie das Projekt und klicken Sie die Schaltfläche 'Wer war Erster'
  • Starten Sie das zweite Projekt und wiederholen Sie die beiden vorhergehenden Schritte

Wenn Sie die Meldung, die nach dem Klicken der Schaltfläche erscheint genau prüfen, werden Sie feststellen, dass der ActiveX-Server Ihnen die Daten aus dem zuerst gestarteten Projekt zurückliefert. Das funktioniert auch, wenn Sie die Startreihenfolge der Projekte 'BeweisTesten1' und 'BeweisTesten2' tauschen.

Fazit: Es geht! Frage: WARUM?

Sehen Sie sich dazu jetzt die Implementierung des ActiveX-Servers an: Das Projekt besteht aus folgenden Modulen:

  Modulname   Modultyp   Einstellungen/Eigenschaften
  CBeweisConnector   Klassenmodul   Instancing: GlobalMultiUse
  CBeweis   Klassenmodul   Instancing: PublicNotCreatable
  MMehrfVerwObjektInst   Standardmodul    

'CBeweis' würde in Ihrem Projekt der Klasse entsprechen, die Sie dem Benutzer des ActiveX-Servers zur Verfügung stellen wollen. Die beiden anderen Module sind nur das Beiwerk, das erforderlich ist, um die Einmaligkeit von 'CBeweis'-Objekten sicher zu stellen.

Dabei besteht der Trick darin, dass innerhalb des ActiveX-Servers eine globale Variable vom Typ 'CBeweis' gehalten wird. Clients des ActiveX-Servers können jedoch keine entsprechende Objektvariable instanziieren (Instancing: PublicNotCreatable). Statt dessen können die Clients Objekte vom Typ 'CBeweisConnector' instanziieren und diese Objektvariable auffordern, eine Referenz auf die aktuelle Objektvariable vom Typ 'CBeweis' herauszugeben (Methode 'Connect').

Diese Objektvariable wird von 'CBeweisConnector' instanziiert, wenn jemand zum ersten Mal (und nur dann) ein 'CBeweisConnector'-Objekt instanziiert.

Um den Vorgang besser nachzuvollziehen, setzen Sie am besten einen Haltepunkt an den Anfang der 'Connect'-Methode der Klasse 'CBeweisConnector' - vielleicht auch in 'Class-Terminate' und starten nacheinander die beiden Client-Programme.

Ergänzende Hinweise:
1. Am wichtigsten folgender Hinweis:
Bedenken Sie bitte was passiert, wenn ein Client seine Referenz auf ein 'CBeweisConnector'-Objekt entfernt, jedoch das auf das gelieferte 'CBeweis'-Objekt behält. Vielleicht wollen Sie darüber gar nicht so genau nachdenken - aber wenn so etwas geschieht, haben Sie Probleme!!!

Stellen Sie stets sicher, dass das von einer Connector-Klasse gelieferte Objekt entfernt wird, bevor Sie das Connector-Objekt entfernen.

Bedenken Sie dabei bitte eines: Eine Objektreferenz wird nicht unbedingt erst entfernt, wenn Sie diese explizit auf 'Nothing' setzen. VB entfernt Objektvariablen VB automatisch, wenn der Gültigkeitsbereich der Objektvariablen verlassen wird. Deklarieren Sie also die Variable auf das Connector-Objekt niemals auf Modul- oder Prozedurebene, während Sie die Referenz auf das gelieferte Objekt auf höherer Ebene deklarieren!

2. Das Beispiel-Projekt ist als ActiveX-EXE implementiert. Das ist erforderlich, damit der beschriebene Mechanismus funktioniert. ActiveX-EXE-Server werden in einem eigenen Adressraum ausgeführt, d.h. es handelt sich um eine eigenständige Anwendung. Nur deshalb können unterschiedliche Client-Anwendungen eine Verbindung mit dem ActiveX-Server herstellen.

Im Gegensatz dazu werden ActiveX-DLL-Server im Adressraum der Client-Anwendung ausgeführt, d.h. ActiveX-DLL-Server verhalten sich so, als sei ihr Code Bestandteil der Client-Anwendung. Aus diesem Grund ist eine Objektinstanz eines Active-X-DLL-Servers _immer_ eine exklusive Objektinstanz der Client-Anwendung.

3. Beachten Sie bitte, dass wir uns bei dieser Verfahrensweise etwas aufhalsen, womit VB-Programmierer normalerweise nichts zu tun haben: Referenzzählung. Sie fragen sich: wieso Referenzzählung? - Schauen Sie einmal, welchen Zweck die Variable 'iBeweisUserCount' hat.

4. Es gibt noch eine nette Möglichkeit, diesen Mechanismus zu erweitern: Wenn Sie genau darüber nachdenken, stellen Sie folgendes fest: Sobald der letzte Client seine Referenz auf sein Connector-Objekt entfernt (unter Berücksichtigung von Punkt 1!) wird auf die Instanz des 'Nutz'-Objektes (im Beispiel die 'CBeweis'-Klasse) entfernt und der ActiveX-Server wird aus dem Speicher entfernt.

Durch gezielte Modifikationen der Connector-Klasse, können Sie eine Implementierung erreichen, bei der der ActiveX-Server nach Beendigung des/der Clients weiter arbeitet. Dazu müsste der ActiveX-Server einen bestimmten Modus (z.B. Arbeitsmodus im Gegensatz zu Bereitschaftsmodus) unterstützen:

Solange der ActiveX-Server sich in diesem Modus befindet, wird er auch dann nicht beendet, wenn der letzte Client sich verabschiedet.

Wenn sich anschließend ein Client erneut mit dem ActiveX-Server verbindet, findet er die alte Referenz auf das Objekt der 'CBeweis'-Klasse vor.

Auf diese Weise läßt sich z.B. auch eine Art Dienstprogramm implementieren. Wenn man dabei DCOM nutzt (beachten Sie dazu DCOM verwenden), kann ein Dienst durchaus auf einem entfernten Rechner im Netzwerk gestartet werden.

Diese Überlegung ist übrigens keine bloße Theorie, sondern wird von einem durch mich entwickelten System zur Zählerfernauslesung verwendet (siehe unser Projekt Zählerfernauslesung am Ende der Seite unter 'Prozessüberwachung').

Seitenanfang

Kontaktaufnahme- und Terminvereinbarung:

Bei Fragen und für Terminvereinbarungen erreichen Sie uns unter:

0 63 49 99 07 38

0 151 51 95 34 00

Oder nutzen Sie das Kontaktformular




Ihr Ansprechpartner:


Hier sollte das Fahnungsfoto zu sehen sein.

Ralf Kunsmann

Spezialist für VBA-Programmierung
(alle Office-Anwendungen)
Entwickler der
VBA-Extension-Tools