Abfragen direkt in der SQL-Ansicht erstellen

Microsoft hat neuerdings einen Befehl zum direkten Anzeigen von Abfragen in der SQL-Ansicht. Damit können wir eine Abfrage direkt in der SQL-Ansicht öffnen statt den Umweg über den Abfrageentwurf zu wählen. Leider hat Microsoft keine entsprechende Funktion für das Erstellen von Abfragen hinzugefügt – also eine Schaltfläche im Ribbon, mit der wir eine neue SQL-Abfrage direkt in der SQL-Ansicht öffnen können. Das ist allerdings gar nicht schlimm, denn wir rüsten diese Funktion einfach selbst nach. Zunächst schauen wir uns an, welche Befehle dazu notwendig sind, danach erstellen wir ein COM-Add-In, das die Funktion in der Benutzeroberfläche verankert – gleich neben den Schaltflächen für den Abfrageassistenten und das Anlegen von neuen Abfragen über die Entwurfsansicht.

In dem Beitrag, der die neuen Befehle zum direkten Anzeigen vorhandener Abfragen in der SQL-Ansicht vorstellt, gehen wir bereits kurz auf die notwendigen Anweisungen ein, die zum Erstellen einer neuen Abfrage und ihrer Anzeige in der SQL-Ansicht nötig sind – siehe Abfragen in der SQL-Ansicht öffnen (www.access-im-unternehmen.de/1482).

Dort stellen wir die folgende Prozedur vor:

Public Sub NewQueryInSQLView()
     RunCommand acCmdNewObjectDesignQuery
     RunCommand acCmdSQLView
End Sub

Diese ruft die RunCommand-Anweisung mit zwei verschiedenen Parametern auf, die wir auch über die Benutzeroberfläche aufrufen können.

Der erste namens acCmdNewObjectDesignQuery öffnet zunächst eine neue Abfrage in der Entwurfsansicht.

Der zweite nutzt den Parameter acCmdSQLView, um die so erstellte Abfrage in der SQL-Ansicht anzuzeigen. Platzieren wir Access-Fenster und VBA-Editor nebeneinander und rufen die Prozedur auf, sehen wir ein kurzes Flackern und erhalten anschließend eine weitgehend leere SQL-Ansicht der neuen Abfrage (siehe Bild 1).

Neue, leere Abfrage per Code in der SQL-Ansicht

Bild 1: Neue, leere Abfrage per Code in der SQL-Ansicht

Das kurze Flackern resultiert daraus, dass zuerst die Entwurfsansicht eingeblendet wird, zu der standardmäßig auch noch der Bereich Tabellen hinzufügen eingeblendet wird (in älteren Access-Versionen erscheint ein Fenster mit dem Titel Tabelle auswählen). Dieser verschwindet beim Wechsel zur SQL-Ansicht allerdings direkt wieder.

In älteren Versionen (zum Beispiel Access 2010) wird das Fenster Tabelle auswählen als modaler Dialog eingeblendet, den man erst schließen muss, bevor die Abfrage von der Entwurfsansicht in die SQL-Ansicht wechselt (siehe Bild 2).

Dieses Fenster erscheint in älteren Access-Versionen

Bild 2: Dieses Fenster erscheint in älteren Access-Versionen

In diesem Fall können wir nicht viel ausrichten – beim Anzeigen eines modalen Dialogs wird der aufrufende Code unterbrochen und folgende Anweisungen, mit denen wir den Dialog ausblenden könnten, würden nicht ausgeführt werden.

Benutzer älterer Access-Versionen müssen also diese Meldung noch schließen, bevor dann die SQL-Ansicht eingeblendet wird. Immerhin wird die Anweisung zum Wechseln zur SQL-Ansicht dann noch ausgeführt.

Funktion per COM-Add-In zum Ribbon hinzufügen

