前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >WinForm中WebBrowser加载Flash库

WinForm中WebBrowser加载Flash库

作者头像
码客说
发布2022-03-24 08:05:45
2K0
发布2022-03-24 08:05:45
举报
文章被收录于专栏:码客

前言

Webview2官方文档:

https://docs.microsoft.com/zh-cn/microsoft-edge/webview2/get-started/wpf

WPF加载网页的三种方式

  • WebBrowser IE内核
  • Webview2 Chrome内核(官方库)
  • CEFSharp Chrome内核(三方库)

CEFSharp:

https://cloud.tencent.com/developer/article/1895623

Webview2 :

WebView2未来应该是要替代WebBrowser的,虽然需要依赖本机自带的Edge chromium内核,但相信未来的windows 更新肯定会以Edge chromium内核代替IE内核,并且不需要重新下载Chrome浏览器,使用Edge也会有一样的浏览体验。而作为桌面开发人员来说,使用WebView2直接加载网页会比使用CefSharp来得更舒服,不再需要引入一堆的CEF类库,同时安装文件也会缩小很多。

Flash支持测试页面

https://sc.chinaz.com/donghua/220315391630.htm

FlashPlayer

https://www.flash.cn/download-wins

其实我们不同的浏览器使用到的DLL是不同的

Windows

Chrome

FireFox

所以我们可以根据自己的需求去安装,不用全部安装到PC上。

Flash的现状

  • IE安装插件还可以使用
  • 360极速及QQ浏览器等,这些浏览器一般都是双内核,其中的Chromium内核版本一般都比较低,所以还可以继续加载Flash Player来使用,啥时候这些国产浏览器升级内核到88及以上版本,就彻底不支持了

WebBrowser

WPF下的WebBrowser存在内存泄漏的问题,所以这里用WinForm实现。

添加Falsh插件

有些老的系统必须用IE执行的,就只能用WebBrowser了。

保证IE上能运行Flash只需要安装flashplayerax_install_cn.exe就可以了。

首先我们要判断Flash有没有安装

代码语言:javascript
复制
private bool checkFlashInstall()
{
    Type type = Type.GetTypeFromProgID("ShockwaveFlash.ShockwaveFlash");
    if (type == null)
    {
        return false;
    }

    object flashObject = Activator.CreateInstance(type);
    string versionString = flashObject
        .GetType()
        .InvokeMember("GetVariable", BindingFlags.InvokeMethod, null, flashObject, new object[] { "$version" }) as string;

    Console.WriteLine("Flash版本:" + versionString);
    Marshal.ReleaseComObject(flashObject);
    return true;
}

安装EXE程序

代码语言:javascript
复制
private void installEXE(string fileName, string arguments)
{
    string result = "";
    try
    {
        using (Process process = new Process())
        {
            process.StartInfo.FileName = fileName;
            process.StartInfo.Arguments = arguments;
            process.StartInfo.CreateNoWindow = true;
            process.StartInfo.UseShellExecute = false; // 要获取输出,此值必须为 false。
            process.StartInfo.RedirectStandardOutput = true;
            process.StartInfo.RedirectStandardError = true;

            process.Start();
            process.WaitForExit(); // 等待执行完毕
            result = process.StandardError.ReadToEnd(); // 获取输出值
            process.Close();
        }
    }
    catch (Exception ex)
    {
        result = ex.Message;
    }

    Console.WriteLine("result:" + result);
}

注意

安装成功或退出,result返回的字符串都是空字符串。

判断并安装

代码语言:javascript
复制
private void Form1_Load(object sender, EventArgs e)
{
    bool isInstallFlash = checkFlashInstall();
    if (!isInstallFlash)
    {
        installEXE("./Libs/flashplayerax_install_cn.exe", "");
    }

    extendedWebBrowser1.Url = new Uri(url);
}

获取系统IE版本

获取浏览器内核版本

https://ie.icoa.cn/

网上有这么个说法

WebBrowser使用的浏览器版本是IE7,这个说法其实是不太准确的。

应该这样说

WebBrowser使用的是系统版本的IE对应的兼容模式。 比如Win10的是IE11,对应的兼容模式是IE7。 所以我在Win10上用下面两种方式获取到的IE版本都是11。

方式1

代码语言:javascript
复制
/// <summary>
/// 获取IE版本号
/// </summary>
/// <returns>
/// </returns>
public static int GetMajorVersion()
{
  //通过WebBrowser方案获取版本号
  return new WebBrowser().Version.Major;
}

方式2

