65.9K
CodeProject 正在变化。 阅读更多。
Home

WebBrowser IE 仿真以满足 Google Maps JavaScript API 密钥要求

starIconstarIconstarIconstarIconstarIcon

5.00/5 (8投票s)

2016年7月4日

CPOL

8分钟阅读

viewsIcon

31901

downloadIcon

1200

"不关心 Google Maps/Routing/StreetView 编程。此控件可为您的 WinForms 应用程序提供 Google Maps API v3 的强大功能。" - 我之前的文章。不幸的是,自 2015 年 12 月起,Google Maps JavaScript API 应用程序需要身份验证,程序停止正常工作。

引言

我写于 2014 年 12 月的文章 GMaps v1.1.12 - Google Maps/Routing/StreetView All-in-1 运行良好。此外,社区还将其评为“2014 年 12 月最佳 VB.NET 文章(一等奖)”。谢谢。

但自 2015 年 12 月起,Google Maps JavaScript API 应用程序需要身份验证,程序停止正常工作(在“路线”视图中,未显示方向蓝色线条和文本方向面板),因为 HTML/JavaScript 文件在 Visual Studio 的 WebBrowser 的控制下运行,默认情况下是 Internet Explorer 7 版本,这不足以满足要求。

必须采取措施。最初,对于我自己的应用程序,我获取了一个 API 密钥并手动修改了注册表等。

但是有必要自动化上述文章组件中的过程,我首先考虑用 GeckoAwesomium 等解决方案替换 WebBrowser。

在这两种情况下,引擎的实现都会导致程序更加沉重,代码转换将是一项巨大的任务。所以我选择仿真 WebBrowser 到更高的 IE 版本。这涉及到

  1. 向注册表项 HKEY_CURRENT_USER\SOFTWARE\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION 写入一个值
    可以使用 HKEY_CURRENT_USER 而不是 HKEY_LOCAL_MACHINE,但这需要高权限。HKCU 足够了。
    • 值名称:应用程序项目名称 + ".exe"(或 ".vshost.exe",如果项目在 Visual Studio 中运行)。示例
      MyProgram1.exe
      MyProgram1.vshost.exe
    • 值:一个 DWORD,如 此处 定义(参见 Browser Emulation)。值为十进制。我们将使用11000(IE 11 默认)或10000(IE 10 默认)。
  2. 确保在应用程序开始时写入该值,并在应用程序结束时删除(不要用垃圾填充注册表)。
    最好的解决方案是使用 My.Application 类的启动关闭事件,但这不能在类库(如上述文章的用户控件 DLL)中完成,它仅允许在 WinForms 应用程序级别进行。

然后,由于 DLL 组件是用 VB 编写的,对于任何 VB 应用程序,与其使用 DLL 组件,不如只将一个文件 GMapsVB.vb(包含四个类,包括组件)插入 WinForms 项目。重新生成后,该组件将在工具箱中可用。因此,写一篇新文章而不是仅仅更新原来的文章。

对于使用其他语言(包括 VB)的人,我还提供了一个用户控件 DLL 项目(GMapsX)。但是,有一个限制:My.Application 的启动和关闭事件成为 DLL 组件的方法,必须由启动窗体的事件分别手动调用:Load 和 [FormClosing (VB.NET) 或 OnFormClosing (C#)]。

必备组件

  • Visual Studio 2012 或更高版本。
  • 要使用新的 VB 类文件或 DLL,项目必须以.NET Framework 4(客户端配置文件)为目标。
  • 必须安装Internet Explorer 1011。在 Windows 7 上,安装最新的 IE 版本之前,请先更新到 Service Pack 1 (SP1)。
  • 有关用户控件的完整信息,请参阅文章 GMaps v1.1.12 - Google Maps/Routing/StreetView All-in-1,您也可以在那里下载文档。在本篇文章中,我们将只讨论引入的差异和新代码。
  • 最小屏幕分辨率为1360x768

Google Maps API 密钥

必须将密钥放入的、应该位于可执行文件文件夹中的文件位于

...\GMaps_VB\GMapsVB_Demo\GMapsVB_Demo\bin\Release\GMaps1.html,或者,

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

我不知道 Google Maps API 密钥、其身份验证、与操作系统的交互等的真正机制,因为我迄今为止找到的文档不是非常有帮助。但事实是,在我体验这些项目生成的程序的大多数机器上,一切都与提供的文件GMaps1.html 一起正常工作,即,没有 API 密钥。

“正常工作”意味着在“路线”视图中显示方向蓝色线条文本方向面板。

因此,首先,尝试按原样运行所选项目。正常工作?太棒了!

但如果不行

  • 在此 获取 API 密钥。
  • 在文件 GMaps1.html 的末尾,找到这个
    <!--- (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
    --->
  • 按顺序进行三次尝试并测试,一次一个
    1. 同步加载 API。
    2. 异步加载 API(如 Google 推荐)。
    3. 不加载 API(再次)。

使用代码

1) 对于GMapsVB,在一个新的或现有的 VB 项目中
  1. 解决方案资源管理器 -> 应用程序选项卡 -> 将目标框架更改为.NET Framework 4客户端配置文件更轻)
  2. 插入文件GMapsVB.vb:Visual Studio 菜单项目 -> 添加现有项... -> GMapsVB.vb(从...\GMaps_VB\GMapsVB_Demo\GMapsVB_Demo\GMapsVB.vb 选择)。选择此项后,还将传输另外两个文件:GMapsVB.Designer.vbGMapsVB.resx
  3. 将文件GMaps1.html复制到您的项目启动文件夹(...\...\bin\Debug...\...\bin\Release,取决于配置管理器设置)
  4. 生成(或重新生成)项目。一个新GMapsVB图标将出现在工具箱中。

GMapsVB.vb 包含四个类

1) 类 GMapsVB - 是用户控件,因此必须是第一个类。