Wenn wir diese aus zwei Anweisungen bestehende Funktion über das Ribbon aufrufen wollen, haben wir verschiedene Möglichkeiten. Die nachhaltigste ist die Erstellen eines COM-Add-Ins. Dieses wird einmal installiert und die Funktion ist dauerhaft in der Benutzeroberfläche verankert – egal, welche Datenbank Sie damit öffnen.

Das könnte beispielsweise wie in Bild 3 aussehen. Es schien uns logisch, dass die betroffene Schaltfläche in den Bereich Erstellen|Abfragen integriert werden sollte. Ein Mausklick auf diese Abfrage ruft die beiden oben vorgestellten Anweisungen auf und öffnet so eine neue Abfrage in der SQL-Ansicht.

Neue Schaltfläche zum Anlegen einer Abfrage in der SQL-Ansicht

Bild 3: Neue Schaltfläche zum Anlegen einer Abfrage in der SQL-Ansicht

Ein solches COM-Add-In ist schnell erstellt. Wir nutzen dazu das schon oft referenzierte twinBASIC von Wayne Philips, das in der Version für das Erstellen von 32-Bit-Programmen kostenlos ist – erst die 64-Bit-Version ist kostenpflichtig (in DLLs, die mit der kostenlosen Version erstellt wurden, werden Hinweise auf twinBASIC eingeblendet). Die jeweils aktuelle Version kann hier heruntergeladen werden:

https://github.com/twinbasic/twinbasic/releases

Nach dem Erstellen eines neuen Projekts auf Basis der Vorlage Sample 5. MyCOMAddin (siehe Bild 4) beginnen wir mit dem Speichern des Projekts unter dem von uns gewählten Pfad und Dateinamen, zum Beispiel amvSQLView.twinproj. Merken Sie sich diesen Pfad, wir benötigen ihn später noch. Danach fahren wir mit dem Anpassen der Projekteinstellungen fort.

Neues Projekt auf Basis einer Vorlage

Bild 4: Neues Projekt auf Basis einer Vorlage

Projekteinstellungen anpassen

Diese finden wir, wenn wir auf der linken Seite auf Settings klicken. Wir stellen nun den Projektnamen, die Projektbeschreibung und den Anwendungstitel auf den gewünschten Wert ein, beispielsweise amvSQLView. Das sieht dann für den Projekttitel wie in Bild 5 aus.

Projekteinstellungen anpassen

Bild 5: Projekteinstellungen anpassen

Danach fügen wir noch einen Verweis auf die Access-Bibliothek hinzu. Dazu scrollen wir unter Settings weiter nach unten bis zum Bereich Library References.

Hier wechseln wir zur Registerseite Available COM References und suchen nach Access. Die nun erscheinende Bibliothek fügen wir durch Setzen eines Hakens hinzu (siehe Bild 6).

Hinzufügen eines Access-Verweises

Bild 6: Hinzufügen eines Access-Verweises

Registrierung der DLL programmieren

Damit kommen wir zu einem wichtigen Aspekt für ein COM-Add-In, das als DLL erstellt wird, nämlich die Registrierung. Damit Access beim Starten merkt, dass die Funktionen unseres COM-Add-Ins geladen werden sollen, müssen wir dies an bestimmten Stellen in der Registry vermerken.

Die Funktionen des Moduls aus Listing 1 erledigen genau dies. Im oberen Teil finden wir einige Konstanten mit wichtigen Informationen, die während der Installation benötigt werden. Die Funktion DLLRegisterServer schreibt die Einträge, die von Access beim Start abgefragt werden sollen und zum Laden des COM-Add-Ins führen, in einen bestimmten Bereich der Registry.

Module DllRegistration
     Const AddinProjectName As String = VBA.Compilation.CurrentProjectName
     Const AddinClassName As String = "amvSQLView"
     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: Modul für die Registrierung und die Deregistrierung des COM-Add-Ins