代码语言:javascript
复制
/// <summary>
/// IE浏览器版本号帮助类
/// </summary>
public static class IEVersionHelper
{
  /// <summary>
  /// 获取IE主版本号
  /// </summary>
  /// <returns>
  /// </returns>
  public static string GetMajorVersion()
  {
    var majorVersion = string.Empty;

    var detailVersion = GetDetailVersion();
    if (!string.IsNullOrWhiteSpace(detailVersion))
    {
      if (detailVersion.IndexOf(".", StringComparison.Ordinal) is int connectedCharFirstIndex && connectedCharFirstIndex > -1)
      {
        majorVersion = detailVersion.Substring(0, connectedCharFirstIndex);
      }
      else
      {
        majorVersion = detailVersion;
      }
    }

    return majorVersion;
  }

  /// <summary>
  /// 获取IE详细版本号
  /// </summary>
  /// <returns>
  /// </returns>
  public static string GetDetailVersion()
  {
    string text = @"SOFTWARE\Microsoft\Internet Explorer";
    //通过注册表获取用户IE版本号
    RegistryKey mainKey = Registry.LocalMachine;
    RegistryKey subKey = mainKey.OpenSubKey(text);

    var versionNumber = subKey?.GetValue("svcVersion")?.ToString() ?? string.Empty;
    if (string.IsNullOrEmpty(versionNumber))
    {
      versionNumber = subKey?.GetValue("svcUpdateVersion")?.ToString() ?? string.Empty;
      if (string.IsNullOrEmpty(versionNumber))
      {
        versionNumber = subKey?.GetValue("Version")?.ToString() ?? string.Empty;
      }
    }
    return versionNumber;
  }
}

设置IE版本

记录WebBrowser控件使用IE渲染版本的路径:

32位 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\MAIN\FeatureControl\FEATURE_BROWSER_EMULATION 64位 HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Internet Explorer\MAIN\FeatureControl\FEATURE_BROWSER_EMULATION

或者

32位 HKEY_CURRENT_USER\SOFTWARE\Microsoft\Internet Explorer\MAIN\FeatureControl\FEATURE_BROWSER_EMULATION 64位 HKEY_CURRENT_USER\SOFTWARE\Wow6432Node\Microsoft\Internet Explorer\MAIN\FeatureControl\FEATURE_BROWSER_EMULATION

工具类

代码语言:javascript
复制
public class IEHelper
{
  /// <summary>
  /// 定义IE版本的枚举
  /// </summary>
  public enum IeVersion
  {
    ie11强制,//11001 (0x2AF9) IE11
    ie11,//11000 (0x2AF8) IE11
    ie10强制,//10001 (0x2711) IE10
    ie10,//10000 (0x02710) IE10
    ie9强制,//9999 (0x270F) IE9
    ie9,//9000 (0x2328) IE9.
    ie8强制,//8888 (0x22B8) IE8. 强制IE8标准模式显示,忽略!DOCTYPE指令
    ie8,//8000 (0x1F40) IE8. 默认设置,在IE8标准模式中按照网页上!DOCTYPE指令展示网页
    ie7//7000 (0x1B58) 使用WebBrowser Control控件的应用程序所使用的默认值,在IE7标准模式中按照网页上!DOCTYPE指令来展示网页
  }

  /// <summary>
  /// 设置WebBrowser的默认版本
  /// </summary>
  /// <param name="ver">
  /// IE版本
  /// </param>
  public static void SetIE(IeVersion ver)
  {
    //获取程序名称
    //string productName = AppDomain.CurrentDomain.SetupInformation.ApplicationName;
    string productName = System.IO.Path.GetFileName(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName);
    object version;
    switch (ver)
    {
      case IeVersion.ie7:
        version = 0x1B58;
        break;

      case IeVersion.ie8:
        version = 0x1F40;
        break;

      case IeVersion.ie8强制:
        version = 0x22B8;
        break;

      case IeVersion.ie9:
        version = 0x2328;
        break;

      case IeVersion.ie9强制:
        version = 0x270F;
        break;

      case IeVersion.ie10:
        version = 0x2710;
        break;

      case IeVersion.ie10强制:
        version = 0x2711;
        break;

      case IeVersion.ie11:
        version = 0x2AF8;
        break;

      case IeVersion.ie11强制:
        version = 0x2AF9;
        break;

      default:
        version = 0x1F40;
        break;
    }
    string fcRegKey = @"HKEY_LOCAL_MACHINE\Software\Microsoft\Internet Explorer\Main\FeatureControl\";
    Registry.SetValue(fcRegKey + "FEATURE_BEHAVIORS", productName, 1, RegistryValueKind.DWord);
    Registry.SetValue(fcRegKey + "FEATURE_BROWSER_EMULATION", productName, version, RegistryValueKind.DWord);
    if (Environment.Is64BitOperatingSystem)
    {
      string fcRegKey64 = @"HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Internet Explorer\MAIN\FeatureControl\";
      Registry.SetValue(fcRegKey64 + "FEATURE_BEHAVIORS", productName, 1, RegistryValueKind.DWord);
      Registry.SetValue(fcRegKey64 + "FEATURE_BROWSER_EMULATION", productName, version, RegistryValueKind.DWord);
    }
  }
}