与原始v1.1.12 GMaps 唯一的区别是:a) 程序集不是 COM 可见的,以及 b) GMaps.html 文件已更改为 GMaps1.html。所以这些行

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

已更改为

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

2) 类 MyApplication - 定义在Namespace My

控制启动关闭事件,这些事件在应用程序启动和结束时触发。此外,它还包含执行仿真操作所需的所有代码 -获取信息写入删除注册表项值。还调用_InfoBox 窗体(在下一个类中定义)。

  • 可以修改配置变量,但建议在一切正常之前保留它们的默认值。
  • _Process_My_Events - 在需要仿真时保持为 True(谁知道,也许有一天 Microsoft 会改变 WebBrowser 的默认设置...)。
  • _Default_Emul_Version - 保持为 0,除非使用以前的版本有什么好处。
  • _Verbose_Mode - 只有当一切正常时才将其更改为 False,即,“路线”视图显示方向蓝线和文本方向面板。
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
        ' ================================================================================

内部变量。不要更改。_InfoBox 消息背景色的含义

  • Lime:OK。WebBrowser 已为可用的最新版本进行了仿真。
  • Yellow:警告。WebBrowser 已为可用的工作版本进行了仿真,但不是最新的。
  • Orange:危险。WebBrowser 已为(可预见的)不适用版本进行了仿真。
  • Red:错误。WebBrowser 未被仿真。
        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

如果必须处理启动事件

  • GetInfo() 收集一些信息并设置内部变量。
  • 如果没有检测到错误,则写入注册表项值。变量 Emulation 包含一个主版本(例如 11、10、..),并乘以 1000...
  • 并且(如果适用)显示_InfoBox 窗体。
        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

如果必须处理关闭事件

  • 如果注册表项值已被写入,则将其删除,
  • 并且(如果适用)显示_InfoBox 窗体。
        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() 获取已安装的 IE 版本并设置一些变量,包括 Emulation(要仿真的主版本)和 Error_Color,它控制要执行的操作的质量。

        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

_InfoBox 窗体将在请求时显示,在检测到错误或危险状态时也会显示。

        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) 类 _InfoBox - 是一个窗体,有两个主要部分:DESIGNERCODE

  • DESIGNER 由 IDE 生成。关于这个没有什么可说的。
  • CODE 根据 Class MyApplication 中定义的内部变量准备要显示的信息,在类中,它作为 Application 可见,类型为 Friend ReadOnly Property Application,因此变量必须带有前缀 My.Application
    变量.StartupEvent指示调用事件:Startup=True)或 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

输出示例

4) 类 _List - 是原始 GMaps 用户控件的列表窗体,有两个主要部分:DESIGNERCODE

  • 唯一的区别是窗体的 FormBorderStyle 属性从 FixedToolWindow 更改为 SizableToolWindow

输出看起来像这样

2) 对于GMapsX - 其他语言(包括 VB)

项目GMapsX 生成一个用户控件 DLL(GMapsX.dll),必须将其复制到应用程序的启动文件夹,并通过 WinForms 项目进行引用。

文件GMaps1.html 也必须复制到应用程序的启动文件夹。

GMapsVB相比,GMapsXStartupShutdown 事件的实现上有所不同,这些事件不能在类库项目中定义为 My.Application 事件。因此,类 MyApplication 被省略,事件由类 GMapsX 中的用户控件控制

1) 添加了新变量

    '
    ' 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 (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) 并且 StartupShutdown 事件变为方法(重命名为 Application_StartupApplication_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
  • 请注意,上述方法必须由启动窗体的事件分别调用:Load 和 [FormClosing (VB.NET) 或 OnFormClosing (C#)]。请参阅示例
    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

将组件放置在工具箱中

如果右键单击工具箱 -> 选择项... -> 浏览(...\...\GMapsX.dll)-> 打开,然后收到一条消息 [‘...\...\GmapsX.dll’中没有可以放置在工具箱上的组件。],那么,

  • 使用文件资源管理器,打开GMapsX.dll 所在的文件夹。
  • GMapsX.dll拖动放入您想放置它的选项卡(在工具箱中)。

历史

2016 年 7 月 4 日 - 首次发布。

© . All rights reserved.