Im Beitrag „Besserer Suchen und Ersetzen-Dialog“ haben wir den Dialog zum Suchen und Ersetzen in Access-Formularen nachgebaut und um einige Features ergänzt. Nun wollen wir unseren selbst gebauten Dialog noch für jede Access-Anwendung verfügbar machen. Was liegt da näher, als diesen über das Ribbon aufzurufen? Um eine solche Erweiterung für jede geöffnete Anwendung verfügbar zu machen und so flexibel wie möglich zu sein, verwenden wir dazu ein COM-Add-In. Dieses enthält lediglich die Erweiterung des Ribbons um die benötigten Befehlsschaltflächen sowie den Code, um von dort aus den „Suchen und Ersetzen“-Dialog zu starten.
COM-Add-Ins erstellen mit twinBASIC
Unsere erste Wahl für das komfortable Erstellen von COM-Add-Ins für Microsoft Access ist twinBASIC. Diese Entwicklungsumgebung ist in der 32-Bit-Version kostenlos und 64-Bit-DLLs können ebenfalls damit erstellt werden – in der kostenlosen Version erscheint hier allerdings ein Splash-Screen des Herstellers.
Den jeweils aktuellen Release kann man hier herunterladen:
https://github.com/twinbasic/twinbasic/releases
Hier klickt man auf den gewünschten Release und lädt beispielsweise für den Release mit der Nummer 784 die Datei twinBASIC_IDE_BETA_784.zip herunter.
Den Inhalt entpackt man in ein neues, leeres Verzeichnis. Es ist keine weitere Installation notwendig, wir brauchen einfach nur die Datei twinBASIC.exe zu starten. Nach dem Start erscheint ein Startdialog, in dem wir zur Registerseite Samples wechseln. Hier finden wir den Eintrag Sample 5. MYCOMAddIn, den wir doppelt anklicken (siehe Bild 1).
Bild 1: Anlegen eines COM-Add-In-Projekts mit Beispiel
Danach erscheint ein weiterer Dialog namens twinBASIC New Project Options. Hier passen wir den Projektnamen an, in diesem Fall auf amvSuchenUndErsetzen (siehe Bild 2).
Bild 2: Angeben des Projektnamens
twinBASIC erstellt nun in wenigen Augenblicken das neue Projekt und öffnet das Modul MyCOMAddin.twin.
Verweise hinzufügen
Da wir ein COM-Add-In erstellen wollen, fügen wir diesem zunächst einen Verweis auf die Objektbibliothek von Microsoft Access hinzu.
Dazu öffnen wir den References-Bereich mit dem Menübefehl Project|References… (siehe Bild 3).
Bild 3: Öffnen der Referenzen
Dort angekommen, wechseln wir zur Registerseite Available COM References und geben im Suchbereich microsoft access ein. Dies bringt den Verweis auf die Bibliothek Microsoft Access 16.0 Object Library zum Vorschein, die wir nun aktivieren (siehe Bild 4). Anschließend klicken wir auf Save Changes.
Bild 4: Hinzufügen eines Verweises auf die Access-Bibliothek
Einstellungen anpassen
Danach öffnen wir mit Project|Project Settings weitere Einstellungen, wo wir jeweils den Namen unseres Projekts eingeben können (siehe Bild 5).
Bild 5: Einstellen von Name, Description und Application Title
.twin-Datei umbenennen
Nun klicken wir mit der rechten Maustaste links auf den Eintrag Sources|MyCOMAddin.twin und wählen aus dem Kontextmenü den Befehl Rename aus (siehe Bild 6). Wir können den Namen von MyCOMAddin.twin nun bearbeiten und ändern diesen auf SuchenUndErsetzen.twin.
Bild 6: Umbenennen der Code-Datei
Achtung: Die Datei muss zu diesem Zweck geschlossen sein.
Prozeduren zum Registrieren des COM-Add-Ins
Wie sehen neben der frisch umbenannten Datei SuchenUndErsetzen.twin noch eine weitere Datei namens DllRegistration.twin. Wenn wir diese öffnen, sehen wir verschiedene Elemente, die wir durch den Inhalt aus Listing 1 ersetzen.
Module DllRegistration Const AddinProjectName As String = VBA.Compilation.CurrentProjectName Const AddinClassName As String = "SuchenUndErsetzen" Const AddinQualifiedClassName As String = AddinProjectName & "." & AddinClassName Const RootRegistryFolder As String = "HKCU\SOFTWARE\Microsoft\Office\Access\Addins\" & AddinQualifiedClassName & "\" Public Function DllRegisterServer() As Boolean On Error GoTo RegError Dim wscript As Object = CreateObject("wscript.shell") wscript.RegWrite RootRegistryFolder & "FriendlyName", AddinProjectName, "REG_SZ" wscript.RegWrite RootRegistryFolder & "Description", AddinProjectName, "REG_SZ" wscript.RegWrite RootRegistryFolder & "LoadBehavior", 3, "REG_DWORD" Return True RegError: MsgBox "DllRegisterServer -- An error occured trying to write to the system registry:" & vbCrLf & _ Err.Description & " (" & Hex(Err.Number) & ")" Return False End Function Public Function DllUnregisterServer() As Boolean On Error GoTo RegError Dim wscript As Object = CreateObject("wscript.shell") wscript.RegDelete RootRegistryFolder & "FriendlyName" wscript.RegDelete RootRegistryFolder & "Description" wscript.RegDelete RootRegistryFolder & "LoadBehavior" wscript.RegDelete RootRegistryFolder Return True RegError: MsgBox "DllUnregisterServer -- An error occured trying to delete from the system registry:" & vbCrLf & _ Err.Description & " (" & Hex(Err.Number) & ")" Return False End Function End Module
Listing 1: Prozeduren zum Registrieren des COM-Add-Ins
Hier sehen wir verschiedene Elemente. Ganz oben finden wir einige Konstanten, die unter anderem mit dem Projektnamen gefüllt werden (AddinProjectName) oder mit dem Namen der zu verwendenden Klasse (SuchenUndErsetzen).
Darunter finden wir zwei Funktionen. Diese Funktionen werden ausgeführt, wenn wir das COM-Add-In registrieren oder die Registrierung aufheben wollen, zum Beispiel über die Kommandozeile.
Die erste Funktion DllRegisterServer nimmt die für den Einsatz notwendigen Einträge in der Registry vor, die zweite Funktion DllUnregisterServer entfernt diese wieder.
Code der COM-DLL
Nun müssen wir nur noch den Code erstellen, mit dem wir die gewünschten Einträge zum Ribbon hinzufügen und dafür sorgen, dass das COM-Add-In überhaupt ausgeführt wird, wenn wir Access starten.
Dazu benötigen wir die Schnittstelle IDTExtensibility, die wir durch Hinzufügen mit dem Schlüsselwort Implements zur Klasse SuchenUndErsetzen bekannt geben.
Außerdem benötigen wir noch eine zweite Schnittstelle, damit wir über eine Funktion die Ribbondefinition übergeben können. Diese machen wir durch Anhängen von Implements IRibbonExtensibility und dem zusätzlichen Hinweis [WithDispathForwarding] für die Klasse bekannt.
IDTExensibility2-Schnittstelle implementieren
Durch das Implementieren diese Schnittstellen müssen wir die dadurch definierten Methoden, Ereignisse und Eigenschaften ebenfalls im Code implementieren. Bei der Schnittstelle IDTExtensibility2 bedeutet dies, dass wir einige Ereignisprozeduren anlegen müssen, die beim Laden des COM-Add-Ins durch Access ausgelöst werden, andere werden zu anderen Zeitpunkten aktiviert. Die wichtigste für uns ist die Ereignisprozedur OnConnection, die beim Start von Access ausgelöst wird und mit der Access uns mit dem Parameter Application einen Verweis auf die aktuelle Access-Instanz übergibt. Diesen Verweis speichern wir in der Variablen objAccess, damit wir später darüber auf die Access-Instanz zugreifen können. Das ist in diesem Fall streng genommen gar nicht nötig, aber wir führen diesen Code immer mit, weil er für die meisten COM-Add-Ins, die direkt Aktionen mit dem Access-Objekt ausführen sollen, nötig ist.
Diesen Teil des Codes finden Sie in Listing 2.
[ClassId("DC8E7154-FAC8-43B7-88E5-A93527539222")] Class SuchenUndErsetzen Implements IDTExtensibility2 [WithDispatchForwarding] Implements IRibbonExtensibility Private objAccess As Access.Application Private objRibbon As IRibbonUI Sub OnConnection(ByVal Application As Object, ByVal ConnectMode As ext_ConnectMode, ByVal AddInInst As Object, _ ByRef custom As Variant()) Implements IDTExtensibility2.OnConnection Set objAccess = Application End Sub Sub OnDisconnection(ByVal RemoveMode As ext_DisconnectMode, ByRef custom As Variant()) _ Implements IDTExtensibility2.OnDisconnection End Sub Sub OnAddInsUpdate(ByRef custom As Variant()) Implements IDTExtensibility2.OnAddInsUpdate End Sub Sub OnStartupComplete(ByRef custom As Variant()) Implements IDTExtensibility2.OnStartupComplete End Sub Sub OnBeginShutdown(ByRef custom As Variant()) Implements IDTExtensibility2.OnBeginShutdown End Sub ...
Listing 2: Code des COM-Add-Ins, Teil 1
Ribbon erweitern
In unserem Fall wollen wir das COM-Add-In nur nutzen, um dem Ribbon von Access einige neue Elemente hinzuzufügen. Dazu implementieren wir die Funktion GetCustomUI der Schnittstelle IRibbonUI. Diese wird von Access aus aufgerufen und wir bekommen so die Gelegenheit, Access eine Anpassung des Ribbons zu übergeben. Wir tun das wie in Listing 3, wo wir die passende Ribbon-Definition in der Variablen strXML zusammenstellen. Wer genau hinschaut, sieht, dass wir hier nicht strXML = strXML & … verwenden, sondern dass wir hier einen anderen Operator verwenden, um die Zeilen zusammenzufügen, nämlich &=.
Private Function GetCustomUI(ByVal RibbonID As String) As String Implements IRibbonExtensibility.GetCustomUI Dim strXML As String strXML &= "<customUI xmlns=""http://schemas.microsoft.com/office/2009/07/customui"" " _ & "loadImage=""LoadImage"" onLoad=""onLoad"">" & vbCrLf strXML &= " <ribbon startFromScratch=""false"">" & vbCrLf strXML &= " <tabs>" & vbCrLf strXML &= " <tab idMso=""TabHomeAccess"">" & vbCrLf strXML &= " <group idMso=""GroupFindAccess"" visible=""false"" />" & vbCrLf strXML &= " <group id=""grpSuchenUndErsetzen"" insertAfterMso=""GroupFindAccess"" " _ & "label=""amvSuchenUndErsetzen"">" & vbCrLf strXML &= " <button id=""btnSuchen"" imageMso=""FindDialog"" size=""large"" " _ & "onAction=""onAction"" label=""Suchen""/>" & vbCrLf strXML &= " <button id=""btnErsetzen"" imageMso=""ReplaceDialog"" size=""normal"" " _ & "onAction=""onAction"" label=""Ersetzen""/>" & vbCrLf strXML &= " <control idMso=""GoToMenuAccess"" size=""normal"" />" & vbCrLf strXML &= " <control idMso=""SelectMenuAccess"" size=""normal"" />" & vbCrLf strXML &= " </group>" & vbCrLf strXML &= " </tab>" & vbCrLf strXML &= " </tabs>" & vbCrLf strXML &= " </ribbon>" & vbCrLf strXML &= "</customUI>" & vbCrLf Return strXML End Function Function OnLoad(ribbon As IRibbonUI) Set objRibbon = ribbon End Function Public Sub OnAction(control As IRibbonControl) Select Case control.Id Case "btnSuchen" objAccess.Run Environ("AppData") & "\Microsoft\AddIns\amvSuchenUndErsetzen.amvSuchen" Case "btnErsetzen" objAccess.Run Environ("AppData") & "\Microsoft\AddIns\amvSuchenUndErsetzen.amvErsetzen" Case Else MsgBox "OnAction nicht behandelt: " & control.Id End Select End Sub End Class
Listing 3: Code des COM-Add-Ins, Teil 2
Was genau erledigen wir mit dieser Ribbondefinition? Wir definieren das customUI-Element, das ribbon-Element und das tabs-Element wie in jeder herkömmlichen Ribbonerweiterung.
Danach fügen wir ein tab-Element mit dem Wert TabHomeAccess für das Attribut idMso hinzu. Damit referenzieren wir das Ribbontab mit der Beschriftung Start.
Darunter referenzieren wir ein group-Element, das den Wert GroupFindAccess für das Attribut idMso enthält. Das entspricht dem eingebauten Bereich mit den Funktionen Suchen und Ersetzen (siehe Bild 7). Dieses wollen wir ausblenden und durch unsere eigene Version ersetzen, also stellen wir das Attribut visible auf false ein.
Bild 7: Das zu ersetzende Ribbon-Element
Danach legen wir unsere eigene Struktur für diesen Zweck an. Das erledigen wir mit einem benutzerdefinierten group-Element mit der ID grpSuchenUndErsetzen und der Beschriftung amvSuchenUndErsetzen.
Damit diese Gruppe an der gleichen Stelle angezeigt wird wie die zuvor ausgeblendete Gruppe, fügen wir diese über das Attribut insertAfterMso genau dort ein – und zwar mit dem Wert GroupFindAccess.
Schließlich fügen wir zunächst zwei rein benutzerdefinierte button-Elemente namens btnSuchen und btnErsetzen ein – samt entsprechenden Beschriftungen.
Wie im Original soll die Suchen-Schaltfläche groß dargestellt werden und die Ersetzen-Schaltfläche klein. Damit die gleichen Icons wie beim Original erscheinen, stellen wir die Eigenschaft imageMso jeweils auf die Namen dieser Elemente ein, nämlich FindDialog und ReplaceDialog.
Danach replizieren wir noch die beiden übrigen Steuerelemente aus der Originalgruppe, indem wir button-Elemente anlegen, deren Attribut idMso wir mit den Werten GoToMenuAccess und SelectMenuAccess füllen.
Danach fügen wir die fehlenden schließenden Elemente hinzu wie zum Beispiel .
Die Anweisung Return strXML gibt die Zeichenkette aus strXML als Funktionswert an Access zurück.
Schließlich fehlen noch die Aktionen, die beim Anklicken der beiden benutzerdefinierten button-Elemente ausgelöst werden sollen.
Dazu nutzen wir die Prozedur OnAction, die wir bereits für das gleichnamige Attribut der beiden button-Elemente hinterlegt haben (onAction=“onAction“).
Diese erhält nach dem Auslösen durch Betätigen einer der Schaltflächen mit dem Parameter control einen Verweis auf das auslösende Element.
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