Winform下CefSharp的引用、配置、实例与报错排除

本文详细介绍了CefSharp在vs2013、.net4.0环境下,创建Winfrom项目、引用CefSharp的方法,演示了winfrom下CefSharp的基本使用,包括显示网页url/本地html显示、JavaScript调用异步C#方法、JavaScript调用带参数C#方法、JavaScript调用委托C#方法、JavaScript调用C#返回实体对象、ChromiumWebBrowser控件扩展IContextMenuHandler接口实现禁用右击按钮菜单、简单介绍WebGL页面渲染;详细介绍了的CefSharp依赖项、常见报错查看与必要依赖项分析,最后进行了简单总结、并提供了源码的下载.

1、关于CefSharp

装一手,比较简单的英语

CefSharp lets you embed Chromium in .NET apps. It is a lightweight .NET wrapper around the Chromium Embedded Framework (CEF) by Marshall A. Greenblatt. About 30% of the bindings are written in C++/CLI with the majority of code here is C#. It can be used from C# or VB, or any other CLR language. CefSharp provides both WPF and WinForms web browser control implementations.

CefSharp is BSD licensed, so it can be used in both proprietary and free/open source applications. For the full details, see the LICENSE file.

自己总结的:

CefShar是一个提供了Chromium Embedded Framework (CEF)的.NET接口的开源项目,提供了Winform、WPF封装,可以用来代替微软的WebBrowser,浏览网页,尤为强大的是实现了C#、VB等vs支持的语言与JavaScript的交互方法。

2、CefSharp项目源码下载

3、Winfrom项目引入CefSharp

我的开发环境vs2013、.net4.0,Nugget中搜索CefSharp显示的版本是v53,然而v51.0.0-pre01的Breaking Changes里面有这么一句

CefSharp requires at least .Net 4.5.2 (Last version to support .Net 4.0 is 49)

不想安装.net4.5.2,所以只能通过工具-程序包管理器-程序包管理控制台手动命令行导入版本v49。0.1的,输入命令Install-Package CefSharp.WinForms -Version 49.0.1回车等待执行完成,我这里已经安装过了。



其他版本命令请参考http://www.nuget.org/packages/CefSharp.WinForms.

等待导入成功,生成一下...报错...

CefSharp.Common does not work correctly on 'AnyCPU' platform. You need to specify platform (x86 / x64).

嗯?!!!

cefsharp不支持anycup,还需要设置一下目标平台为x86或x64

如果你以为只是在项目名右击-属性-生成-目标平台改为x86就太天真了....

反正我试了不行...

正确的姿zhi势shi: 解决方案名右击-属性-配置属性-配置,右边平台选择x86或x64,什么?选不到?



点击当前界面右上角配置管理器-活动解决方案平台下拉新建,x86/x64随便选,回来这边下拉已经可以选择了,完事左下角确定,再生成一下试试吧



以上看不懂的参考这里.net使用cefsharp开源库开发chrome浏览器(二)

4、Winfrom下CefSharp的基本使用

4.1 显示一个页面

4.1.1 显示url网页

对照下面在一个Form的对应位置添加代码

	   using CefSharp.WinForms;
public partial class Form1 : Form
{
ChromiumWebBrowser webBrower = null;
public Form1()
{
InitializeComponent();
Load += Form_Load;
}
private void Form_Load(object sender, EventArgs e)
{
string path = "www.baidu.com";
webBrower = new ChromiumWebBrowser(path);
webBrower.Dock = DockStyle.Fill;//填充方式
this.Controls.Add(webBrower);
}
}

直接运行就OK了

4.1.2显示一个本地html

把path改为File协议就行,例如:显示程序下的文件夹html中的test.html

//获取文件的物理路径
string path = AppDomain.CurrentDomain.BaseDirectory + "\\html\\test.html";
//转换为File协议路径
path = "file://" + path.Replace("\\", "/");

如果实在不知道怎么写的话,建议直接用浏览器把html打开,地址栏里面显示的file://链接就是File协议路径

需要在 test.html文件上右击-属性-复制到输出目录改为始终复制,这样调试时debug下面才会有这个文件

推荐个CCS3动画的html,直接右击保存到本地就行了大风车CCS3动画,修改完成,同样运行就可以看到页面了,运行还是挺流畅的.

4.2 JavaScript调用异步C#方法

走弯路后的说明:BoundObject等这三个类以及里面的方法都是可以自己任意定义实现的,和普通的方法类没有太大区别,没有必要去源码中拷过来.

