{"id":55000473,"date":"2025-06-01T00:00:00","date_gmt":"2025-08-27T13:52:44","guid":{"rendered":"http:\/\/access-im-unternehmen.aix-dev.de\/aiu\/?p=473"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-30T00:00:00","slug":"Ereignisse_aus_VBNETCOMDLLs_implementieren","status":"publish","type":"post","link":"https:\/\/vbentwickler.de\/Ereignisse_aus_VBNETCOMDLLs_implementieren\/","title":{"rendered":"Ereignisse aus VB.NET-COM-DLLs implementieren"},"content":{"rendered":"<p><b>Viele Szenarien, in denen man eine COM-DLL ben&ouml;tigt, kann man mit einer VB6-COM-DLL auf Basis von twinBASIC abbilden. Manchmal m&ouml;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&ouml;nnen.<\/b><\/p>\n<h2>Beispielprojekt anlegen<\/h2>\n<p>Um das Beispielprojekt zu erstellen, ben&ouml;tigen wir Visual Studio, zum Beispiel in der Version 2022. Hier legen wir ein neues Projekt an und w&auml;hlen dazu den Typ <b>Klassenbibliothek (.NET-Framework) <\/b>aus (siehe Bild 1).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_03\/pic_473_001.png\" alt=\"Projekttyp f&uuml;r das neue Projekt ausw&auml;hlen\" width=\"700\" height=\"491,5727\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 1: Projekttyp f&uuml;r das neue Projekt ausw&auml;hlen<\/span><\/b><\/p>\n<h2>Name festlegen<\/h2>\n<p>Anschlie&szlig;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&uuml;r die Eigenschaft <b>Name<\/b> den Wert <b>amvEvents <\/b>ein (siehe Bild 2).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_03\/pic_473_002.png\" alt=\"Projekteigenschaften vor dem Speichern festlegen\" width=\"700\" height=\"405,0559\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 2: Projekteigenschaften vor dem Speichern festlegen<\/span><\/b><\/p>\n<h2>Klasse umbenennen<\/h2>\n<p>Im nun erscheinenden Projekt-Explorer benennen wir als Erstes die Klasse <b>Class1.vb<\/b> in <b>Ereignis.vb <\/b>um. Visual Studio fragt uns nun, ob wir auch die Verweise auf das entsprechende Code-Element anpassen wollen, was wir best&auml;tigen (siehe Bild 3).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_03\/pic_473_003.png\" alt=\"Umbenennen der Klasse des Projekts\" width=\"700\" height=\"320,2759\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 3: Umbenennen der Klasse des Projekts<\/span><\/b><\/p>\n<h2>Assemblyinformationen anpassen<\/h2>\n<p>Damit kommen wir zu einigen Einstellungen, die f&uuml;r die Verwendung des Projekts als COM-DLL wichtig sind.<\/p>\n<p>Als Erstes klicken wir im Projektmappen-Explorer doppelt auf den Eintrag <b>My Project<\/b>.<\/p>\n<p>Dies &ouml;ffnet den Bereich mit den Eigenschaften des Projekts. Hier sehen wir unter <b>Anwendung <\/b>die Schaltfl&auml;che <b>Assemblyinformationen&#8230;<\/b> (siehe Bild 4).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_03\/pic_473_004.png\" alt=\"Bearbeiten der Projekteigenschaften\" width=\"499,6267\" height=\"419,7269\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 4: Bearbeiten der Projekteigenschaften<\/span><\/b><\/p>\n<p>Diese klicken wir an und &ouml;ffnen so den Dialog <b>Assemblyinformationen<\/b>. Hier aktivieren wir im unteren Bereich die Option <b>Assembly COM-sichtbar machen <\/b>(siehe Bild 5).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_03\/pic_473_005.png\" alt=\"Aktivieren der COM-Sichtbarkeit\" width=\"599,6265\" height=\"427,1721\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 5: Aktivieren der COM-Sichtbarkeit<\/span><\/b><\/p>\n<p>Nachdem wir den Dialog wieder geschlossen haben, wechseln wir in den Projekt-Optionen zum Bereich <b>Kompilieren<\/b>. Hier finden wir ganz unten die Option <b>F&uuml;r COM-Interop registrieren<\/b>. Indem wir diese aktivieren, sorgen wir daf&uuml;r, dass die COM-DLL beim Erstellen in die Registry eingetragen wird, sodass sie f&uuml;r den Zugriff von VBA aus verf&uuml;gbar ist (siehe Bild 6).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_03\/pic_473_006.png\" alt=\"Aktivieren der Registrierung f&uuml;r COM-Interop\" width=\"599,6265\" height=\"494,1647\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 6: Aktivieren der Registrierung f&uuml;r COM-Interop<\/span><\/b><\/p>\n<p>Damit haben wir die Vorbereitungen abgeschlossen und k&ouml;nnen uns dem eigentlichen Programmieren zuwenden.<\/p>\n<h2>Beispiel f&uuml;r ein COM-DLL-Ereignis programmieren<\/h2>\n<p>Das Ziel der folgenden Schritte ist die Programmierung des einfachsten denkbaren Beispiels f&uuml;r das Bereitstellen eines Ereignisses durch die COM-DLL. Dazu wollen wir die folgende Struktur realisieren:<\/p>\n<ul>\n<li>Programmierung eines Ereignisses mit dem Schl&uuml;sselwort <b>Event<\/b>, so wie es auch in VBA realisierbar ist<\/li>\n<li>Hinzuf&uuml;gen einer &ouml;ffentlichen Methode, mit der wir das Ereignis ausl&ouml;sen k&ouml;nnen.<\/li>\n<\/ul>\n<p>Damit die Elemente der COM-DLL optimal im VBA-Editor genutzt werden k&ouml;nnen, k&ouml;nnen wir nicht einfach eine Klasse mit der Definition des Ereignisses und der ausl&ouml;senden Methode programmieren.<\/p>\n<p>Unter VBA k&ouml;nnten wir das etwa wie folgt in einem Klassenmodul programmieren:<\/p>\n<pre><span style=\"color:blue;\">Public <\/span>Event Ereignis()\r\n<span style=\"color:blue;\">Public Sub <\/span>EreignisAusloesen()\r\n     RaiseEvent Ereignis()\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>In VB.NET reicht das aber nicht aus. Hier ben&ouml;tigen wir einige weitere Elemente, damit das Ereignis problemlos funktioniert und nicht mehr Elemente als n&ouml;tig unter VBA angezeigt werden. Die Klasse wird in Listing 1 im &Uuml;berblick dargestellt, in den folgenden Abschnitten erl&auml;utern wir die einzelnen Elemente.<\/p>\n<pre>Imports System.Runtime.InteropServices\r\n&lt;InterfaceType(ComInterfaceType.InterfaceIsDual)&gt;\r\n<span style=\"color:blue;\">Public <\/span>Interface IEreignis\r\n     Sub EreignisAusloesen()\r\nEnd Interface\r\n&lt;InterfaceType(ComInterfaceType.InterfaceIsIDispatch)&gt;\r\n<span style=\"color:blue;\">Public <\/span>Interface IEreignisEvents\r\n     Sub Ereignis()\r\nEnd Interface\r\n&lt;ClassInterface(ClassInterfaceType.None)&gt;\r\n&lt;ComSourceInterfaces(GetType(IEreignisEvents))&gt;\r\n<span style=\"color:blue;\">Public Class<\/span> Ereignis\r\n     Implements IEreignis\r\n     <span style=\"color:blue;\">Public <\/span>Event Ereignis()\r\n     <span style=\"color:blue;\">Public <\/span>Sub EreignisAusloesen() Implements IEreignis.EreignisAusloesen\r\n         RaiseEvent Ereignis()\r\n     End Sub\r\n<span style=\"color:blue;\">End Class<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 1: Die Klasse Ereignis im &Uuml;berblick<\/span><\/b><\/p>\n<h2>Notwendiger Namespace: InteropServices<\/h2>\n<p>Damit wir die gleich im Detail beschriebenen speziellen COM-Interfaces verwenden k&ouml;nnen, f&uuml;gen wir dem Modul als erste Zeile den Import des Namensraums <b>System.Runtime.InteropServices <\/b>hinzu:<\/p>\n<pre>Imports System.Runtime.InteropServices<\/pre>\n<h2>Trennung von COM-Methoden und COM-Ereignissen<\/h2>\n<p>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&szlig;en sichtbar werden &#8211; zum Beispiel unter VBA.<\/p>\n<p>Wenn wir kein Interface verwenden w&uuml;rden, sehen wir unter VBA unn&ouml;tige Elemente wie <b>Equals<\/b>, <b>GetHashCode <\/b>oder <b>GetType<\/b>. Diese ben&ouml;tigen wir aber nicht und sie machen die Auswahl der Elemente per IntelliSense auch noch un&uuml;bersichtlicher. Das ist also der Grund, warum wir ein Interface wie das folgende definieren:<\/p>\n<pre>&lt;InterfaceType(ComInterfaceType.InterfaceIsDual)&gt;\r\n<span style=\"color:blue;\">Public <\/span>Interface IEreignis\r\n     Sub EreignisAusloesen()\r\nEnd Interface<\/pre>\n<p>Hier legen wir zun&auml;chst den Typ des Interfaces fest, und zwar <b>ComInterfaceType.InterfaceIsDual<\/b>. damit stellen wir sicher, dass alle in diesem Interface deklarierten Methoden, Eigenschaften und so weiter auch unter VBA angezeigt und verwendet werden k&ouml;nnen &#8211; sowohl per IntelliSense als auch im Objektkatalog.<\/p>\n<p>Hier sehen wir allerdings nur die Methode <b>EreignisAusloesen<\/b> und nicht die Definition des Ereignisses selbst. Dieses m&uuml;ssen wir in einem eigenen Interface definieren.<\/p>\n<p>F&uuml;r dieses verwenden wir wiederum einen anderen Interface-Typ, n&auml;mlich <b>ComInterfaceType.InterfaceIsDispatch<\/b>. Nur so k&ouml;nnen wir Ereignisse empfangen. Das Ereignis definieren wir durch eine einfache <b>Sub<\/b>-Definition wie folgt:<\/p>\n<pre>&lt;InterfaceType(ComInterfaceType.InterfaceIsIDispatch)&gt;\r\n<span style=\"color:blue;\">Public <\/span>Interface IEreignisEvents\r\n     Sub Ereignis()\r\nEnd Interface<\/pre>\n<h2>Logik der Klasse und Implementierung der Elemente<\/h2>\n<p>Schlie&szlig;lich folgt die eigentliche Logik beziehungsweise die Implementierung der beiden Elemente, also der Methode und des Ereignisses.<\/p>\n<p>Dies geschieht in der eigentlichen Klasse <b>Ereignis<\/b>, die das Interface <b>IEreignis <\/b>mit der Methode <b>EreignisAusloesen <\/b>implementiert. Diese Klasse deklarieren wir als Klassen-Interface mit dem Typ <b>ClassInterfaceType.None<\/b>. Die Elemente dieser Klasse werden dadurch nicht automatisch ver&ouml;ffentlicht und erscheinen somit nicht im VBA-Projekt, wenn wir diesem einen Verweis auf die COM-DLL hinzuf&uuml;gen. Das ist auch nicht n&ouml;tig, denn alle Elemente haben wir bereits &uuml;ber die zuvor beschriebenen Elemente mit den Interface-Typen <b>InterfaceIsDual <\/b>(f&uuml;r die Eigenschaften und Methoden) sowie <b>InterfaceIsDispatch <\/b>(f&uuml;r die Ereignisse) ver&ouml;ffentlicht.<\/p>\n<p>Wie aber machen wir in dieser Klasse kenntlich, durch welche &ouml;ffentlichen Elemente die Methode und das Ereignis nach au&szlig;en verf&uuml;gbar gemacht werden?<\/p>\n<p>F&uuml;r das Interface <b>IEreignis <\/b>gelingt dies durch zwei Ma&szlig;nahmen:<\/p>\n<ul>\n<li>Wir f&uuml;gen der Klasse <b>Ereignis <\/b>&uuml;ber das Schl&uuml;sselwort <b>Implements <\/b>das Interface <b>IEreignis <\/b>hinzu.<\/li>\n<li>Dadurch m&uuml;ssen wir alle Elemente dieses Interfaces auch implementieren. Dass die Methode <b>EreignisAusloesen <\/b>der Klasse <b>Ereignis <\/b>die gleichnamige Methode <b>EreignisAusloesen <\/b>der Schnittstelle <b>IEreignis <\/b>implementiert, legen wir dabei durch den Zusatz <b>Implements IEreignis.EreignisAusloesen <\/b>fest.<\/li>\n<\/ul>\n<p>F&uuml;r das Interface <b>IEreignisEvents <\/b>m&uuml;ssen wir lediglich das Attribut <b><ComSourceInterfaces(GetType(IEreignisEvents))> <\/b>&uuml;ber der Klasse angeben.<\/p>\n<p>Wir k&ouml;nnen dann mit <b>Public Event Ereignis() <\/b>das Ereignis definieren.<\/p>\n<p>Die Klasse <b>Ereignis <\/b>sieht nun wie folgt aus:<\/p>\n<pre>&lt;ClassInterface(ClassInterfaceType.None)&gt;\r\n&lt;ComSourceInterfaces(GetType(IEreignisEvents))&gt;\r\n<span style=\"color:blue;\">Public Class<\/span> Ereignis\r\n     Implements IEreignis\r\n     <span style=\"color:blue;\">Public <\/span>Event Ereignis()\r\n     <span style=\"color:blue;\">Public <\/span>Sub EreignisAusloesen() _\r\n             Implements IEreignis.EreignisAusloesen\r\n         RaiseEvent Ereignis()\r\n     End Sub\r\n<span style=\"color:blue;\">End Class<\/span><\/pre>\n<h2>Zwischenstand<\/h2>\n<p>Wir haben nun also drei Elemente:<\/p>\n<ul>\n<li>Ein Interface f&uuml;r die Eigenschaften und Methoden namens <b>IEreignis<\/b>,<\/li>\n<li>ein Interface f&uuml;r die Ereignisse namens <b>IEreignisEvents <\/b>und<\/li>\n<li>eine Klasse, welche die beiden Interfaces implementiert.<\/li>\n<\/ul>\n<h2>COM-DLL erstellen<\/h2>\n<p>Damit k&ouml;nnen wir die COM-DLL nun erstellen. Das erledigen wir mit dem Befehl <b>Erstellen|amvEvents <\/b>erstellen. Alternativ k&ouml;nnen wir dazu die Tastenkombination <b>Strg + B <\/b>nutzen.<\/p>\n<p>Voraussetzung f&uuml;r das Erstellen ist, dass Visual Studio im Administrator-Modus ge&ouml;ffnet wurde. Falls nicht, erscheint eine Fehlermeldung und wir m&uuml;ssen Visual Studio erneut starten &#8211; diesmal mit Administrator-Berechtigungen.<\/p>\n<p>Wichtig ist au&szlig;erdem, dass Du die COM-DLL mit der gleichen Bitness erzeugst, die auch Deine Office-Installation aufweist.<\/p>\n<p>Wenn Du Office in der 32-Bit-Version nutzt, musst Du in den Projekteigenschaften unter Kompilieren die Eigenschaft Ziel-CPU auf <b>x86<\/b> einstellen (siehe Bild 7).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_03\/pic_473_007.png\" alt=\"Einstellen der Ziel-Bitness\" width=\"499,6267\" height=\"419,7269\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 7: Einstellen der Ziel-Bitness<\/span><\/b><\/p>\n<p>M&ouml;chtest Du hingegen f&uuml;r Office in der 64-Bit-Version kompilieren, ben&ouml;tigst Du die Einstellung <b>x64<\/b>.<\/p>\n<p>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 &#8211; zum Beispiel den aus Bild 8. Der Fehler ist nicht unbedingt selbsterkl&auml;rend, deshalb weisen wir hier gezielt darauf hin.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_03\/pic_473_008.png\" alt=\"Fehler bei falscher Bitness\" width=\"499,6267\" height=\"411,4088\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 8: Fehler bei falscher Bitness<\/span><\/b><\/p>\n<p>Das Erstellen legt die DLL an und f&uuml;gt entsprechende Eintr&auml;ge zur Registry hinzu, damit zum Beispiel der VBA-Editor diese &uuml;ber den <b>Verweise<\/b>-Dialog anzeigen kann.<\/p>\n<h2>COM-DLL in ein VBA-Projekt einbinden<\/h2>\n<p>Damit k&ouml;nnen wir eine Access-Anwendung starten und den VBA-Editor anzeigen (zum Beispiel mit <b>Alt + F11<\/b>).<\/p>\n<p>Hier f&uuml;gen wir einen Verweis auf die Bibliothek <b>amvEvents <\/b>hinzu (siehe Bild 9).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_03\/pic_473_009.png\" alt=\"Hinzuf&uuml;gen eines Verweises auf die COM-DLL\" width=\"424,6267\" height=\"334,749\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 9: Hinzuf&uuml;gen eines Verweises auf die COM-DLL<\/span><\/b><\/p>\n<p>Schauen wir uns die Bibliothek <b>amvEvents <\/b>im Objektkatalog an, finden wir die Klasse <b>Ereignis <\/b>mit der Methode <b>EreignisAusloesen <\/b>und dem Ereignis <b>Ereignis<\/b> (siehe Bild 10).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_03\/pic_473_010.png\" alt=\"Objektkatalog mit den Elementen der Ereignis-Klasse\" width=\"424,6267\" height=\"357,1707\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 10: Objektkatalog mit den Elementen der Ereignis-Klasse<\/span><\/b><\/p>\n<h2>Ereignis per Formular ausl&ouml;sen <\/h2>\n<p>Nun legen wir ein Formular an und f&uuml;gen diesem eine Schaltfl&auml;che namens <b>cmdEreignisAusloesen <\/b>hinzu. (siehe Bild 11). Warum ein Formular und nicht einfach ein Standardmodul? Weil wir die Klasse <b>Ereignis <\/b>mit dem Schl&uuml;sselwort <b>WithEvents <\/b>deklarieren m&uuml;ssen, um das Ereignis implementieren zu k&ouml;nnen &#8211; und das gelingt nur in einem Klassenmodul. Hier liegt ein Formular-Klassenmodul f&uuml;r Beispielzwecke n&auml;her als die Erstellung eines alleinstehenden Klassenmoduls, das wir noch initialisieren m&uuml;ssten.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_03\/pic_473_011.png\" alt=\"Formular zum Testen des Ereignisses\" width=\"424,6267\" height=\"211,8701\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 11: Formular zum Testen des Ereignisses<\/span><\/b><\/p>\n<p>Im Klassenmodul des Formulars f&uuml;gen wir nun zun&auml;chst eine Variable f&uuml;r die Klasse <b>amvEvents.Ereignis <\/b>hinzu, die wir <b>objEreignis <\/b>nennen und mit dem bereits erw&auml;hnten Schl&uuml;sselwort <b>WithEvents <\/b>deklarieren:<\/p>\n<pre><span style=\"color:blue;\">Private <\/span>WithEvents objEreignis<span style=\"color:blue;\"> As <\/span>amvEvents.Ereignis<\/pre>\n<p>Dann f&uuml;gen wir f&uuml;r die Ereigniseigenschaft <b>Beim Laden <\/b>die folgende Prozedur hinzu, die ein Objekt auf Basis von <b>amvEvents.Ereignis <\/b>initialisiert:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_Load()\r\n     <span style=\"color:blue;\">Set<\/span> objEreignis = <span style=\"color:blue;\">New<\/span> amvEvents.Ereignis\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Au&szlig;erdem m&uuml;ssen wir das Ereignis implementieren. Dazu w&auml;hlen wir im linken Kombinationsfeld im Code-Fenster den Eintrag <b>objEreignis<\/b>, wodurch im rechten Kombinationsfeld automatisch das Ereignis <b>Ereignis <\/b>ausgew&auml;hlt und die passende Ereignisprozedur angelegt wird (siehe Bild 12).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_03\/pic_473_012.png\" alt=\"Implementieren des Ereignisses\" width=\"499,6267\" height=\"287,7597\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 12: Implementieren des Ereignisses<\/span><\/b><\/p>\n<p>Diese erg&auml;nzen wir durch eine einfache Meldungsbox:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>objEreignis_Ereignis()\r\n     <span style=\"color:blue;\">MsgBox<\/span> \"Ereignis ausgel&ouml;st\"\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Nun m&uuml;ssen wir nur noch daf&uuml;r sorgen, dass das Ereignis ausgel&ouml;st wird.<\/p>\n<p>Dazu f&uuml;gen wir der Schaltfl&auml;che eine Ereignisprozedur hinzu, welche die Methode <b>EreignisAusloesen <\/b>von <b>objEreignis <\/b>aufruft:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>cmdEreignisAusloesen_Click()\r\n     objEreignis.EreignisAusloesen\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Was geschieht nun? Die Methode <b>EreignisAusloesen <\/b>ruft die entsprechende <b>Sub<\/b>-Prozedur in der COM-DLL auf. Diese wiederum l&ouml;st mit <b>RaiseEvent Ereignis() <\/b>das Ereignis aus. Dadurch wird die in unserem Modul definierte Ereignisprozedur <b>objEreignis_Ereignis <\/b>ausgel&ouml;st. Wir haben also ein funktionierendes in unserer COM-DLL programmiert.<\/p>\n<p>Den Ablauf haben wir in Bild 13 &uuml;bersichtlich skizziert. Das <b>Click<\/b>-Ereignis der Schaltfl&auml;che wird an das Interface <b>IEreignis <\/b>weitergeleitet, von wo aus es die Implementierung <b>EreignisAusloesen <\/b>aufruft. Dies startet mit <b>RaiseEvent <\/b>das Ereignis, was wiederum &uuml;ber das <b>InterfaceIEreignisEvents <\/b>&ouml;ffentlich bereitgestellt und von der Ereignisprozedur <b>objEreignis_Ereignis <\/b>implementiert wird.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_03\/pic_473_013.png\" alt=\"Ablauf des Codes\" width=\"700\" height=\"362,6852\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 13: Ablauf des Codes<\/span><\/b><\/p>\n<h2>Einsatzm&ouml;glichkeiten<\/h2>\n<p>Wir haben hier einen einfachen Einsatzzweck genutzt, der keinen echten Nutzen hat. Wir k&ouml;nnen das Beispiel jedoch beliebig erweitern, zum Beispiel, indem wir hinter die Prozedur <b>EreignisAusloesen <\/b>eine echte, gegebenenfalls l&auml;nger dauernde Routine integrieren &#8211; zum Beispiel, um Daten aus dem Internet herunterzuladen, Dateien zu generieren, einen Export oder Import zu beginnen oder einen Timer zu starten.<\/p>\n<p>Mit dem Ereignis <b>Ereignis <\/b>k&ouml;nnen wir dann an Access zur&uuml;ckmelden, wenn die gew&uuml;nschten Aufgaben durch die COM-DLL durchgef&uuml;hrt wurden.<\/p>\n<p>In Access k&ouml;nnen wir darauf reagieren, indem wir beispielsweise die Anzeige aktualisieren und das Ergebnis mitteilen. Oder wir f&uuml;hren daraufhin in Access weitere Aktionen aus, welche auf dem Ergebnis der COM-DLL basieren.<\/p>\n<h2>Erweiterung: Ereignis mit Parametern<\/h2>\n<p>Wer schon einmal die Ereignisse von Access-Formularen programmiert hat, der wei&szlig;:<\/p>\n<ul>\n<li>Ereignisprozeduren k&ouml;nnen per Parameter Informationen liefern wie beispielsweise die Mausposition bei Ereignissen wie <b>MouseDown<\/b> oder <b>MouseUp <\/b>oder die gedr&uuml;ckte Taste bei <b>KeyDown <\/b>oder <b>KeyUp<\/b>.<\/li>\n<li>Sie k&ouml;nnen aber auch Parameter entgegennehmen wie etwa den Parameter <b>Cancel <\/b>im Ereignis <b>Form_Open<\/b>, der das Abbrechen des &Ouml;ffnens eines Formulars erlaubt.<\/li>\n<\/ul>\n<p>Wie k&ouml;nnen wir solche Parameter in VB.NET-COM-DLLs realisieren? Bei Parametern, welche die COM-DLL liefern soll, also solchen mit dem Schl&uuml;sselwort <b>ByVal<\/b>, gelingt dies ganz einfach.<\/p>\n<p>Wir f&uuml;gen dazu ein neues Ereignis namens <b>EreignisByVal <\/b>zum Interface <b>IEreignis <\/b>des VB.NET-Projekts hinzu:<\/p>\n<pre>&lt;InterfaceType(ComInterfaceType.InterfaceIsDual)&gt;\r\n<span style=\"color:blue;\">Public <\/span>Interface IEreignis\r\n     Sub EreignisAusloesen()\r\n     Sub EreignisByValAusloesen(ByVal strText<span style=\"color:blue;\"> As String<\/span>)\r\nEnd Interface<\/pre>\n<p>Dem Interface <b>IEreignis <\/b>f&uuml;gen wir die entsprechende Methode hinzu:<\/p>\n<pre>&lt;InterfaceType(ComInterfaceType.InterfaceIsIDispatch)&gt;\r\n<span style=\"color:blue;\">Public <\/span>Interface IEreignisEvents\r\n     Sub Ereignis()\r\n     Sub EreignisByVal(ByVal strText<span style=\"color:blue;\"> As String<\/span>)\r\nEnd Interface<\/pre>\n<p>Und schlie&szlig;lich erweitern wir die Klasse <b>Ereignis <\/b>um ein neues Event und eine neue <b>Sub<\/b>-Prozedur:<\/p>\n<pre>&lt;ComVisible(<span style=\"color:blue;\">False<\/span>)&gt;\r\n<span style=\"color:blue;\">Public <\/span>Delegate Sub EreignisEventHandler()\r\n&lt;ClassInterface(ClassInterfaceType.None)&gt;\r\n&lt;ComSourceInterfaces(GetType(IEreignisEvents))&gt;\r\n<span style=\"color:blue;\">Public Class<\/span> Ereignis\r\n     Implements IEreignis\r\n     <span style=\"color:blue;\">Public <\/span>Event Ereignis()\r\n     <span style=\"color:blue;\">Public <\/span>Event EreignisByVal(ByVal strText<span style=\"color:blue;\"> As String<\/span>)\r\n     <span style=\"color:blue;\">Public <\/span>Sub EreignisAusloesen() _\r\n             Implements IEreignis.EreignisAusloesen\r\n         RaiseEvent Ereignis()\r\n     End Sub\r\n     <span style=\"color:blue;\">Public <\/span>Sub EreignisByValAusloesen(strText<span style=\"color:blue;\"> As String<\/span>) _\r\n             Implements IEreignis.EreignisByValAusloesen\r\n         RaiseEvent EreignisByVal(strText)\r\n     End Sub\r\n<span style=\"color:blue;\">End Class<\/span><\/pre>\n<p>Dem Formular f&uuml;gen wir eine Schaltfl&auml;che namens <b>cmdEreignisMitByVal <\/b>hinzu, f&uuml;r das wir das folgende <b>Beim Klicken<\/b>-Ereignis hinzuf&uuml;gen. Damit rufen wir die Methode <b>EreignisByValAusloesen <\/b>auf und &uuml;bergeben den Text aus dem ebenfalls neu hinzugef&uuml;gten Textfeld:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>cmdEreignisMitByVal_Click()\r\n     <span style=\"color:blue;\">Call<\/span> objEreignis.EreignisByValAusloesen( _\r\n         Me.txtZuUebergebenderText)\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Au&szlig;erdem implementieren wir das Ereignis <b>EreignisByVal<\/b>, welches den Parameter <b>strText <\/b>liefern soll, und geben diesen Text in einer Meldungsbox aus:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>objEreignis_EreignisByVal( _\r\n         ByVal strText<span style=\"color:blue;\"> As String<\/span>)\r\n     <span style=\"color:blue;\">MsgBox<\/span> \"&Uuml;bergebener Text: \" & strText\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Durch einen Klick auf die Schaltfl&auml;che l&ouml;sen wir in der COM-DLL das Ereignis <b>EreignisByVal <\/b>aus, das den &uuml;bergebenen Wert zur&uuml;ckliefert (siehe Bild 14).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_03\/pic_473_014.png\" alt=\"Ereignis mit &Uuml;bergabe eines Wertes per ByVal\" width=\"499,6267\" height=\"297,1758\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 14: Ereignis mit &Uuml;bergabe eines Wertes per ByVal<\/span><\/b><\/p>\n<h2>Anwendungszweck<\/h2>\n<p>Normalerweise w&uuml;rden wir keinen Wert an die DLL &uuml;bergeben, den wir dann zur&uuml;ckgeben lassen. Stattdessen w&uuml;rden wir andere Informationen zur&uuml;ckliefern &#8211; zum Beispiel das Ergebnis einer Aktion wie beispielsweise dem Aufrufen einer Rest-API.<\/p>\n<h2>Parameter an eine ausgel&ouml;ste Ereignisprozedur &uuml;bergeben<\/h2>\n<p>Nun zeigen wir noch, wie man einen Wert an ein ausgel&ouml;stes Ereignis zur&uuml;ckgeben kann.<\/p>\n<p>Dazu f&uuml;gen wir im VB.NET-Projekt zun&auml;chst eine Methode hinzu, mit der wir das Ereignis ausl&ouml;sen wollen:<\/p>\n<pre>&lt;InterfaceType(ComInterfaceType.InterfaceIsDual)&gt;\r\n<span style=\"color:blue;\">Public <\/span>Interface IEreignis\r\n     ...\r\n     Sub EreignisByRefAusloesen()\r\nEnd Interface<\/pre>\n<p>Im Interface <b>IEreignisEvents <\/b>f&uuml;gen wir entsprechend die Definition des Ereignisses hinzu:<\/p>\n<pre>&lt;InterfaceType(ComInterfaceType.InterfaceIsIDispatch)&gt;\r\n<span style=\"color:blue;\">Public <\/span>Interface IEreignisEvents\r\n     ...\r\n     Sub EreignisByRef(ByRef strText<span style=\"color:blue;\"> As String<\/span>)\r\nEnd Interface<\/pre>\n<p>Und in der Klasse <b>Ereignis <\/b>definieren wir das Ereignis sowie die ausl&ouml;sende Prozedur wie folgt:<\/p>\n<pre>&lt;ClassInterface(ClassInterfaceType.None)&gt;\r\n&lt;ComSourceInterfaces(GetType(IEreignisEvents))&gt;\r\n<span style=\"color:blue;\">Public Class<\/span> Ereignis\r\n     Implements IEreignis\r\n     ...\r\n     <span style=\"color:blue;\">Public <\/span>Event EreignisByRef(ByRef strText<span style=\"color:blue;\"> As String<\/span>)\r\n     ...\r\n     <span style=\"color:blue;\">Public <\/span>Sub EreignisByRefAusloesen() _\r\n         Implements IEreignis.EreignisByRefAusloesen\r\n         <span style=\"color:blue;\">Dim <\/span>strText<span style=\"color:blue;\"> As String<\/span>\r\n         RaiseEvent EreignisByRef(strText)\r\n         <span style=\"color:blue;\">MsgBox<\/span>(\"Es wurde der Wert ''\" & strText _\r\n             & \"'' an das Ereignis &uuml;bergeben.\")\r\n     End Sub\r\n<span style=\"color:blue;\">End Class<\/span><\/pre>\n<p>W&auml;hrend wir das Ereignis mit dem Schl&uuml;sselwort Event mit einem als <b>ByRef <\/b>versehenen Parameter anlegen, stellt sich die Frage, wo und wie wir den von Access beim Ausl&ouml;sen des Ereignisses zur&uuml;ckgegebenen Parameter auswerten.<\/p>\n<p>Dies geschieht in der Prozedur, welche das Ereignis ausl&ouml;st. Diese kann den Parameter auslesen und soll ihn in diesem Fall per Meldungsfenster ausgeben.<\/p>\n<p>Nach dem Kompilieren passen wir wiederum das Access-Formular an. Diesem f&uuml;gen wir eine weitere Schaltfl&auml;che namens <b>cmdEreignisMitByRef <\/b>hinzu, f&uuml;r deren <b>Beim Klicken<\/b>-Ereigniseigenschaft wir die folgende Prozedur hinterlegen:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>cmdEreignisMitByRef_Click()\r\n     <span style=\"color:blue;\">Call<\/span> objEreignis.EreignisByRefAusloesen\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Au&szlig;erdem implementieren wir nun das Ereignis <b>EreignisByRef <\/b>von <b>objEreignis<\/b>, wobei wir nun f&uuml;r den Parameter <b>strText <\/b>den Inhalt des Textfeldes &uuml;bergeben:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>objEreignis_EreignisByRef(strText<span style=\"color:blue;\"> As String<\/span>)\r\n     strText = Me.txtZuUebergebenderText\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Damit l&ouml;sen wir bei Anklicken das Ereignis aus, dem wir f&uuml;r den Parameter <b>strText <\/b>den Inhalt des Textfeldes &uuml;bergeben. Dieser wird dann von der COM-DLL verarbeitet und per <b>MsgBox<\/b> ausggeben.<\/p>\n<h2>Zusammenfassung und Ausblick<\/h2>\n<p>Dieser Artikel zeigt, wie man Ereignisse in einer COM-DLL programmiert und wie man diese von Access aus einem VBA-Projekt heraus nutzen kann. Zus&auml;tzlich haben wir gezeigt, wie man Parameter von einem solchen Ereignis erh&auml;lt und wie man Parameter an das Ereignis zur&uuml;ckgeben kann.<\/p>\n<h2>Downloads zu diesem Beitrag<\/h2>\n<p>Enthaltene Beispieldateien:<\/p>\n<p>amvEvents.zip<\/p>\n<p>EreignisseAusVBNETCOMDLLsImplementieren.accdb<\/p>\n<p><a href=\"..\/fileadmin\/beispiele\/D4D0E6D1-0BE6-43D5-8FC2-21D3028568AF\/vbe_473.zip\">Download<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Viele Szenarien, in denen man eine COM-DLL ben&ouml;tigt, kann man mit einer VB6-COM-DLL auf Basis von twinBASIC abbilden. Manchmal m&ouml;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&ouml;nnen.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_uf_show_specific_survey":0,"_uf_disable_surveys":false,"footnotes":""},"categories":[662025,66032025,44000035],"tags":[],"yst_prominent_words":[],"class_list":["post-55000473","post","type-post","status-publish","format-standard","hentry","category-662025","category-66032025","category-COMDLLs_programmieren"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/posts\/55000473","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/comments?post=55000473"}],"version-history":[{"count":0,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/posts\/55000473\/revisions"}],"wp:attachment":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/media?parent=55000473"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/categories?post=55000473"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/tags?post=55000473"},{"taxonomy":"yst_prominent_words","embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/yst_prominent_words?post=55000473"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}