Die Funktion DllUnregisterServer entfernt diese Einträge wieder, falls gewünscht. Den Code des Moduls DLLRegistration des soeben erstellen Projekts können Sie durch den Code aus dem abgedruckten Listing ersetzen.

Wann werden diese Funktionen aufgerufen?

  • Während der Entwicklung erfolgt der Aufruf der ersten Funktion, wenn wir das COM-Add-In durch einen Klick auf die Build-Schaltfläche oben rechts in der Symbolleiste von twinBASIC betätigen. Dann wird die DLL mit dem COM-Add-In erstellt, im Ordner Build abgelegt und registriert. Jedes Mal, wenn wir das tun, wird zuvor die Funktion DLLUnregisterServer aufgerufen, um die eventuell vorhandenen Einträge zuvor zu entfernen. Achtung: Wenn das COM-Add-In registriert und Access dieses nach dem Start geladen hat, kann dieses nicht deregistriert werden. Sie müssen Access zuvor schließen.
  • Wir können die Funktion DLLRegisterServer auch manuell im Debugging-Modus aufrufen, indem wir auf den Pfeil über der ersten Zeile der Funktion klicken (siehe Bild 7). Auf die gleiche Weise starten wir DLLUnregisterServer, um die Registrierung der DLL aufzuheben.
  • Start der Registrierung

    Bild 7: Start der Registrierung

  • Die nächste Möglichkeit, für den Aufruf der Funktion DLLRegisterServer zu sorgen und das COM-Add-In zu registrieren, ist das Registrieren mit dem Kommandozeilentool RegSvr32. Diesem übergeben Sie den Pfad zur DLL als Parameter, was dazu führt, dass die enthaltene Funktion DLLRegisterServer ausgeführt und die DLL registriert wird. Der gleiche Befehl führt mit dem Parameter -u zum Aufruf der Funktion DLLUnregisterServer.
  • Schließlich können wir den COM-Add-Ins-Dialog über die Access-Optionen öffnen (Datei|Optionen, Bereich Add-Ins, unten COM-Add-Ins auswählen und auf Los… klicken). Im nun erscheinenden Dialog klicken wir auf Hinzufügen… und wählen die zuvor erstellte DLL aus, die dann registriert wird (siehe Bild 8). Durch Auswählen des neuen Eintrags und Anklicken der Schaltfläche Entfernen wird die DLL wieder deregistriert.
  • Registrierung über die Access-Optionen

    Bild 8: Registrierung über die Access-Optionen

  • Schließlich können wir in einem Inno Setup die DLL als Komponente im Files-Bereich angeben und mit dem Flag regserver versehen (mehr dazu in einem anderen Beitrag). Auch dies führt bei der Installation zum Aufruf der Funktion DLLRegisterServer.

Programmieren der Ribbon-Erweiterung

Damit kommen wir zum Hauptteil der Arbeit, dem Klassenmodul amvSQLView (siehe Listing 2). Dieses enthält eine eindeutige ID als Kennzeichnung.

[ ClassId ("DC8E7154-FAC8-43B7-88E5-A9352753999F") ]
Class amvSQLView
     Implements IDTExtensibility2
     [ WithDispatchForwarding ]
     Implements IRibbonExtensibility
     Private objAccess As Access.Application
     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
     ... mehr Code
End Class