从源码的CefSharp.Example中找到三个类BoundObject、SubBoundObject、ExceptionTestBoundObject的源码拷过来,记得对应着自己的项目把命名空间名改了。

如果是.net4.0,TestCallback、TestCallbackException两个方法有提示async/await、Task.Run的报错,处理方式:

  • 直接升级到.NET Framework 4.5:从用户安装便捷性上讲,个人感觉完全没必要
  • 直接修改掉,因为这是测试的代码,可自己写不用Task.Run,详情请参阅CSDN论坛-Task.Factory.StartNew()和Task.Run()有什么区别CSDN论坛-task .run必须是 4.5框架,4.0里没有;如果是想在.net4.0下使用async/await还有别的方法-直接Nuget搜索安装Microsoft.Bcl.Async,如果搜索太慢或者搜索不到可以直接在nuget控制台执行Install-Package Microsoft.Bcl.Async.如果和我一样提示Nuget版本2.7太低、至少需要2.8的,需要卸载升级Nuget,步骤:
    • 卸载:打开VS-〉打开菜单“工具”-“扩展管理器”-〉选择“NuGet Package Manager”-〉点击“卸载”,然后会提示重启,不自动重启的话可以自己手动重启
    • 下载新版本nugethttps://dist.nuget.org/index.html,根据你的vs版本选择下载后缀是.vsix,直接安装就行,装完最好再重启一下vs.

我这里选择不升级.net 4.5后面一种方法,同时安装Microsoft.Bcl.Async.

这里实现的是一个延时回调的例子,即点一个按钮,调用绑定的C#方法在3秒后显示一条消息同时调用js方法立即显示一条消息。

测试内容准备:

  • BoundObject中定义回调方法(可以自己定义一个空的BoundObject类,增加一下内容)

    public void TestCallback(IJavascriptCallback javascriptCallback)

    {

    //.net 4.0 的写法

    const int taskDelay = 3000;

    Task.Factory.StartNew(async () =>

    {

    Delay(taskDelay);

    using (javascriptCallback)

    {

    //var response = new CallbackResponseStruct("This callback from C# was delayed " + taskDelay + "ms");

    await javascriptCallback.ExecuteAsync(" 来自C#的返回值,在当前延迟" + taskDelay + "ms");

    }

    });

    /*

    //.net 4.5的写法

    const int taskDelay = 1500;

    Task.Run(async () =>

    {

    await Task.Delay(taskDelay);

                  using (javascriptCallback)
    {
    //NOTE: Classes are not supported, simple structs are
    var response = new CallbackResponseStruct("This callback from C# was delayed " + taskDelay + "ms");
    await javascriptCallback.ExecuteAsync(response);
    }
    });
    */
    }
  • 在Form中给ChromiumWebBrowser增加绑定,第三个参数false忽略方法名大小写建议不要忘记,否则JS中掉用时方法名默认区分大小写

    webBrower.RegisterJsObject("bound", new BoundObject(),false);

  • 新建个html,body中录入一下内容

          <p> Javascript Callback Test </p>
    <script type="text/javascript">
    function callback(s) {
    var result = document.getElementById('show');
    result.innerText += "callback返回值:" + s.toString() + " 时间:" + Date();
    }
    function TestCallback() {
    //调用后台C#方法TestCallback,返回结果回调方法callback
    bound.TestCallback(callback);
    var result = document.getElementById('show');
    result.innerText = "方法返回 时间: " + Date() + "\n";
    //window.location.assign("http://www.baidu.com");
    }
    </script>
    <button onclick="TestCallback()">TestCallBakck</button>
    <br />
    <span id="show"></span>

可以运行一下了,点击一下TestCallBakck按钮,会首先显示一行内容与时间,3秒后显示第二行内容.

4.3 JavaScript调用带参数C#方法

准备内容:

  • BoundObject添加Repeat方法

              public string Repeat(string str, int n)
    {
    string result = String.Empty;
    for (int i = 0; i < n; i++)
    {
    result += str;
    }
    return result;
    }
  • html内容

          <p>带参数调用C# repeat方法</p>
    <span id="content"></span>
    <script type="text/javascript">
    var result = bound.Repeat("hello ", 6);
    document.getElementById("content").innerHTML = ""+result+"";
    </script>

执行结果

4.4 JavaScript调用委托C#方法

