65.9K
CodeProject is changing. Read more.
Home

WebBrowser IE Emulation for Google Maps JavaScript API Key Requirement

starIconstarIconstarIconstarIconstarIcon

5.00/5 (8 votes)

Jul 4, 2016

CPOL

8 min read

viewsIcon

31131

downloadIcon

1131

"Don't care about Google Maps/Routing/StreetView programming. This Control gives your WinForms applications the power of Google Maps API v3". - my previous article. Unfortunately, since Dec.2015, Google Maps JavaScript API applications requires authentication and the program stopped working properly

Introduction

My Article GMaps v1.1.12 - Google Maps/Routing/StreetView All-in-1 was written in Dec.2014, and worked well. Moreover, the community has awarded it as "Best VB.NET Article of December 2014 (First Prize)". Thanks.

But since Dec.2015, Google Maps JavaScript API applications require authentication, and the program stopped working properly (in "Route" Views, Directions blue line and Text Directions Panel are not shown), because the HTML/JavaScript file runs under the control of the Visual Studio's WebBrowser, which is, by default, Internet Explorer version 7, and that's not enough for the requirements.

Something had to be done. Initially, for my own applications, I got an API Key and proceeded to manual changes in the Registry, etc.

But it was necessary to automate the processes in the aforecited Article's Component, and first I thought to replace the WebBrowser by solutions like Gecko or Awesomium.

