温故知新,遇见WPF/WinForms,托管控件WebBrowser按本机浏览器版本修正仿真配置,提高运行兼容性

背景

使用WinForms或者WPF里面自带的WebBrowser控件来加载网页时,该控件会默认使用IE7的标准模式加载网页,但是有些网页可能要求在特定的模式下运行才有较好的兼容性,但是微软提供了一个注册表方法,只需要将程序名称添加到对应注册表位置,那么它将不以兼容视图模式运行以便提高对访问网站的兼容性。

Webpages containing standards-based !DOCTYPE directives are displayed in IE7 Standards mode. Default value for applications hosting the WebBrowser Control

原理

https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/general-info/ee330730(v=vs.85)?redirectedfrom=MSDN

浏览器仿真

Windows Internet Explorer 8及以后的版本FEATURE_BROWSER_EMULATION特性定义了Internet Explorer的默认仿真模式,支持以下数值:

数值 描述
11001 (0x2AF9) Internet Explorer 11, 网页在IE 11的Edge模式下显示,不管是否声明了!DOCTYPE指令。如果没有声明!DOCTYPE指令,会导致网页在Quirks中加载。
11000 (0x2AF8) Internet Explorer 11, 包含基于标准的!DOCTYPE指令的网页在IE 11 Edge模式下显示。Internet Explorer 11的默认值
10001 (0x2711) Internet Explorer 10, 网页在IE 10的标准模式下显示,与!DOCTYPE指令无关。
10000 (0x02710) Internet Explorer 10, 包含基于标准的!DOCTYPE指令的网页在IE 10标准模式下显示。Internet Explorer 10的默认值
9999 (0x270F) Internet Explorer 9, 网页在IE 9标准模式下显示,不管是否声明了!DOCTYPE指令。如果没有声明!DOCTYPE指令,就会导致页面以Quirks模式加载。
9000 (0x2328) Internet Explorer 9, 包含基于标准的!DOCTYPE指令的网页在IE 9模式下显示。Internet Explorer 9的默认值
在Internet Explorer 10中,包含基于标准的!DOCTYPE指令的网页会在IE 10标准模式下显示。
8888 (0x22B8) Internet Explorer 8, 网页在IE 8标准模式下显示,不管是否声明了!DOCTYPE指令。如果没有声明!DOCTYPE指令,就会导致页面以Quirks模式加载。
8000 (0x1F40) Internet Explorer 8, 包含基于标准的!DOCTYPE指令的网页在IE 8模式下显示。Internet Explorer 8的默认值
在Internet Explorer 10中,包含基于标准的!DOCTYPE指令的网页会在IE10标准模式下显示。
7000 (0x1B58) Internet Explorer 7, 包含基于标准的!DOCTYPE指令的网页在IE 7标准模式下显示。托管WebBrowser控件的应用程序的默认值

要通过使用注册表来控制该功能的值,请将你的可执行文件的名称添加到以下设置中,并将其值设置为与所需设置相匹配。

HKEY_LOCAL_MACHINE (or HKEY_CURRENT_USER)
   SOFTWARE
      Microsoft
         Internet Explorer
            Main
               FeatureControl
                  FEATURE_BROWSER_EMULATION
                     contoso.exe = (DWORD) 00009000

子窗口剪裁

Internet Explorer 9,Internet Explorer 9优化了窗口绘制程序的性能,这些程序涉及与子窗口相关的剪切区域。这有助于提高某些窗口绘制操作的性能。然而,某些承载WebBrowser控件的应用程序依赖于以前的行为,当这些优化被启用时,不能正常工作。FEATURE_ENABLE_CLIPCHILDREN_OPTIMIZATION功能可以禁用这些优化。

默认情况下,该功能在Internet Explorer和承载WebBrowser控件的应用程序中被启用。要通过使用注册表禁用该功能,请将你的可执行文件的名称添加到以下设置中。

HKEY_LOCAL_MACHINE (or HKEY_CURRENT_USER)
   SOFTWARE
      Microsoft
         Internet Explorer
            Main
               FeatureControl
                  FEATURE_ENABLE_CLIPCHILDREN_OPTIMIZATION
                     contoso.exe = (DWORD) 00000000

当值设置为00000001(DWORD)时,该功能被启用,当值为00000000(DWORD)时,该功能被禁用。

效果对比

我们可以利用演示程序中访问https://ie.icoa.cn来验证。

未添加注册表之前,显示的内核版本为Trident 7.0(IE 11.0的兼容视图)

image

添加注册表之后,显示的内核版本为Trident 7.0(IE 11.0),没有了兼容视图字眼。

image

实施策略

https://github.com/TaylorShi/HelloWiki

定义常量

/// <summary>
/// 浏览器仿真
/// </summary>
const string FEATURE_BROWSER_EMULATION = @"\FEATURE_BROWSER_EMULATION";