这里将一个方法ReturnJsonEmployeeList作为参数进行传递,并返回一个json数据进行解析展示

  • BoundObject中添加方法

          public string ReturnJsonEmployeeList()
    {
    return "{\"employees\":[{\"firstName\":\"John\", \"lastName\":\"Doe\"},{\"firstName\":\"Anna\", \"lastName\":\"Smith\"},{\"firstName\":\"Peter\", \"lastName\":\"Jones\"}]}";
    }
  • html内容

           <p> 委托C#方法-返回json字符串</p>
    <script type="text/javascript">
    function myfunc(fucPara) {
    return fucPara();
    }
    var res = myfunc(bound.ReturnJsonEmployeeList);
    document.write("委托输出结果:" + res + "<br>");
    var json = JSON.parse(res); //eval("'"+ res+"'");
    document.write("employees 数量:" + json.employees.length + "<br>");
    document.write("json.employees[0].lastName :" + json.employees[0].lastName);
    </script>

运行结果:

4.5 JavaScript调用C#返回实体对象

准备内容

  • 新建类SubBoundObject,对照添加以下内容

                   public class SubBoundObject
    {
    public string SimpleProperty { get; set; }
    public SubBoundObject()
    {
    SimpleProperty = "This is a very simple property.";
    }
    public string GetMyType()
    {
    return "My Type is " + GetType();
    }
    public string EchoSimpleProperty()
    {
    return SimpleProperty;
    }
    }
  • BoundObject中添加内容

              public SubBoundObject SubObject { get; set; }
    public SubBoundObject GetSubObject()
    {
    return SubObject;
    }
  • html中添加内容

           <p>返回实体对象</p>
    <script type="text/javascript">
    document.write("bound.GetSubObject().SimpleProperty : " + bound.GetSubObject().SimpleProperty);
    </script>

运行结果:

4.6 ChromiumWebBrowser控件扩展IContextMenuHandler接口实现禁用右击按钮菜单

禁用右击菜单需要创建一个类实现接口IContextMenuHandler,然后把这个类赋值给ChromiumWebBrowser的MenuHandler即可。这里创建类MenuHandler:

	 internal class MenuHandler : IContextMenuHandler
{
public void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model)
{
model.Clear();
}
public bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, CefMenuCommand commandId, CefEventFlags eventFlags)
{
return false;
}
public void OnContextMenuDismissed(IWebBrowser browserControl, IBrowser browser, IFrame frame)
{
}
public bool RunContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model, IRunContextMenuCallback callback)
{
return false;
}
}

配置到ChromiumWebBrowser:

webBrower.MenuHandler = new Class.MenuHandler();

这里只是禁用了菜单,也可以在相关事件里面增加内容,实现自定义右击菜单、不同页面的不同右击菜单.

4.6 WebGL页面渲染

WebGL(全写Web Graphics Library)是一种3D绘图标准,这种绘图技术标准允许把JavaScript和OpenGL ES 2.0结合在一起,通过增加OpenGL ES 2.0的一个JavaScript绑定,WebGL可以为HTML5 Canvas提供硬件3D加速渲染,这样Web开发人员就可以借助系统显卡来在浏览器里更流畅地展示3D场景和模型了,还能创建复杂的导航和数据视觉化。显然,WebGL技术标准免去了开发网页专用渲染插件的麻烦,可被用于创建具有复杂3D结构的网站页面,甚至可以用来设计3D网页游戏等等。

使用WebGL可以实现很炫的页面效果,以下这些实例都可以直接应用到一个引入了CefSharp的WinFrom桌面程序上面.

9个令人震惊的WebGL示例

20个使用WebGL和Three.js实现的网页场景

5、依赖项

5.1必需的运行环境

CefSharp官方文件readme.txt中有以下要求:

  • 根据X86/X64安装对应的 Visual C++ Redistributable Packages for Visual Studio 2013
  • 安装.Net 4.0或者.Net 4.0 Client Profile
  • 必有的依赖项
    • libcef.dll (CEF code)
    • icudtl.dat (Unicode Support data)
    • CefSharp.Core.dll, CefSharp.dll,

      CefSharp.BrowserSubprocess.exe, CefSharp.BrowserSubProcess.Core.dll
  • 根据不同的开发平台CefSharp.WinForms.dll、CefSharp.Wpf.dll、CefSharp.OffScreen.dll至少有一个

5.2依赖内容排错

重要说明:不想看高(dan)达(dan)上(teng)分析的,请直接看5.3依赖列表

因为我这是nuget引入的,debug/release生成的内容很多,直接运行也是成功的,因此我以发布为例,实际和debug/release下的调试是一样的。

首先发布好的内容是这样的