In both cases, the implementation of the Engine would cause a much heavier program, and code conversion would be a huge task. So I chose to emulate the WebBrowser to a IE higher version. This involves:

  1. Writing a Value to the Registry Key HKEY_CURRENT_USER\SOFTWARE\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION
    Instead of HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE could also be used, but that requires high permissions. HKCU is enough.
    The Value is:
    • Value Name: the Name of the Application Project + ".exe" (or ".vshost.exe", if the Project runs inside Visual Studio). Examples:
      MyProgram1.exe
      MyProgram1.vshost.exe
    • Value: a DWORD, as defined here (see Browser Emulation). Values are Decimal. We'll use 11000 (IE 11 default) or 10000 (IE 10 default).
  2. Ensure that the Value is written at the beginning of the Application and deleted when the Application ends (don't fill the Registry with trash).
    The best solution is to use the Startup and Shutdown events of My.Application class, however this cannot be done in a Class Library like the UserControl DLL of the aforementioned article, it's allowed just at WinForms Application level.

Then, and because the DLL Component is written in VB, for any VB Application, instead of using the DLL Component, it's better to insert only one file, GMapsVB.vb (with four classes, including the Component) in the WinForms Project. After rebuilding, the Component will be available in the Toolbox. Hence the reason to write a new Article and not just an Update to the original article.

And for those using other languages (including VB), I also made available a UserControl DLL Project (GMapsX). However, with one limitation: the My.Application Startup and Shutdown events become Methods of the DLL Component and will have to be manually called by the Startup Form events, respectively, Load and [ FormClosing (VB.NET) or OnFormClosing (C#) ].

Prerequisites

  • Visual Studio 2012 or later.
  • To use the new VB Class file or the DLL, the Projects must target to .NET Framework 4 (Client Profile).
  • Internet Explorer 10 or 11 must be installed. In Windows 7, prior to install last IE version, update it to Service Pack 1 (SP1).
  • To acquire full information on the UserControl, see the article GMaps v1.1.12 - Google Maps/Routing/StreetView All-in-1, where you can also download the Documentation. In the present article we will only deal with the differences introduced and the new code.
  • The minimum screen resolution is 1360x768

The Google Maps API Key

The file in which the key has to be placed, which should be present in the executable's Folder, is located in:

...\GMaps_VB\GMapsVB_Demo\GMapsVB_Demo\bin\Release\GMaps1.html , or,

...\GMaps_X\GMapsX_Demo\GMapsX_Demo\bin\Release\GMaps1.html

I don't know the true mechanisms behind the Google Maps API Key, its authentication, its interaction with the Operating System, etc., since the documentation I found, so far, is not very helpful. But the truth is that in most of the machines where I experienced the programs generated by these Projects, everything worked fine with the provided file GMaps1.html, as-is, i.e., without API Key.

"Work fine" means showing Directions blue line and Text Directions Panel in "Route" Views.

Therefore, to start, try running the chosen Project as-is. Works fine? Great!

But if not:

  • Get an API Key here.
  • At the end of file GMaps1.html, find this:
    <!--- (1) First attempt
        <script src="https://maps.googleapis.com/maps/api/js?key=XXXXXXXXXX"></script>
    --->
    
    <!--- (2) Second attempt
        <script async defer
        src="https://maps.googleapis.com/maps/api/js?key=XXXXXXXXXX&callback=Init(38.7438882, -9.1417950)">
        </script>
    --->
       
    <!--- Specifying an API KEY (above attempts): --->
    <!--- [(1) or (2)] Replace XXXXXXXXXX by YOUR API KEY --->
    <!--- (2) Replace 38.7438882 by YOUR INITIAL LATITUDE --->
    <!--- (2) Replace -9.1417950 by YOUR INITIAL LONGITUDE --->
    <!--- Uncomment only the chosen <script> ... </script> --->
    
    <!--- (3) Third attempt
          Without loading the API
    --->
  • Make and test the three attempts, in that order, one at a time:
    1. Synchronously loading the API.
    2. Asynchronously loading the API (as reccomended by Google).
    3. Without loading the API (again).

Using the code

1) For GMapsVB, in a new or existing VB Project:
  1. In Solution Explorer -> Application tab -> change the Target framework to .NET Framework 4 (Client Profile is lighter)
  2. Insert the file GMapsVB.vb: Visual Studio Menu PROJECT -> Add Existing Item... -> GMapsVB.vb (select from ...\GMaps_VB\GMapsVB_Demo\GMapsVB_Demo\GMapsVB.vb). By selecting this one, two more files will be transferred: GMapsVB.Designer.vb and GMapsVB.resx
  3. Copy the file GMaps1.html to your Project Startup Folder (...\...\bin\Debug or ...\...\bin\Release, depending on Configuration Manager settings)
  4. Build (or Rebuild) the Project. A new GMapsVB icon will appear in the Toolbox.

GMapsVB.vb contains four Classes:

1) Class GMapsVB - Is the UserControl and therefor must be the first Class.

The only differences to the original v1.1.12 GMaps is that: a) The assembly is not COM-visible, and b) GMaps.html file has changed to GMaps1.html. So the lines

    WBrowser.ObjectForScripting = Me
    WBrowser.Navigate(Application.StartupPath & "\GMaps.html")

have changed to

    ' WBrowser.ObjectForScripting = Me
    WBrowser.Navigate(Application.StartupPath & "\GMaps1.html")

2) Class MyApplication - Defined within Namespace My

Controls the Startup and Shutdown events, which are raised when the Application starts and ends. Also, contains all the code needed to perform the Emulation operations - Get information, Write and Delete the Registry Key Value. Also calls the _InfoBox Form (defined in the next Class).

  • The CONFIGURATION VARIABLES can be modified, but it is advisable to keep them with the default values until everything works fine.
  • _Process_My_Events - Keep True while Emulation is required (who knows, one day Microsoft can change the WebBrowser defaults...).
  • _Default_Emul_Version - Keep 0, unless there is some advantage in using a previous version.
  • _Verbose_Mode - Change it to False only when everything is OK, i.e., "Route" Views shows the Directions blue line and the Text Directions Panel.
