Google-Maps als Kartendienst im Formular

Wenn Sie ein Abonnement des Magazins 'Access im Unternehmen' besitzen, können Sie sich anmelden und den kompletten Artikel lesen.
Anderenfalls können Sie das Abonnement hier im Shop erwerben.

Google-Maps als Kartendienst im Formular

Sie möchten den Anwendern Ihrer Datenbank die Möglichkeit anbieten, neben den eigentlichen Adressdaten auch gleich dazugehörige Geoinformationen einzusehen? Dazu eignen sich sicher die Dienste Google-Maps oder Bing-Maps. Ein Webbrowser-Steuerelement im Formular könnte als Host für jene dienen. Doch der Weg ist steiniger, als erwartet! Wie Sie die auftretenden Probleme lösen können, beschreibt dieser Beitrag.

Google Maps

Wenn Sie nach einem Ort auf der Startseite von Google Maps (https://www.google.de/maps) recherchieren, so geben Sie in das Suchfeld links oben die gewünschte Adresse ein. Google verarbeitet die Anfrage mit seinen Geo Location Services und zeigt das Resultat im Browser an. Dabei ändert sich die Adresszeile entsprechend. Aus der Anfrage Duisburg Borkhofer Str. wird dann eine URL, die sich aus mehreren Teilen unterschiedlicher Bedeutung zusammensetzt:

https://www.google.de/maps/place
     /Borkhofer+Str.,+47137+Duisburg
     /@51.4634026,6.7777953,17z
     /data=!3m1!4b1!4m5!3m4!1
     s0x47b8bfbe53cca829:0xb28d5de5549581d!8m2!3d51.4634026!4d6.7799893

Der Service hat zunächst ermittelt, dass es sich offenbar um den Ort Duisburg in Deutschland handeln soll, der die Postleitzahl 47137 besitzt. Die Angabe des Landes fehlt. Google geht davon aus, dass der Ort sich mit großer Wahrscheinlichkeit in dem Land befindet, von dem aus die Anfrage gesendet wurde. Dies geht etwa aus der übermittelten IP hervor. Der Straßenname vervollständigt diesen Teil, in dem natürlich keine Leerzeichen vorkommen dürfen. Sie sind durch Pluszeichen ersetzt.

Doch damit nicht genug! Hinter einem Slash befinden sich, durch ein @ symbolisiert, auch gleich die Geokoordinaten des gefundenen Orts. Längen- und Breitengrad kommen als Fließkommazahlen daher, wobei als Dezimaltrennzeichen der Punkt dient. Kommas trennen hingegen die einzelnen Werte. Was jedoch hat es mit dem dritten Parameter dieses Teils auf sich, dem 17z?

Versuch und Irrtum machen schlau, denn Google hat den Aufbau dieser Parameter nicht wirklich dokumentiert. Etliche Leute, den Autor eingeschlossen, haben teilweise herausgefunden, was sie bedeuten. Am weitesten kam wohl M. Sticklesville mit der Aufstellung in seinem Blog (https://mstickles.wordpress.com/2015/06/12/gmaps-urls-options). Der dritte Parameter gibt nämlich den Zoomgrad der Kartenansicht wieder.

Sie können den Wert in der Adresszeile des Browsers einfach von Hand ändern, etwa in 11z. Der Ort wird nun von weiter oben betrachtet. Bei 4z ist allerdings Schluss. Damit wird fast die Erdhalbkugel angezeigt. Der höchste Zoomfaktor beträgt 21z. Bei allen anderen Werten außerhalb dieses Bereichs kommt es nicht etwa zu einer Fehlermeldung, sondern Google korrigiert den Faktor automatisch durch Auf- oder Abrunden auf den nächsten Wert.

Im dritten Teil der URL findet sich ein ominöser data-Parameter. Zahlen, Buchstaben und Ausrufezeichen wechseln sich scheinbar willkürlich ab. Tatsächlich haben sie eine Bedeutung, der Sie auf die Schliche kommen, wenn Sie etwa die Ansicht der Karte auf Satellit einstellen, oder den Layer für das Verkehrsaufkommen einschalten. Bis auf diesen data-Parameter bleiben alle anderen Teile der URL dabei konstant. Der data-Parameter bestimmt das Layout der Karte. Wenn Sie mehr über seinen Aufbau erfahren möchten, so kundschaften Sie den angegebenen Blog von Sticklesville aus. Wir kommen auf den data-String aber auch später noch zu sprechen.

Am Ende der URL schließt sich ein länglicher String an, der wohl die ID der Suchanfrage enthält. Google cachet diesen Wert auch in einem Cookie, um Rechenzeit einzusparen. Er ist für die Suchanfrage bedeutungslos.

Sie können die URL nun dergestalt modifizieren, dass nur noch die wichtigsten Elemente enthalten sind. Das sähe dann so aus:

https://www.google.de/maps/place
     /@51.4634026,6.7777953,17z
     /data=!3m1!4b1!4m5!3m4!1

Falls die Koordinaten dieselben sind, wie zuvor, so macht Google sofort wieder die ursprüngliche Version daraus, weil es sie aus dem Cookie ausliest. Bei geänderten Koordinaten hingegen bleibt der String meist erhalten. Allerdings ändert sich nun auch die Ansicht komplett: Das Control Panel links verschwindet und der Orts-Marker ist ebenfalls nicht mehr da.

Man kann an dieser Stelle zusammenfassen, dass sich die Google-Maps-Anfragen in einer URL unterbringen und sich dabei sowohl Zoomfaktor, wie auch Gestalt des Kartengebnisses, beeinflussen lassen. Was will man mehr? Damit ist der erste Teil der Aufgabe in Angriff genommen, eine Google-Maps-Karte in ein Formular zu bringen.

Das Webbrowser-Steuerelement

Als Host für die Maps-Seiten soll ein Webbrowser-Steuerelement dienen, das Microsoft seit der Access-Version 2007 in den Fundus der Steuerelemente integriert hat. Es unterscheidet sich in nichts vom gleichnamigen ActiveX-Steuerelement, das Windows immer mit sich führt. Lediglich die Möglichkeit, es direkt an ein Datenfeld einer Tabelle oder Abfrage zu binden, welches die zu navigierende URL enthält, ist ein Bonus-Feature.

Zum Test setzen Sie das Webbrowser-Steuerelement in ein neues Formular ein, wie dies im Formular frmMaps der Beispieldatenbank GoogleMaps.accdb geschah (siehe Bild 1). Außer dem Webbrowser Control enthält es nur ein Textfeld rechts oben, welches den Inhalt des URL-Felds des aktuellen Datensatzes anzeigt. Die Tabelle tblURLs dient als Datenherkunft des Formulars. Sie weist neben der Autowert-ID nur das Feld URL aus und ein optionales Feld Beschreibung, welches hier nicht zum Einsatz kommt. An URL sind sowohl das Textfeld, wie auch das Webbrowser-Steuerelement gebunden.

Im Testformular zur Tabelle tblURLs ist zentral ein Webbrowser-Steuerelement untergebracht

Bild 1: Im Testformular zur Tabelle tblURLs ist zentral ein Webbrowser-Steuerelement untergebracht

Nach dem ersten Start präsentiert das Formular eine leere Fläche, da die erste URL den Inhalt about:blank hat. Würde die URL nämlich aus einem Leer-String bestehen, so käme es zu einer Fehleranzeige im Browser wegen ungültiger Adresse. Der zweite Datensatz hat den folgenden Inhalt:

https://www.google.de/maps/

Sie erwarten, dass nun Google-Maps im Browser angezeigt wird? Stattdessen konfrontiert uns Google mit der Meldung aus Bild 2. Aus irgendeinem Grund ist es mit dem Webbrowser-Steuerelement nicht zufrieden und verwehrt die Navigation zu Maps. Doch dieses verwendet intern ja lediglich den im System installierten Internet Explorer, der möglicherweise in einer aktuellen Version 11 vorhanden ist (Edge bleibt außen vor). Warum dann diese Meldung?

Statt Maps zeigt Google trotz korrekter URL zunächst eine Inkompatibilitätsmeldung an

Bild 2: Statt Maps zeigt Google trotz korrekter URL zunächst eine Inkompatibilitätsmeldung an

Webbrowser Control: Limitierungen und deren Aufhebung

Aus Sicherheitsgründen grenzt Microsoft die Möglichkeiten im Webbrowser Controls stark ein. Das gilt übrigens für das Access-Steuerelement gleichermaßen, wie für das ActiveX-Steuerelement. Die wichtigste Änderung besteht darin, dass das Control grundsätzlich die Version IE7 nach außen meldet.

Genau damit ist Google nicht einverstanden, da die aktuelle Version von Maps einen neueren Browser für korrekte Funktion erwartet. Zudem erlaubt das Control nur eine eingeschränkte Ausführung von JavaScript.

Das Ende der Fahnenstange ist damit zum Glück noch nicht erreicht. Tatsächlich können Sie das Verhalten des Webbrowser Controls durch Einstellungen in der Registry ändern! Und dafür sind noch nicht einmal administrative Rechte erforderlich, da sich der entsprechende Zweig im Benutzerteil HKEY_CURRENT_USER befindet:

HKEY_CURRENT_USERSoftwareMicrosoft
                    Internet ExplorerMainFeatureControl

Unter diesem Zweig befinden sich noch weitere Schlüssel, die verschiedene Funktionen des Controls steuern. Der wichtigste ist dabei der Folgende:

FEATURE_BROWSER_EMULATION

Unter diesem Schlüssel tragen Sie einen DWORD-Wert ein, der den Namen msaccess.exe trägt. Als Wert verwenden Sie 11001. Dieser nämlich führt dazu, dass Windows beim Start einer Access-Instanz und dem Öffnen eines Webbrowser-Steuerelements hier nachschaut, ob ein Eintrag zu finden ist. Falls Prozessname und Eintrag zueinander passen, so spendiert Windows dem zugrundeliegenden Internet Explorer die angegebenen Version. Beim Wert 11001 wäre das die Version 11. Funktionieren würde Google Maps auch noch mit der Version 9, die dem Registry-Wert 9999 entspräche. Doch warum zu einer älteren Version greifen, wenn es eine neuere gibt? Voraussetzung ist natürlich, dass auch tatsächlich der Internet Explorer 11 installiert ist. Passen Sie den Wert an die installierte Version an. Im MSDN gibt es eine Seite, die erschöpfender darüber Auskunft gibt (https://msdn.microsoft.com/en-us/library/ee330730(v=vs.85).aspx). Edge kann das Webbrowser Control übrigens nicht hosten. Es verwendet auch unter Windows 10 den Kompatibilitätsmodus des IE11.

Bedenken brauchen Sie bei der Modifikation der Registry hier nicht zu haben. Zum einen sind Einträge unter dem Benutzerzweig recht unverdächtig, zum anderen betrifft die Änderung nur ausschließlich Access-Prozesse. Übrigens bedienen sich auch andere Entwickler dieser Möglichkeit. Wir fanden in diesem Zweig auch Einträge prominenter Anwendungen, wie Visual Studio, RapidPHP oder Starmoney.

Da die Änderungen an der Registry keine Administratorrechte erfordern, können Sie auch von Access aus über VBA getätigt werden. Dies geschieht auch in der Beispieldatenbank. Das Intro-Formular ruft beim Klick auf den grünen Button die Funktion SetWebControlAsIE9 des Moduls mdlWebcontrol auf. Diese liest zunächst aus der Registry aus, ob der Wert für die Browser Emulation bereits gesetzt ist. Falls nicht, so holt sie das umgehend nach. Allerdings wirkt sich die Änderung noch nicht unmittelbar aus. Erst nach einem Neustart von Access gibt das Webbrowser Control die Version IE11 aus. Deshalb empfiehlt die Routine in diesem Fall auch gleich den Neustart (Bild 3) und bewerkstelligt diesen auch noch. Schauen wir uns diese Routine (ersterer Teil in Listing 1) einmal genauer an.

Automatische Aufforderung zum Neustart von Access über die Prozedur SetWebControlAsIE9 und eine Messagebox

Bild 3: Automatische Aufforderung zum Neustart von Access über die Prozedur SetWebControlAsIE9 und eine Messagebox

Da Access und VBA keine Methoden zum Auslesen oder Schreiben der Registry haben, benötigen wir den Verweis auf eine externe Komponente. Für unseren einfachen Zweck gelingt das am effizientesten mit der Bibliothek Windows Script Host Object Model, die im Objektkatalog nachher den Namen IWshRuntimeLibrary trägt und auf der Datei wshom.ocx beruht. Diese Bibliothek ist Bestandteil von Windows und kann deshalb bedenkenlos zum Einsatz kommen. Ihre Klasse WshShell enthält Methoden zur Modifikation der Registry.

Die Objektvariable oShell nimmt eine Instanz dieser Klasse per New auf. Der Zweig der Registry ist in der String-Variablen sKey gespeichert, und zwar inklusive des Wertnamens. Die Funktion RegRead auf den Schlüssel gibt dann den Wert als Variant in der Variablen vKey zurück. Da es zum Fehler kommt, wenn der Registry-Schlüssel nicht existiert, ist der Aufruf der Funktion in eine Fehlerbehandlung über On Error Resume Next eingebettet. Der Fehlerwert beträgt in diesem Fall -2147024894, der in der folgenden Bedingung dazu führt, dass der Schlüsselwert über die Methode RegWrite neu geschrieben wird. Die Klasse WshShell erlaubt also einen komfortablen Zugriff auf die Registry mit sehr wenig Aufwand.

Existiert der Schlüsselwert zwar, so ist zu prüfen, ob er dem gewünschten entspricht. Das übernehmen die folgenden Zeilen. Weicht der Inhalt von vKey von 11001 ab, so erfolgt abermals das Schreiben in den Schlüssel. Ansonsten passiert außer der informativen Ausgabe im VBA-Direktfenster weiter nichts. Wichtig aber ist noch eine Kleinigkeit: Wurde in die Registry geschrieben, so erhält die Bool-Variable bNewStart den Wert True. Dieser Wert wird am Ende der Routine ausgewertet:

    If bNewStart Then
         RestartAccess
     End If

RestartAccess ist eine weitere Prozedur im Modul, die den Neustart von Access veranlasst (siehe Listing 2). Wird die Nachfrage der MsgBox bestätigt, so wird wieder das Shell-Objekt bemüht. Seine Methode Exec entspricht ungefähr der Shell-Methode von VBA, ist aber etwas einfacher zu handhaben. In sExec wird ein String zusammengebastelt, der eine neue Instanz von Access startet, wobei über SysCmd erfahren wird, wo sich die msaccess.exe befindet. Als Parameter für den Prozess wird der Name der aktuellen Datenbank (CurrentDb.Name) übergeben. In der Folge startet eine zusätzliche Instanz der Datenbank. Die aktuelle Instanz wird aber über Quit geschlossen. Das passiert so schnell, dass es kaum wahrnehmbar ist. Im Ergebnis befinden wir uns in der Datenbank mit dem neu aktiviertem Webbrowser Control.

Sub RestartAccess()
     If MsgBox("Die Datenbank und Access müssen neu gestartet werden," & vbCrLf & _
         "weil die Einstellungen für das WebControl geändert wurden." & vbCrLf & _
         "Jetzt neu starten?", vbQuestion Or vbYesNo, "Bestätigen:") = vbYes Then
         
         Dim sExec As String
         Dim oShell As New WshShell
         
         sExec = Chr$(34) & SysCmd(acSysCmdAccessDir) & "msaccess.exe" & Chr$(34) & _
                 " " & Chr$(34) & CurrentDb.Name & Chr$(34)
         oShell.Exec sExec
         Application.Quit acQuitSaveNone
     End If
End Sub

Listing 2: Die Routine RestartAccess übernimmt gegebenenfalls den Neustart von Access

Die Routine SetWebControlAsIE9 enthält noch einen zweiten Teil, der drei weitere Einstellungen für das Control vornimmt. Das passiert analog zum ersten Teil. Der Unterschied besteht nur darin, dass der Code-Block nicht dreimal wiederholt wird, sondern eine Schleife auf das Array vRegElement die einzelnen Registry-Schlüssel anspricht:

vRegElement = Array("FEATURE_BLOCK_LMZ_SCRIPT", 
     "FEATURE_BLOCK_LMZ_OBJECT", 
     "FEATURE_BLOCK_LMZ_IMG")
For i= 0 To 2
     sKey = "HKEY_CURRENT_USERSoftwareMicrosoft" & _
         "Internet ExplorerMainFeatureControl" & _
         vRegElement(i) & "msaccess.exe"
     ...
     oShell.RegWrite sKey, 1, "REG_DWORD"
     ...
Next i

Falls es noch nicht aufgefallen sein sollte: RegWrite übernimmt in einem Rutsch die Anlage des Registry-Schlüssels und des Werts! Einfacher geht's nicht! Bei allen alternativen Methoden muss das separat erfolgen.

Neben den Einstellungen, die so über die Registry vorgenommen werden können, gibt es noch einige weitere, die die weitgehende Übereinstimmung des Webbrowser-Steuerelements mit dem dem Internet Explorer herstellen können. Dazu jedoch muss eine Windows-API-Funktion bemüht werden, die sich CoInternetSetFeatureEnabled nennt. Das Setzen dreier neuer Eigenschaften ist in die Prozedur ChangeWebControlFeature ausgelagert (Listing 3).

Public Declare Function CoInternetSetFeatureEnabled Lib "urlmon.dll" _
     (ByVal FeatureEntry As eINTERNETFEATURELIST, ByVal Flags As eFEATURESetting, ByVal bEnable As Long) As Long
Public Declare Function CoInternetIsFeatureEnabled Lib "urlmon.dll" _
     (ByVal FeatureEntry As eINTERNETFEATURELIST, ByVal Flags As eFEATURESetting) As Long
Sub ChangeWebControlFeature()

Dies war die Leseprobe dieses Artikels.
Melden Sie sich an, um auf den vollständigen Artikel zuzugreifen.

Bitte geben Sie die Zeichenfolge in das nachfolgende Textfeld ein

Die mit einem * markierten Felder sind Pflichtfelder.

Ich habe die Datenschutzbestimmungen zur Kenntnis genommen.