调用

代码语言:javascript
复制
int version = GetMajorVersion();
Console.WriteLine("version:" + version);

if (version >= 9)
{
  IEHelper.SetIE(IEHelper.IeVersion.ie9);
}

注意

网上有这么个说法,把版本设置为非IE的版本号,会使用Edge,这个说法是错误的。 虽然更改后加载检测浏览器内核的网页上显示是Edge,但是其实上并不是使用的Edge。

窗口弹出

默认的WebBrowser新打开的窗口会用系统默认的IE打开,并且我们也没法获取新窗口的地址自行处理。

所以我们自定义WebBrowser保证能获取新窗口的地址。

自定义ExtendedWebBrowser

代码语言:javascript
复制
using System;

namespace WinFormWebFlash.Views
{
    public class ExtendedWebBrowser : System.Windows.Forms.WebBrowser
    {
        private System.Windows.Forms.AxHost.ConnectionPointCookie cookie;
        private WebBrowserExtendedEvents events;

        public event EventHandler BeforeNavigate;

        public event EventHandler BeforeNewWindow;

        [System.Runtime.InteropServices.ComImport(), System.Runtime.InteropServices.Guid("34A715A0-6587-11D0-924A-0020AFC7AC4D"),
                System.Runtime.InteropServices.InterfaceTypeAttribute(System.Runtime.InteropServices.ComInterfaceType.InterfaceIsIDispatch),
                System.Runtime.InteropServices.TypeLibType(System.Runtime.InteropServices.TypeLibTypeFlags.FHidden)]
        public interface DWebBrowserEvents2
        {
            [System.Runtime.InteropServices.DispId(250)]
            void BeforeNavigate2(
                [System.Runtime.InteropServices.In,
                System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.IDispatch)] object pDisp,
                [System.Runtime.InteropServices.In] ref object URL,
                [System.Runtime.InteropServices.In] ref object flags,
                [System.Runtime.InteropServices.In] ref object targetFrameName, [System.Runtime.InteropServices.In] ref object postData,
                [System.Runtime.InteropServices.In] ref object headers,
                [System.Runtime.InteropServices.In,
                System.Runtime.InteropServices.Out] ref bool cancel);

            [System.Runtime.InteropServices.DispId(273)]
            void NewWindow3(
                [System.Runtime.InteropServices.In,
                System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.IDispatch)] object pDisp,
                [System.Runtime.InteropServices.In, System.Runtime.InteropServices.Out] ref bool cancel,
                [System.Runtime.InteropServices.In] ref object flags,
                [System.Runtime.InteropServices.In] ref object URLContext,
                [System.Runtime.InteropServices.In] ref object URL);
        }

        //This method will be called to give you a chance to create your own event sink
        protected override void CreateSink()
        {
            //MAKE SURE TO CALL THE BASE or the normal events won't fire
            base.CreateSink();
            events = new WebBrowserExtendedEvents(this);
            cookie = new System.Windows.Forms.AxHost.ConnectionPointCookie(this.ActiveXInstance, events, typeof(DWebBrowserEvents2));
        }

        protected override void DetachSink()
        {
            if (null != cookie)
            {
                cookie.Disconnect();
                cookie = null;
            }
            base.DetachSink();
        }

        protected void OnBeforeNavigate(string url, string frame, out bool cancel)
        {
            EventHandler h = BeforeNavigate;
            WebBrowserExtendedNavigatingEventArgs args = new WebBrowserExtendedNavigatingEventArgs(url, frame);
            if (null != h)
            {
                h(this, args);
            }
            //Pass the cancellation chosen back out to the events
            cancel = args.Cancel;
        }

        protected void OnBeforeNewWindow(string url, out bool cancel)
        {
            EventHandler h = BeforeNewWindow;
            WebBrowserExtendedNavigatingEventArgs args = new WebBrowserExtendedNavigatingEventArgs(url, null);
            if (null != h)
            {
                h(this, args);
            }
            cancel = args.Cancel;
        }

        //This class will capture events from the WebBrowser
        private class WebBrowserExtendedEvents : System.Runtime.InteropServices.StandardOleMarshalObject, DWebBrowserEvents2
        {
            private ExtendedWebBrowser _Browser;

            public WebBrowserExtendedEvents(ExtendedWebBrowser browser)
            { _Browser = browser; }

            //Implement whichever events you wish
            public void BeforeNavigate2(object pDisp, ref object URL, ref object flags, ref object targetFrameName, ref object postData, ref object headers, ref bool cancel)
            {
                _Browser.OnBeforeNavigate((string)URL, (string)targetFrameName, out cancel);
            }

            public void NewWindow3(object pDisp, ref bool cancel, ref object flags, ref object URLContext, ref object URL)
            {
                _Browser.OnBeforeNewWindow((string)URL, out cancel);
            }
        }
    }

    public class WebBrowserExtendedNavigatingEventArgs : System.ComponentModel.CancelEventArgs
    {
        private string _Frame;
        private string _Url;

        public WebBrowserExtendedNavigatingEventArgs(string url, string frame)
            : base()
        {
            _Url = url;
            _Frame = frame;
        }

        public string Frame
        {
            get { return _Frame; }
        }

        public string Url
        {
            get { return _Url; }
        }
    }
}

