Möchtest Du den gesamten Artikel lesen? Und vielleicht sogar den Artikel im PDF-Format und die Beispieldateien herunterladen? Dann hole Dir den Artikel gleich hier - völlig kostenlos!
Viele Szenarien, in denen man eine COM-DLL benötigt, kann man mit einer VB6-COM-DLL auf Basis von twinBASIC abbilden. Manchmal möchte man aber auf Funktionen zugreifen, die einfacher mit einem VB.NET-Projekt zu erledigen sind. In diesem Artikel schauen wir uns nicht nur an, wie wir einen COM-DLL mit VB.NET erstellen, sondern legen den Fokus auf das Bereitstellen von Ereignissen und wie wir diese in dem VBA-Projekt, welches die COM-DLL nutzt, implementieren können.
Beispielprojekt anlegen
Um das Beispielprojekt zu erstellen, benötigen wir Visual Studio, zum Beispiel in der Version 2022. Hier legen wir ein neues Projekt an und wählen dazu den Typ Klassenbibliothek (.NET-Framework) aus (siehe Bild 1).
Bild 1: Projekttyp für das neue Projekt auswählen
Name festlegen
Anschließend erscheint der Dialog, mit dem wir den Namen des Projekts festlegen sowie das Verzeichnis, in dem es angelegt werden soll. Hier stellen wir für die Eigenschaft Name den Wert amvEvents ein (siehe Bild 2).
Bild 2: Projekteigenschaften vor dem Speichern festlegen
Klasse umbenennen
Im nun erscheinenden Projekt-Explorer benennen wir als Erstes die Klasse Class1.vb in Ereignis.vb um. Visual Studio fragt uns nun, ob wir auch die Verweise auf das entsprechende Code-Element anpassen wollen, was wir bestätigen (siehe Bild 3).
Bild 3: Umbenennen der Klasse des Projekts
Assemblyinformationen anpassen
Damit kommen wir zu einigen Einstellungen, die für die Verwendung des Projekts als COM-DLL wichtig sind.
Als Erstes klicken wir im Projektmappen-Explorer doppelt auf den Eintrag My Project.
Dies öffnet den Bereich mit den Eigenschaften des Projekts. Hier sehen wir unter Anwendung die Schaltfläche Assemblyinformationen… (siehe Bild 4).
Bild 4: Bearbeiten der Projekteigenschaften
Diese klicken wir an und öffnen so den Dialog Assemblyinformationen. Hier aktivieren wir im unteren Bereich die Option Assembly COM-sichtbar machen (siehe Bild 5).
Bild 5: Aktivieren der COM-Sichtbarkeit
Nachdem wir den Dialog wieder geschlossen haben, wechseln wir in den Projekt-Optionen zum Bereich Kompilieren. Hier finden wir ganz unten die Option Für COM-Interop registrieren. Indem wir diese aktivieren, sorgen wir dafür, dass die COM-DLL beim Erstellen in die Registry eingetragen wird, sodass sie für den Zugriff von VBA aus verfügbar ist (siehe Bild 6).
Bild 6: Aktivieren der Registrierung für COM-Interop
Damit haben wir die Vorbereitungen abgeschlossen und können uns dem eigentlichen Programmieren zuwenden.
Beispiel für ein COM-DLL-Ereignis programmieren
Das Ziel der folgenden Schritte ist die Programmierung des einfachsten denkbaren Beispiels für das Bereitstellen eines Ereignisses durch die COM-DLL. Dazu wollen wir die folgende Struktur realisieren:
- Programmierung eines Ereignisses mit dem Schlüsselwort Event, so wie es auch in VBA realisierbar ist
- Hinzufügen einer öffentlichen Methode, mit der wir das Ereignis auslösen können.
Damit die Elemente der COM-DLL optimal im VBA-Editor genutzt werden können, können wir nicht einfach eine Klasse mit der Definition des Ereignisses und der auslösenden Methode programmieren.
Unter VBA könnten wir das etwa wie folgt in einem Klassenmodul programmieren:
Public Event Ereignis() Public Sub EreignisAusloesen() RaiseEvent Ereignis() End Sub
In VB.NET reicht das aber nicht aus. Hier benötigen wir einige weitere Elemente, damit das Ereignis problemlos funktioniert und nicht mehr Elemente als nötig unter VBA angezeigt werden. Die Klasse wird in Listing 1 im Überblick dargestellt, in den folgenden Abschnitten erläutern wir die einzelnen Elemente.
Imports System.Runtime.InteropServices <InterfaceType(ComInterfaceType.InterfaceIsDual)> Public Interface IEreignis Sub EreignisAusloesen() End Interface <InterfaceType(ComInterfaceType.InterfaceIsIDispatch)> Public Interface IEreignisEvents Sub Ereignis() End Interface <ClassInterface(ClassInterfaceType.None)> <ComSourceInterfaces(GetType(IEreignisEvents))> Public Class Ereignis Implements IEreignis Public Event Ereignis() Public Sub EreignisAusloesen() Implements IEreignis.EreignisAusloesen RaiseEvent Ereignis() End Sub End Class
Listing 1: Die Klasse Ereignis im Überblick
Notwendiger Namespace: InteropServices
Damit wir die gleich im Detail beschriebenen speziellen COM-Interfaces verwenden können, fügen wir dem Modul als erste Zeile den Import des Namensraums System.Runtime.InteropServices hinzu:
Imports System.Runtime.InteropServices
Trennung von COM-Methoden und COM-Ereignissen
Wenn wir in anderen Artikeln einmal COM-DLLs auf Basis von VB.NET vorgestellt haben, wurde dort auch schon immer ein Interface verwendet, welches die Klasse dann implementiert hat. Das hat den Sinn, dass wirklich nur die in dem Interface definierten Elemente wie Eigenschaften oder Methoden nach außen sichtbar werden – zum Beispiel unter VBA.
Wenn wir kein Interface verwenden würden, sehen wir unter VBA unnötige Elemente wie Equals, GetHashCode oder GetType. Diese benötigen wir aber nicht und sie machen die Auswahl der Elemente per IntelliSense auch noch unübersichtlicher. Das ist also der Grund, warum wir ein Interface wie das folgende definieren:
<InterfaceType(ComInterfaceType.InterfaceIsDual)>
Public Interface IEreignis
Sub EreignisAusloesen()
End Interface
Hier legen wir zunächst den Typ des Interfaces fest, und zwar ComInterfaceType.InterfaceIsDual. damit stellen wir sicher, dass alle in diesem Interface deklarierten Methoden, Eigenschaften und so weiter auch unter VBA angezeigt und verwendet werden können – sowohl per IntelliSense als auch im Objektkatalog.
Hier sehen wir allerdings nur die Methode EreignisAusloesen und nicht die Definition des Ereignisses selbst. Dieses müssen wir in einem eigenen Interface definieren.
Für dieses verwenden wir wiederum einen anderen Interface-Typ, nämlich ComInterfaceType.InterfaceIsDispatch. Nur so können wir Ereignisse empfangen. Das Ereignis definieren wir durch eine einfache Sub-Definition wie folgt:
<InterfaceType(ComInterfaceType.InterfaceIsIDispatch)>
Public Interface IEreignisEvents
Sub Ereignis()
End Interface
Logik der Klasse und Implementierung der Elemente
Schließlich folgt die eigentliche Logik beziehungsweise die Implementierung der beiden Elemente, also der Methode und des Ereignisses.
Dies geschieht in der eigentlichen Klasse Ereignis, die das Interface IEreignis mit der Methode EreignisAusloesen implementiert. Diese Klasse deklarieren wir als Klassen-Interface mit dem Typ ClassInterfaceType.None. Die Elemente dieser Klasse werden dadurch nicht automatisch veröffentlicht und erscheinen somit nicht im VBA-Projekt, wenn wir diesem einen Verweis auf die COM-DLL hinzufügen. Das ist auch nicht nötig, denn alle Elemente haben wir bereits über die zuvor beschriebenen Elemente mit den Interface-Typen InterfaceIsDual (für die Eigenschaften und Methoden) sowie InterfaceIsDispatch (für die Ereignisse) veröffentlicht.
Wie aber machen wir in dieser Klasse kenntlich, durch welche öffentlichen Elemente die Methode und das Ereignis nach außen verfügbar gemacht werden?
Für das Interface IEreignis gelingt dies durch zwei Maßnahmen:
- Wir fügen der Klasse Ereignis über das Schlüsselwort Implements das Interface IEreignis hinzu.
- Dadurch müssen wir alle Elemente dieses Interfaces auch implementieren. Dass die Methode EreignisAusloesen der Klasse Ereignis die gleichnamige Methode EreignisAusloesen der Schnittstelle IEreignis implementiert, legen wir dabei durch den Zusatz Implements IEreignis.EreignisAusloesen fest.
Für das Interface IEreignisEvents müssen wir lediglich das Attribut
Wir können dann mit Public Event Ereignis() das Ereignis definieren.
Die Klasse Ereignis sieht nun wie folgt aus:
<ClassInterface(ClassInterfaceType.None)> <ComSourceInterfaces(GetType(IEreignisEvents))> Public Class Ereignis Implements IEreignis Public Event Ereignis() Public Sub EreignisAusloesen() _ Implements IEreignis.EreignisAusloesen RaiseEvent Ereignis() End Sub End Class
Zwischenstand
Wir haben nun also drei Elemente:
- Ein Interface für die Eigenschaften und Methoden namens IEreignis,
- ein Interface für die Ereignisse namens IEreignisEvents und
- eine Klasse, welche die beiden Interfaces implementiert.
COM-DLL erstellen
Damit können wir die COM-DLL nun erstellen. Das erledigen wir mit dem Befehl Erstellen|amvEvents erstellen. Alternativ können wir dazu die Tastenkombination Strg + B nutzen.
Voraussetzung für das Erstellen ist, dass Visual Studio im Administrator-Modus geöffnet wurde. Falls nicht, erscheint eine Fehlermeldung und wir müssen Visual Studio erneut starten – diesmal mit Administrator-Berechtigungen.
Wichtig ist außerdem, dass Du die COM-DLL mit der gleichen Bitness erzeugst, die auch Deine Office-Installation aufweist.
Wenn Du Office in der 32-Bit-Version nutzt, musst Du in den Projekteigenschaften unter Kompilieren die Eigenschaft Ziel-CPU auf x86 einstellen (siehe Bild 7).
Bild 7: Einstellen der Ziel-Bitness
Möchtest Du hingegen für Office in der 64-Bit-Version kompilieren, benötigst Du die Einstellung x64.
Dass Du die falsche Bitness verwendet hast, erkennst Du daran, dass zwar die COM-DLL als Verweis eingebunden werden kann, dann aber bei der Benutzung Fehler wirft – zum Beispiel den aus Bild 8. Der Fehler ist nicht unbedingt selbsterklärend, deshalb weisen wir hier gezielt darauf hin.
Ende des frei verfügbaren Teil. Wenn Du mehr lesen möchtest, hole Dir ...
den kompletten Artikel im PDF-Format mit Beispieldatenbank
diesen und alle anderen Artikel mit dem Jahresabo