/// <summary>
/// 子窗口剪裁优化
/// </summary>
const string FEATURE_ENABLE_CLIPCHILDREN_OPTIMIZATION = @"\FEATURE_ENABLE_CLIPCHILDREN_OPTIMIZATION";

/// <summary>
/// Microsoft Internet Explorer 特性控制
/// </summary>
const string MicrosoftInternetExplorerMainFeatureControl = @"HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main\FeatureControl";

/// <summary>
/// 获取组件文件名
/// </summary>
/// <param name="hModule"></param>
/// <param name="lpFilename"></param>
/// <param name="nSize"></param>
/// <returns></returns>
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
static extern int GetModuleFileName(IntPtr hModule, StringBuilder lpFilename, int nSize);

获取本地浏览器版本

/// <summary>
/// 获取本地浏览器版本
/// </summary>
/// <returns></returns>
private int GetLocalBrowserVersion()
{
    var systemDir = Environment.GetFolderPath(Environment.SpecialFolder.System);
    var localBrowserFilePath = Path.Combine(systemDir, "mshtml.dll");
    if (!string.IsNullOrEmpty(localBrowserFilePath) && File.Exists(localBrowserFilePath))
    {
        try
        {
            var fileVersionInfo = FileVersionInfo.GetVersionInfo(localBrowserFilePath);
            return fileVersionInfo.FileMajorPart;
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.StackTrace);
        }
    }

    return -1;
}

获取浏览器仿真数值

/// <summary>
/// 获取浏览器仿真数值
/// </summary>
/// <param name="localBrowserVersion"></param>
/// <returns></returns>
private uint GetBrowserEmulationValue(int localBrowserVersion)
{
    uint emulationValue;
    switch (localBrowserVersion)
    {
        // Internet Explorer 7, 包含基于标准的!DOCTYPE指令的网页在IE 7标准模式下显示。托管WebBrowser控件的应用程序的默认值。
        case 7:
            emulationValue = 7000;
            break;
        // Internet Explorer 8, 包含基于标准的!DOCTYPE指令的网页在IE 8模式下显示。Internet Explorer 8的默认值。
        case 8:
            emulationValue = 8000;
            break;
        // Internet Explorer 9, 包含基于标准的!DOCTYPE指令的网页在IE 9模式下显示。Internet Explorer 9的默认值。
        case 9:
            emulationValue = 9000;
            break;
        // Internet Explorer 10, 包含基于标准的!DOCTYPE指令的网页在IE 10标准模式下显示。Internet Explorer 10的默认值。
        case 10:
            emulationValue = 10000;
            break;
        // Internet Explorer 11, 包含基于标准的!DOCTYPE指令的网页在IE 11 Edge模式下显示。Internet Explorer 11的默认值。
        case 11:
        default:
            emulationValue = 11000;
            break;
    }

    return emulationValue;
}

获取应用运行程序名称

/// <summary>
/// 获取应用运行程序名称
/// </summary>
/// <returns></returns>
private string GetAppExecutableName()
{
    var appExecutablePath = string.Empty;
    var sb = new StringBuilder(1024);
    var len = GetModuleFileName(IntPtr.Zero, sb, sb.Capacity);
    if(len > 0)
    {
        appExecutablePath = sb.ToString(0, len);
    }

    var appExecutableName = Path.GetFileName(appExecutablePath);
    return appExecutableName;
}

初始化本机浏览器仿真设置

/// <summary>
/// 初始化本机浏览器仿真设置
/// </summary>
private void InitLocalBrowserEmulation()
{
    // 获取本地浏览器版本
    var browserVersion = GetLocalBrowserVersion();
    // 获取浏览器仿真数值
    var emulationValue = GetBrowserEmulationValue(browserVersion);
    // 获取应用运行程序名称
    var appExecutableName = GetAppExecutableName();
    // 判断执行合法性
    if (browserVersion > 0 && !string.IsNullOrEmpty(appExecutableName))
    {
        // 注册表设置浏览器仿真值
        var FEATURE_BROWSER_EMULATION_KEY = $"{MicrosoftInternetExplorerMainFeatureControl}{FEATURE_BROWSER_EMULATION}";
        Registry.SetValue(FEATURE_BROWSER_EMULATION_KEY, appExecutableName, emulationValue, RegistryValueKind.DWord);

        // 注册表启用子窗口剪裁优化
        var FEATURE_ENABLE_CLIPCHILDREN_OPTIMIZATION_KEY = $"{MicrosoftInternetExplorerMainFeatureControl}{FEATURE_ENABLE_CLIPCHILDREN_OPTIMIZATION}";
        Registry.SetValue(FEATURE_ENABLE_CLIPCHILDREN_OPTIMIZATION_KEY, appExecutableName, 1, RegistryValueKind.DWord);
    }
}

参考

posted @ 2022-08-23 20:44  TaylorShi  阅读(373)  评论(0编辑  收藏  举报