回到Form1.cs[设计]窗口,在菜单生成中,点生成解决方案

一会之后在工具箱的最上方就会出现一个新的组件ExtendedWebBrowser,把ExtendedWebBrowser拖进来。

ExtendedWebBrowser的事件里双击BeforeNewWindow并添加代码:

代码语言:javascript
复制
private void extendedWebBrowser2_BeforeNewWindow(object sender, EventArgs e)
{
    WebBrowserExtendedNavigatingEventArgs eventArgs = e as WebBrowserExtendedNavigatingEventArgs;
    eventArgs.Cancel = true;
    ((ExtendedWebBrowser)sender).Navigate(eventArgs.Url);
}

WebView2

安装WebView2 Runtime

WebView2 实在诱人,最新的 Edge(Chromium) 性能强悍,而且所有使用 WebView2 的应用可以共用一个运行时(说人话就是一个安装了应用时,其他应用就不用装了)。

Windows 11 已经自带 WebView2 ,就连 Office 也会自动部署 WebView2 ,目前 WebView2 已经被部署到 2亿台电脑,并且还在继续增加 …… 未来是属于 WebView2 的。

重要的是 WebView2 仍然支持老旧的、即将被淘汰的 Windows 7 —— 拥有良好的兼容性。

WebView2是依赖于Edge chromium内核的,有如下三种方式可以获取:

  1. 安装开发版的Edge (Chromium),稳定版的Edge目前不支持WebView控件,不知道后续会不会开放。
  2. 安装独立的WebView2 Runtime,它可以独立下载和升级。
  3. 程序内嵌入Edge chromium内核

这三种方式运行效果基本一致,主要特点是:

  • 前两种方式和以前使用IE的浏览器控件非常类似,浏览器内核和程序是分离的,程序可以保持非常小的体积,浏览器内核可以单独升级。
  • 第一种方式目前还不支持Edge的稳定版,无法使用于生产环境
  • 第三种方式和以前的CEF比较类似,将chromium嵌入了程序,可以控制chromium的版本,减少依赖性,同时可以控制浏览器的版本,避免升级导致的不稳定。但是相应的程序包会特别大,配置也相对更麻烦。

所以这里我推荐第二种方式。

下载地址:

https://developer.microsoft.com/zh-cn/microsoft-edge/webview2/#download-section

安装WebView2

安装Microsoft.Web.WebView2程序包

代码语言:javascript
复制
Install-Package Microsoft.Web.WebView2

添加名字空间

代码语言:javascript
复制
xmlns:wv2="clr-namespace:Microsoft.Web.WebView2.Wpf;assembly=Microsoft.Web.WebView2.Wpf"

添加控件

代码语言:javascript
复制
<wv2:WebView2 Name="webView" Source="https://www.psvmc.cn"/>

Flash支持

很遗憾,现在还没找到WebView2支持Flash的方式。

目前要想支持Flash只有两种选择:

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-03-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • FlashPlayer
  • WebBrowser
    • 添加Falsh插件
      • 获取系统IE版本
        • 方式1
        • 方式2
      • 设置IE版本
        • 窗口弹出
        • WebView2
          • 安装WebView2 Runtime
            • 安装WebView2
              • Flash支持
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档