Namespace My
    Partial Friend Class MyApplication
        ' =========================== CONFIGURATION VARIABLES ============================
        Public _Process_My_Events As Boolean = True     ' Events Startup and Shutdown
        Public _Default_Emul_Version As Byte = 0        ' 0 (Installed version), 10, 11
        '                       Only versions 10 or 11 will properly process the HTML file
        Public _Verbose_Mode As Boolean = True          ' True = Shows Form _InfoBox
        ' ================================================================================

Internal variables. Don't change. Meaning of the _InfoBox message's BackColor:

  • Lime: OK. The WebBrowser was emulated for the latest version available.
  • Yellow: Warning. The WebBrowser was emulated for a working version, but not the latest available.
  • Orange: Danger. The WebBrowser was emulated for a (predictably) inadequate version.
  • Red: Error. The WebBrowser was not emulated.
        Public OS_64bit As Boolean
        Public App_64bit As Boolean
        Public RegistryBase As String
        Public RegistrySubKey As String
        Public ProgName As String
        Public IE_Version As String = ""
        Public IE_MajorVersion As Byte = 0
        Public Emulation As Byte = 0
        Public Error_Color As Byte = 3  ' 0=Lime, 1=Yelow, 2=Orange, 3=Red
        Public StartupEvent As Boolean

If Startup event has to be processed:

  • GetInfo() collects some info and sets up the internal variables.
  • If no errors are detected, the Registry Key Value is written. Variable Emulation contains a Major Version (i.e., 11, 10,..) and is multiplied by 1000...
  • And (if applicable) the Form _InfoBox is shown.
        Private Sub MyApplication_Startup(ByVal sender As Object, ByVal e As Microsoft.VisualBasic.ApplicationServices.StartupEventArgs) Handles Me.Startup
            If _Process_My_Events Then
                StartupEvent = True
                GetInfo()
                If Error_Color < 3 Then     ' Create Registry Value
                    Registry.SetValue(RegistryBase & RegistrySubKey, _
                                      ProgName, Emulation * 1000, RegistryValueKind.DWord)
                End If
                ShowInfoBox()
            End If
        End Sub