直接运行setup.exe会有很多报错,因为vs的发布过程中忽略很多依赖内容,下面介绍一下怎么一步步定位到缺少的依赖项:

  • 运行生成的exe,会报错这个



    遇到这个问题的肯定没好好看上边的内容,从源码或者debug/release下找到libcef.dll、icudtl.dat考到exe目录下这个错误就没有了
  • 运行exe会有新的问题,xxx已停止工作-点击关闭程序,注意目录下出现了一个debug.log,打开显示

    FATAL:v8_initializer.cc(155)] Failed to open V8 file 'D:\Project\2013\CefSharpDemo\CefSharpDemo\发布\Application Files\CefSharpDemo_1_0_0_7\natives_blob.bin' (reason: -4)

说明缺少natives_blob.bin,同上边直接拷贝过来

  • 继续运行exe,form1出现了但是没有内容,这时候看log是没有新的报错的,但是请持续观察,报错需要等一会儿才会进来

    [1226/142128:WARNING:resource_bundle.cc(311)] locale_file_path.empty() for locale

    [1226/142128:ERROR:main_delegate.cc(724)] Could not load locale pak for en-US

    [1226/142128:ERROR:main_delegate.cc(731)] Could not load cef.pak

    [1226/142128:ERROR:main_delegate.cc(748)] Could not load cef_100_percent.pak

    [1226/142128:ERROR:main_delegate.cc(766)] Could not load cef_extensions.pak

    根据报错加入locales\en-US.pak 、 cef.pak、cef_100_percent.pak、cef_extensions.pak

  • 继续运行exe,form1出现了但是没有内容,仔细研究日志

    [1226/142128:ERROR:child_process_launcher.cc(443)] Failed to launch child process

    [1226/142129:ERROR:child_process_launcher.cc(443)] Failed to launch child process

    [1226/142925:ERROR:child_process_launcher.cc(443)] Failed to launch child process

    [1226/142926:ERROR:child_process_launcher.cc(443)] Failed to launch child process

    [1226/143326:ERROR:child_process_launcher.cc(443)] Failed to launch child process

    [1226/143327:ERROR:child_process_launcher.cc(443)] Failed to launch child process

    [1226/143502:ERROR:child_process_launcher.cc(443)] Failed to launch child process

    [1226/143503:ERROR:child_process_launcher.cc(443)] Failed to launch child process

    看懂了吗,没看懂?

    好吧,我也没看懂....只好把debug/release下的文件往这边粘贴然后试试,然后在粘了CefSharp.BrowserSubprocess.Core.dll CefSharp.BrowserSubprocess.exe两个之后奇迹发生了....抓紧把之前粘的全删了...

  • 现在已经正常了,但是、但是log里面还有报错

      [1226/145245:ERROR:gpu_child_thread.cc(260)] Exiting GPU process due to errors during initialization
    [1226/145245:ERROR:browser_gpu_channel_host_factory.cc(133)] Failed to launch GPU process.

好了不废话了,经过我的九牛二虎之力,发现加入libEGL.dll、libGLESv2.dll、d3dcompiler_43.dll、d3dcompiler_47.dll就OK了

5.3依赖文件列表

总结一下,CefSharp必有的文件:

---locales

| |--en-US.pak

|--cef.pak

|--cef_100_percent.pak

|--cef_extensions.pak

|--CefSharp.BrowserSubprocess.Core.dll

|--CefSharp.BrowserSubprocess.exe

|--CefSharp.Core.dll

|--CefSharp.dll

|--CefSharp.WinForms.dll

|--d3dcompiler_43.dll

|--d3dcompiler_47.dll

|--icudtl.dat

|--libcef.dll

|--libEGL.dll

|--libGLESv2.dll

|--natives_blob.bin

补充一下,运行环境vs2013、.NET4.0,Winfrom,CefSharp v40.0.1.

6、总结

根据今天初步的部署、测试,感觉CefSharp可以算是比较成熟的CEF的在.net下的实现了,JavaScript和C#的交互做的简单易用,感觉可以比较容易的将一个Web应用的资源经过一定的重新整合打造成为一个桌面程序.

吐槽:一个字,因为从根本上是集成了一个chrome浏览器,所以以上简单的Demo的发布程序的x64、release版本就达到了99.5M,360压缩、7z格式压缩后30.6m,正式项目增加了代码、引入了其他的dll、资源文件等会更大;不知道有没有方法可以做精简

以上均为个人看法,各路大神请指点

7、源码下载与参考资料

7.1提供了两个版本

	CefSharpDemo20161227 包含packages 157M
CefSharpDemo20161227 不含packages 131K

下载请去原文:http://huisky.com/blog/16122515111968

7.2参考资料

