Winform 下 CefSharp 的引用, 配置, 实例与报错排除
本文详细介绍了 CefSharp 在 vs2013,.net4.0 环境下, 创建 Winfrom 项目, 引用 CefSharp 的方法, 演示了 winfrom 下 CefSharp 的基本使用, 包括显示网页 url / 本地 html 显示, JavaScript 调用异步 C# 方法, JavaScript 调用带参数 C# 方法, JavaScript 调用委托 C# 方法, JavaScript 调用 C# 返回实体对象, ChromiumwebBrowser 控件扩展 IContextMenuHandler 接口实现禁用右击按钮菜单, 简单介绍 WebGL 页面渲染; 详细介绍了的 CefSharp 依赖项, 常见报错查看与必要依赖项分析, 最后进行了简单总结, 并提供了源码的下载.
[TOC]
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 项目源码下载
源码下载 github 托管地址 https://github.com/cefsharp/CefSharp 目前最新 v53.0.1
源码结构介绍构建基于 Chromium 的应用程序 - 猫不理饼
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/49.0.1 .
等待导入成功, 生成一下... 报错...
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 动画 http://www.html5tricks.com/demo/html5-CSS3-windmill/index2.html , 修改完成, 同样运行就可以看到页面了, 运行还是挺流畅的.
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()有什么区别 http://bbs.csdn.net/topics/390946849 , CSDN 论坛 - task .run 必须是 4.5 框架, 4.0 里没有 http://bbs.csdn.net/topics/390701152 ; 如果是想在. net4.0 下使用 async/await 还有别的方法 - 直接 Nuget 搜索安装 Microsoft.Bcl.Async, 如果搜索太慢或者搜索不到可以直接在 nuget 控制台执行
Install-Package Microsoft.Bcl.Async
. 如果和我一样提示 Nuget 版本 2.7 太低, 至少需要 2.8 的, 需要卸载升级 Nuget, 步骤:
卸载: 打开
VS-打开菜单 "工具"-"扩展管理器"-选择 "NuGet Package Manager"-点击 "卸载"
, 然后会提示重启, 不自动重启的话可以自己手动重启
下载新版本 nuget https://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 示例 http://www.open-open.com/news/view/9d8136/
20 个使用 WebGL 和 Three.js 实现的网页场景 http://www.chinaz.com/design/2013/1008/320641.shtml
5, 依赖项
5.1 必需的运行环境
CefSharp 官方文件 readme.txt 中有以下要求:
根据 X86/X64 安装对应的 Visual C++ Redistributable Packages for Visual Studio 2013 https://www.microsoft.com/zh-CN/download/details.aspx?id=40784
安装. 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
来源: https://www.cnblogs.com/Leo_wl/p/6239233.html#_label6_1