If Shutdown event has to be processed:

  • If the Registry Key Value was written, it is deleted,
  • And (if applicable) the Form _InfoBox is shown.
        Private Sub MyApplication_Shutdown(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Shutdown
            If _Process_My_Events Then
                StartupEvent = False
                If Error_Color < 3 Then     ' Delete Registry Value
                    Dim Key As RegistryKey = Registry.CurrentUser.OpenSubKey(RegistrySubKey, True)
                    Key.DeleteValue(ProgName)
                End If
                ShowInfoBox()
            End If
        End Sub

GetInfo() gets installed IE version and sets some variables, including Emulation (major version to emulate) and Error_Color, which controls the quality of the Action to be taken.

        Private Sub GetInfo()
            OS_64bit = Environment.Is64BitOperatingSystem
            App_64bit = Environment.Is64BitProcess
            ' Get Internet Explorer version
            Dim FileIE As String = Environment.GetFolderPath(Environment.SpecialFolder.System) & "\ieframe.dll"
            If File.Exists(FileIE) Then
                Dim V = FileVersionInfo.GetVersionInfo(FileIE)
                IE_Version = V.ProductVersion
                IE_MajorVersion = V.FileMajorPart
                Error_Color = 0
            End If
            ' Set Registry Base, SubKey and Value Name (EXE program name)
            RegistryBase = Registry.CurrentUser.Name & "\"
            RegistrySubKey = "SOFTWARE\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION"
            ProgName = My.Application.Info.AssemblyName & If(Debugger.IsAttached, ".vshost", "") & ".exe"

            ' Select IE Emulation version to apply
            If IE_MajorVersion > 0 Then         ' IE detected
                If IE_MajorVersion <= 9 Then    ' Unsuitable version
                    Error_Color = 2
                End If
            End If
            If _Default_Emul_Version = 0 OrElse _Default_Emul_Version = IE_MajorVersion Then
                Emulation = IE_MajorVersion
            Else
                If _Default_Emul_Version > IE_MajorVersion OrElse _Default_Emul_Version < 7 Then
                    Error_Color = 3
                Else
                    Emulation = _Default_Emul_Version
                    Error_Color = If(_Default_Emul_Version < 10, 2, 1)
                End If
            End If
        End Sub

Form _InfoBox is displayed, when requested, but also when an Error or Danger status was detected.

        Private Sub ShowInfoBox()
            If _Verbose_Mode OrElse Error_Color > 1 Then
                Dim F1 As New _InfoBox
                F1.ShowDialog()
                F1.Dispose()
            End If
        End Sub
    End Class
End Namespace   ' My

3) Class _InfoBox - Is a Form and has two main blocks: DESIGNER and CODE.

  • DESIGNER is generated by the IDE. Nothing to say about this.
  • CODE prepares the info to show, based on the Internal Variables defined in Class MyApplication, which, within this Class, is visible as Application, of type Friend ReadOnly Property Application, so the variables must be qualified with prefix My.Application.
    Variable .StartupEvent indicates the calling Event: Startup (=True) or Shutdown (=False)
    ' ============================================================
    ' ==                          CODE                          ==
    ' ============================================================

    Private Tab_Colors() As Color = {Color.Lime, Color.Yellow, Color.Orange, Color.Red}

    Private Sub _InfoBox_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        With My.Application
            If .StartupEvent Then
                A2.Text = "Startup"
            End If
            If .OS_64bit = False Then
                B2.Text = "32 bits"
            End If
            If .App_64bit = False Then
                C2.Text = "32 bits"
            End If
            D2.Text = .RegistryBase & .RegistrySubKey
            E2.Text = .ProgName
            If .IE_MajorVersion > 0 Then
                F2.Text = .IE_MajorVersion.ToString
                F3.Text = .IE_Version
            End If
            If ._Default_Emul_Version > 0 Then
                G2.Text = ._Default_Emul_Version
            End If
            H2.BackColor = Tab_Colors(.Error_Color)
            If .Error_Color = 3 Then
                H2.ForeColor = Color.Yellow
                If .IE_MajorVersion = 0 Then
                    H2.Text = "Internet Explorer not detected..."
                Else
                    H2.Text = "Invalid Default version (" & _
                        ._Default_Emul_Version.ToString & ")"
                End If
            Else
                If .StartupEvent Then
                    H2.Text &= " " & .Emulation.ToString
                Else
                    H2.BackColor = Tab_Colors(0)
                    H2.Text = "Registry Value deleted..."
                End If
            End If
        End With
    End Sub

    Private Sub bClose_Click(sender As Object, e As EventArgs) Handles bClose.Click
        Me.Close()
    End Sub

Output examples:

4) Class _List - Is the List Form of the original GMaps UserControl and has two main blocks: DESIGNER and CODE.

  • The only difference is that the Form's Property FormBorderStyle was changed from FixedToolWindow to SizableToolWindow.

Output looks like this:

2) For GMapsX - Other languages (VB inc.):

Project GMapsX produces an UserControl DLL (GMapsX.dll) which must be copied to your Application's Startup Folder and referenced by your WinForms Project.

The file GMaps1.html must also be copied to your Application's Startup Folder.

Compared to GMapsVB, GMapsX only differs in the implementation of Startup and Shutdown events, which can not be defined, as My.Application events, in a Class Library Project. So, Class MyApplication is supressed and the events are to be controlled by the UserControl in Class GMapsX:

