人虽然渺小,人生虽然短促,但是人能学,人能修身,人能自我完善,人的可贵在人自身。
——杨绛
一、Xilium.CefGlue 简介
Xilium.CefGlue 是一个开源项目,它是基于 Chromium Embedded Framework (CEF) 的一个 .NET 绑定库。CEF 是一个强大的开源项目,它允许开发者在自己的应用程序中嵌入完整的 Chromium 浏览器引擎。
Xilium.CefGlue 提供了一个简单易用的方式,让开发者能够使用 C# 或其他 .NET 语言来创建基于 Chromium 的应用程序。它提供了对 CEF 的封装,使得开发者可以轻松地在自己的应用程序中嵌入一个功能强大的浏览器引擎。
使用 Xilium.CefGlue,开发者可以实现各种功能,例如创建自定义的浏览器窗口、加载网页、处理 JavaScript 和 DOM 事件、执行 JavaScript 代码等等。它还支持与原生代码的交互,可以通过 CEF 的扩展机制来扩展功能。
Xilium.CefGlue 的优点包括:
- 跨平台:CEF 支持多个操作系统,包括 Windows、Linux 和 macOS,因此 Xilium.CefGlue 也可以在这些平台上运行。
- 强大的功能:由于基于 Chromium,Xilium.CefGlue 提供了一个功能丰富的浏览器引擎,支持 HTML5、CSS3、JavaScript 等最新的 Web 技术。
- 易于使用:Xilium.CefGlue 提供了简单易用的 API,使得开发者可以快速上手并构建自己的应用程序。
- 社区支持:作为一个开源项目,Xilium.CefGlue 拥有活跃的社区,开发者可以从社区中获取支持和贡献代码。
二、参考资料
Xilium.CefGlue 文档不多,可以参照 CEF 官网文档,
chromiumembedded / cef / wiki / GeneralUsage — Bitbuckethttps://bitbucket.org/chromiumembedded/cef/wiki/GeneralUsagechromiumembedded / cef / wiki / JavaScriptIntegration — Bitbucket
https://bitbucket.org/chromiumembedded/cef/wiki/JavaScriptIntegration.md
三、项目源代码下载
后续实现的所有 Demo 都基于官方项目源码上修改调整,
# 必应搜索关键字 CefGlue wiki
# 官网 https://xilium.bitbucket.io/cefglue/
# api文档 https://xilium.bitbucket.io/cefglue/doc/index.html
# cef-builds https://cef-builds.spotifycdn.com/index.html
首先下载项目源代码,
# 指定分支 5615
# git clone -b 5615 https://gitlab.com/xiliumhq/chromiumembedded/cefglue.git
# 默认 main
git https://gitlab.com/xiliumhq/chromiumembedded/cefglue.git
查看对应 CEF 版本,
# CefGlue\Interop\version.g.cs
# CEF_VERSION
然后下载对应版本的CEF,
如果是 Debug 编译模式,则需要将 Debug 与 Resources 这两个文件夹下的所有内容拷贝到对应的 bin 文件夹,
如果是 Release 编译模式,则需要将 Release 与 Resources 这两个文件夹下的所有内容拷贝到对应的bin文件夹,
四、启动 Xilium.CefGlue.Client
Xilium.CefGlue.Client 项目设为启动项,Program.cs 注释掉以下这行,
#必须使用 Release 模式运行,Debug 模式会白屏闪退,
//BrowserSubprocessPath = browserProcessPath,
这里说明一下,CefApp 通常需要一个主进程(Browser Process)和一个子进程(Render Process)运行,主进程负责管控窗口生命周期,子进程负责管控Web生命周期,所有网页资源的加载、js脚本都会在子进程中执行,这样设计的好处就是,就算子进程崩溃,也不会影响主应用的运行。当 BrowserSubprocessPath 未指定子进程路径值时,CefApp 则以当前主进程路径作为默认值。
访问必应官网效果如下,
在 Debug 模式下黑屏闪退的问题,我们可以通过日志查看具体原因,
var settings = new CefSettings
{
//BrowserSubprocessPath = browserProcessPath,
MultiThreadedMessageLoop = true,
LogSeverity = CefLogSeverity.Error,
LogFile = "CefGlue.log",
};
报错日志如下,
[0130/153649.007:FATAL:scoped_com_initializer.cc(56)] Check failed: ((HRESULT)0x80010106L) != hr_ (-2147417850 vs. -2147417850)Invalid COM thread model change
[0130/153651.532:ERROR:gpu_process_host.cc(952)] GPU process exited unexpectedly: exit_code=-2147483645
[0130/153651.800:ERROR:ssl_client_socket_impl.cc(985)] handshake failed; returned -1, SSL error code 1, net_error -103
[0130/153653.256:FATAL:scoped_com_initializer.cc(56)] Check failed: ((HRESULT)0x80010106L) != hr_ (-2147417850 vs. -2147417850)Invalid COM thread model change
[0130/153655.150:ERROR:gpu_process_host.cc(952)] GPU process exited unexpectedly: exit_code=-2147483645
[0130/153656.686:FATAL:scoped_com_initializer.cc(56)] Check failed: ((HRESULT)0x80010106L) != hr_ (-2147417850 vs. -2147417850)Invalid COM thread model change
[0130/153658.534:ERROR:gpu_process_host.cc(952)] GPU process exited unexpectedly: exit_code=-2147483645
[0130/153659.936:FATAL:scoped_com_initializer.cc(56)] Check failed: ((HRESULT)0x80010106L) != hr_ (-2147417850 vs. -2147417850)Invalid COM thread model change
[0130/153701.879:ERROR:gpu_process_host.cc(952)] GPU process exited unexpectedly: exit_code=-2147483645
[0130/153703.454:FATAL:scoped_com_initializer.cc(56)] Check failed: ((HRESULT)0x80010106L) != hr_ (-2147417850 vs. -2147417850)Invalid COM thread model change
[0130/153705.239:ERROR:gpu_process_host.cc(952)] GPU process exited unexpectedly: exit_code=-2147483645
[0130/153706.763:FATAL:scoped_com_initializer.cc(56)] Check failed: ((HRESULT)0x80010106L) != hr_ (-2147417850 vs. -2147417850)Invalid COM thread model change
[0130/153708.542:ERROR:gpu_process_host.cc(952)] GPU process exited unexpectedly: exit_code=-2147483645
[0130/153710.003:FATAL:scoped_com_initializer.cc(56)] Check failed: ((HRESULT)0x80010106L) != hr_ (-2147417850 vs. -2147417850)Invalid COM thread model change
[0130/153711.792:ERROR:gpu_process_host.cc(952)] GPU process exited unexpectedly: exit_code=-2147483645
[0130/153713.272:FATAL:scoped_com_initializer.cc(56)] Check failed: ((HRESULT)0x80010106L) != hr_ (-2147417850 vs. -2147417850)Invalid COM thread model change
[0130/153715.113:ERROR:gpu_process_host.cc(952)] GPU process exited unexpectedly: exit_code=-2147483645
[0130/153716.724:FATAL:scoped_com_initializer.cc(56)] Check failed: ((HRESULT)0x80010106L) != hr_ (-2147417850 vs. -2147417850)Invalid COM thread model change
[0130/153718.525:ERROR:gpu_process_host.cc(952)] GPU process exited unexpectedly: exit_code=-2147483645
[0130/153718.525:FATAL:gpu_data_manager_impl_private.cc(440)] GPU process isn't usable. Goodbye.
日志中可以看出,GPU 进程不可用,导致了黑屏,这跟之前说到的子进程是相关的,如此看来,Debug模式下,必须要指定 BrowserSubprocessPath 子进程参数,
browserProcessPath = @"D:\AwsomeWorkSpace\cefglue-5481\CefGlue.Demo.WinForms\bin\x64\Release\net5.0-windows\Xilium.CefGlue.Demo.WinForms.exe";
var settings = new CefSettings
{
BrowserSubprocessPath = browserProcessPath,
MultiThreadedMessageLoop = true,
LogSeverity = CefLogSeverity.Error,
LogFile = "CefGlue.log",
};
可以看到,指定了子进程之后,能够使用 Debug 模式启动项目了,
五、JS 调用 C#
1、CefRuntime.RegisterExtension
定义 DemoRenderProcessHandler ,该类继承 CefRenderProcessHandler,重写 OnWebKitInitialized,通过 CefRuntime.RegisterExtension 注册 C# 方法,
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Xilium.CefGlue.Client.Handlers
{
public class DemoRenderProcessHandler : CefRenderProcessHandler
{
/// <summary>