Winform下CefSharp的引用、配置、实例与报错排除(源码)的更多相关文章

  1. CentOS 下 安装 nginx 执行配置命令 ./configure 报错

    CentOS 下 安装 nginx 执行配置命令 ./configure --prefix=/opt/nginx --sbin-path=/usr/bin/nginx 时提示以下错误: checkin ...

  2. [Spark内核] 第31课:Spark资源调度分配内幕天机彻底解密:Driver在Cluster模式下的启动、两种不同的资源调度方式源码彻底解析、资源调度内幕总结

    本課主題 Master 资源调度的源码鉴赏 [引言部份:你希望读者看完这篇博客后有那些启发.学到什么样的知识点] 更新中...... 资源调度管理 任务调度与资源是通过 DAGScheduler.Ta ...

  3. 配置Eclipse可以查看JDK类库源码

    一.配置方法 配置Eclipse可以查看JDK类库源码 Window->Preferences->Java->Installed JREs 若没有JRE,需要自己添加进来,有的话,点 ...

  4. 解决Linux下启动Tomcat遇到Neither the JAVA_HOME ...报错

    解决Linux下启动Tomcat遇到Neither the JAVA_HOME ...报错 Neither the JAVA_HOME nor the JRE_HOME environment var ...

  5. 【spring boot】spring cloud下spring boot微服务启动没有报错,但是访问访问不到

    spring cloud下spring boot微服务启动没有报错,但是访问访问不到 解决方法: 可能是端口被占用了,但是依旧启用成功了. 更改一下项目启用的端口号,再重新启动查看是否可以正常访问.

  6. 配置MySQL主从复制报错Last_IO_Error: Fatal error: The slave I/O thread stops because master and slave have equal MySQL server ids; these ids must be different for replication to work

    配置MySQL主从复制报错 ``` Last_IO_Error: Fatal error: The slave I/O thread stops because master and slave ha ...

  7. 解决jira配置gmail邮箱报错

    具体报错: AuthenticationFailedException: 535-5.7.8 Username and Password not accepted. Learn more at 535 ...

  8. Maven下Spring + SpringMvc + Hibernate4 配置实例

    1. 开发环境 IDEA 2. 在pom.xml中配置引用相关的包. <properties> <junit.version>4.10</junit.version> ...

  9. Windows下Memcached安装与配置实例

    环境声明: 服务器: Windows Server 2008r2: Memcached: Memcached 64-bit for Windows(64位) From: http://www.urie ...

随机推荐

  1. MacBook安装双系统(Windows多分区)

    分区 ---------- 启动电脑,放入mac os安装盘,按alt选择光盘启动. 1. 在工具菜单里选择磁盘工具对整个硬盘进行分区: ----------- 第一个是  exFAT.Msdos 格 ...

  2. swagger for c# webapi

    最近迷上了前后端分离的开发架构,工作中的项目几乎都采取这种模式,自己主要担任服务端RestFul风格的Webapi开发.那么问题来了,当前端开发人员找我要api说明文档的时候,曾一度非常可耻的冒出过w ...

  3. C# cmd执行命令

    CMD命令执行 ///<summary>         /// cmd命令执行,在cmd上可以执行的语句,直接传到这里,调用grads画图实例如下:         ///  Cmd(& ...

  4. jquery 表单清空

    $(':input','#myform') .not(':button, :submit, :reset, :hidden') .val('') .removeAttr('checked') .rem ...

  5. iOS开发UI篇—xib的简单使用

    iOS开发UI篇—xib的简单使用 一.简单介绍 xib和storyboard的比较,一个轻量级一个重量级. 共同点: 都用来描述软件界面 都用Interface Builder工具来编辑 不同点: ...

  6. Git之(一)Git是什么

    为什么使用Git 孔子曾经曰过的,名正则言顺 言顺则事成. 我们在学习一项新技术之前,弄清楚为什么要学它至关重要,至于为什么要学习Git,我用一段if-else语句告诉你原因: if(你相信我){ 我 ...

  7. 导弹拦截问题(DP+贪心)

    1. 拦截导弹(Noip1999) 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度. ...

  8. js获取浏览器屏幕的尺寸

    浏览器屏幕尺寸参照表: 如何获取屏幕宽度: 网页可见区域宽: document.body.clientWidth网页可见区域高: document.body.clientHeight网页可见区域宽: ...

  9. Python Logging模块 输出日志颜色、过期清理和日志滚动备份

    # coding:utf-8 import logging from logging.handlers import RotatingFileHandler # 按文件大小滚动备份 import co ...

  10. consul 集群

    主机运行 : consul agent -server -bootstrap-expect 2  -data-dir D:\consul  -node=winyh -bind=192.168.10.1 ...