[

Listing 2: Basis der Klasse amvSQLView

Die Klasse implementiert die Schnittstelle IDTExtensibility2, die Ereignisse bereitstellt, die beispielsweise beim Verbinden von Access mit dem COM-Add-In ausgelöst werden. Außerdem implementiert sie die Schnittstelle IRibbonExtensibility, die ein Ereignis bereitstellt, das beim Laden des Ribbons ausgelöst wird und das Anpassen des Ribbons ermöglicht.

Wir deklarieren in der Klasse eine Variable, um die Access-Instanz zu referenzieren:

Private objAccess As Access.Application

In der beim Verbinden ausgelösten Ereignisprozedur OnConnection weisen wir dieser Variable den mit dem Parameter Application übergebenen Verweis auf die aufrufende Access-Instanz zu. Die übrigen Elemente der Schnittstelle IDTExtensibility2 benötigen wir nicht, aber wir müssen diese dennoch implementieren.

Funktion zum Zusammenstellen der Ribbon-Anpassung

In dem mit … mehr Code markierten Teil des Listings finden wir noch die Funktion GetCustomUI. Diese stellt die Anpassungen zusammen, die das COM-Add-In am Ribbon vornehmen soll, damit wir unsere Funktion aufrufen können.

Die Funktion soll eigentlich nur eine Schaltfläche zu der eingebauten Gruppe Abfrage des Tabs Erstellen hinzufügen.

Nun lassen sich eingebaute group-Elemente aber nicht anpassen. Das heißt, wir müssen das eingebaute group-Element GroupCreateClientQuery ausblenden, es nachbauen und dann unser zusätzliches button-Element hinzufügen.

Den Code stellen wir wie in Listing 3 mit der Funktion GetCustomUI zusammen. Dazu verwenden wir die Variable strXML. Dieser weisen wir zuerst die Elemente customUI, ribbon und tabs hinzu. Als tab-Element geben wir mit dem Attribut idMso das eingebaute Element namens TabCreate an.

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"" >" & vbCrLf
     strXML &= "  <ribbon startFromScratch=""false"">" & vbCrLf
     strXML &= "    <tabs>" & vbCrLf
     strXML &= "      <tab idMso=""TabCreate"">" & vbCrLf
     strXML &= "        <group idMso=""GroupCreateClientQuery"" visible=""false"" />" & vbCrLf
     strXML &= "        <group id=""grpGroupCreateClientQuery"" insertAfterMso=""GroupCreateClientQuery"" " _
         & "label=""Abfragen"">" & vbCrLf
     strXML &= "          <button idMso=""CreateQueryFromWizard"" size=""large"" />" & vbCrLf
     strXML &= "          <button idMso=""CreateQueryInDesignView"" size=""large"" />" & vbCrLf
     strXML &= "              <button id=""btnCreateQueryInSQLView"" imageMso=""ViewsAdpDiagramSqlView"" " _
         & "size=""large"" label=""SQL-Ansicht"" onAction=""onAction"" screentip=""SQL-Ansicht"" " _
         & "supertip=""Erstellen Sie eine neue Abfrage, die direkt in der SQL-Ansicht geöffnet wird. Sie können " _
         & "dann direkt SQL-Code eintippen.""/>" & vbCrLf
     strXML &= "        </group>" & vbCrLf
     strXML &= "      </tab>" & vbCrLf
     strXML &= "    </tabs>" & vbCrLf
     strXML &= "  </ribbon>" & vbCrLf
     strXML &= "</customUI>" & vbCrLf
     Return strXML
End Function

Listing 3: Die Funktion GetCustomUI

Dann legen wir ein group-Element mit dem Wert GroupCreateClientQuery für das Attribut idMso an. Damit referenzieren wir das gleichnamige eingebaute Element und machen dieses durch Setzen des Attributs visible auf den Wert false unsichtbar.

Danach definieren wir das neue benutzerdefinierte group-Element, das wir durch den Wert GroupCreateClientQuery für das Attribut insertAfterMso hinter dem soeben ausgeblendeten group-Element einfügen. Über das Attribut label stellen wir den Text Abfragen ein.

In der neuen Gruppe bauen wir nun die beiden Schaltflächen ein, die durch das Ausblenden der eingebauten Gruppe nun nicht mehr vorhanden sind. Dazu legen wir für die beiden button-Elemente lediglich die idMso-Werte auf CreateQueryFromWizard und CreateQueryInDesignView fest und stellen die Größe mit dem Parameter size auf large ein.

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

Schreibe einen Kommentar