1) New Variables are added:

    '
    ' New Public Shared Variables (GMapsX)
    '
    ' =========================== CONFIGURATION VARIABLES ============================
    Public Shared _Process_My_Events As Boolean = True     ' Events Startup and Shutdown
    Public Shared _Default_Emul_Version As Byte = 0        ' 0 (Installed version), 10, 11
    '                       Only versions 10 or 11 will properly process the HTML file
    Public Shared _Verbose_Mode As Boolean = True          ' True = Shows Form _InfoBox
    ' ================================================================================
    Public Shared OS_64bit As Boolean
    Public Shared App_64bit As Boolean
    Public Shared RegistryBase As String
    Public Shared RegistrySubKey As String
    Public Shared ProgName As String
    Public Shared IE_Version As String = ""
    Public Shared IE_MajorVersion As Byte = 0
    Public Shared Emulation As Byte = 0
    Public Shared Error_Color As Byte = 3  ' 0=Lime, 1=Yelow, 2=Orange, 3=Red
    Public Shared StartupEvent As Boolean

2) New Properties are created, to allow the change of CONFIGURATION VARIABLES:

    '
    ' New Properties (GMapsX)
    '

    Public WriteOnly Property Process_My_Events As Boolean
        Set(value As Boolean)
            _Process_My_Events = value
        End Set
    End Property

    Public WriteOnly Property Default_Emul_Version As Byte
        Set(value As Byte)
            _Default_Emul_Version = value
        End Set
    End Property

    Public WriteOnly Property Verbose_Mode As Boolean
        Set(value As Boolean)
            _Verbose_Mode = value
        End Set
    End Property

3) And the Startup and Shutdown events become Methods (renamed Application_Startup and Application_Shutdown):

    '
    ' New Methods (GMapsX)
    '

    Public Sub Application_Startup()
        If _Process_My_Events Then
            StartupEvent = True
            GetInfo()
            If Error_Color < 3 Then     ' Create Registry Value
                Registry.SetValue(RegistryBase & RegistrySubKey, _
                                  ProgName, Emulation * 1000, RegistryValueKind.DWord)
            End If
            ShowInfoBox()
        End If
    End Sub
    Public Sub Application_Shutdown()
        If _Process_My_Events Then
            StartupEvent = False
            If Error_Color < 3 Then     ' Delete Registry Value
                Dim Key As RegistryKey = Registry.CurrentUser.OpenSubKey(RegistrySubKey, True)
                Key.DeleteValue(ProgName)
            End If
            ShowInfoBox()
        End If
    End Sub
  • Notice that above Methods must be called by the Startup Form events, respectively, Load and [ FormClosing (VB.NET) or OnFormClosing (C#) ]. See examples:
    private void Form1_Load(object sender, EventArgs e)
    {
        GMapsX1.Process_My_Events = true;   // (Default) - Required to perform Emulation
        GMapsX1.Default_Emul_Version = 0;   // (Default) - Emulates IE installed version
        GMapsX1.Verbose_Mode = true;        // When "Route" views are running OK, 
        //                       change to false, to stop displaying InfoBox
        //
        GMapsX1.Application_Startup();      // This is mandatory
    }

    protected override void OnFormClosing(FormClosingEventArgs e)
    {
        GMapsX1.Application_Shutdown();     // This is mandatory
    }
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        GMapsX1.Process_My_Events = True ' (Default) - Required to perform Emulation
        GMapsX1.Default_Emul_Version = 0 ' (Default) - Emulates IE installed version
        GMapsX1.Verbose_Mode = True      ' When "Route" views are running OK, 
        '                       change to False, to stop displaying InfoBox
        '
        GMapsX1.Application_Startup()    ' This is mandatory
    End Sub

    Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
        GMapsX1.Application_Shutdown()   ' This is mandatory
    End Sub

Placing the Component on the Toolbox

If you right-click the Toolbox -> Choose Items... -> Browse (...\...\GMapsX.dll) -> Open , and you receive a message [ There are no components in '...\...\GmapsX.dll' that can be placed on the toolbox. ], then,

  • With File Explorer, Open the Folder where GMapsX.dll resides.
  • Drag GMapsX.dll and Drop it into the tab (in Toolbox) where you want to place it.

History

04.Jul.2016 - First posted.