简介:这份资源是CEF(Chromium Embedded Framework)3.2357.1271.g8e0674e的Windows 32位官方二进制包备份,面向需要在C++项目中嵌入浏览器内核、且依赖NPAPI插件能力的开发者。由于官方渠道已无法下载,该版本成为CEF支持NPAPI的最高版本,对维护旧插件体系或兼容历史项目的团队具有不可替代的参考价值。压缩包共580个文件,约120.41MB,以310个h头文件与156个cc源文件为主体,便于查阅接口定义与实现细节;同时包含57个pak资源包、12个dll动态库、4个lib导入库及若干manifest、gypi、cmake构建配置,可直接用于工程集成与编译验证。目前已有515人学习下载,适合具备一定C++与浏览器内核基础的中高级开发者研究使用。1. 拿到 cef_binary_3.2357.1271 这个包,先搞清楚它能干什么如果你正在维护一套基于 CEF 的 Windows 桌面客户端,尤其是那种需要嵌入浏览器控件、还要跟 NPAPI 插件打交道的旧项目,那你大概率绕不开cef_binary_3.2357.1271.g8e0674e_windows32这个版本。它对应的是 CEF 3.2357 分支,Chromium 内核大约在 43 到 45 之间,属于 CEF 3 时代中后期一个相对稳定的节点。这个包解决的核心问题很具体:在 32 位 Windows 上,用 C++ 把 Chromium 嵌入到自己的进程里,同时保留对 NPAPI 插件的兼容能力。适合谁?适合那些不能随便升级内核、业务代码里还挂着 Flash 或自定义 NPAPI 插件、编译环境停留在 VS2013 或 VS2015 的团队。如果你是新项目,直接上 CEF 4 或 WebView2 更省事;但如果你手里就是这套老代码,这个包就是你的“后悔药”。2. 拆包看结构:cef_binary 里到底有什么2.1 目录布局与关键文件识别下载完解压,你会看到类似这样的结构:cef_binary_3.2357.1271.g8e0674e_windows32/ ├── cmake/ ├── include/ ├── libcef_dll/ ├── Release/ ├── Debug/ ├── Resources/ ├── tests/ ├── tools/ └── CMakeLists.txtinclude/里是 CEF 的公共头文件,libcef_dll/是 C++ 包装层的源码,Release/和Debug/里放着libcef.dll、libcef.lib以及cef_sandbox.lib。Resources/下有icudtl.dat、cef.pak、cef_100_percent.pak这些运行时资源。tests/里有一个cefsimple和cefclient,前者是最小可运行示例,后者是功能演示。很多人拿到包直接去翻tests/cefsimple,这是对的,但别急着编译,先把CMakeLists.txt里的CEF_ROOT和PROJECT_ARCH看清楚。2.2 版本号里的信息量3.2357.1271.g8e0674e这个版本串不是随便编的。3表示 CEF 3,2357是 Chromium 的 branch 号,1271是 CEF 自己的修订号,g8e0674e是 git commit 短哈希。windows32明确告诉你这是 32 位构建。这个版本对应的 Chromium 内核大约在 43.0.2357 附近,NPAPI 还没有被完全移除,但已经处于“可用但不推荐”的状态。如果你需要确认某个 API 是否存在,直接去include/里搜头文件,比查文档快。2.3 编译前的环境准备我一般会先确认三件事:VS 版本、CMake 版本、Windows SDK 版本。这个包官方推荐 VS2013 Update 5 或 VS2015 Update 3。CMake 用 3.5 以上就行,但别用太新的,CMake 3.20 之后有些策略变更会导致老项目报错。Windows SDK 用 8.1 或 10 的 10586 版本比较稳。下面是我常用的 CMake 生成命令:mkdir build cd build cmake -G "Visual Studio 14 2015" -A Win32 -DCEF_ROOT="D:/cef_binary_3.2357.1271.g8e0674e_windows32" ..-G指定生成器,-A Win32强制 32 位,-DCEF_ROOT指向解压目录。注意路径里不要有中文和空格,否则 CMake 会给你脸色看。生成成功后,用 VS 打开cef.sln,先编译libcef_dll_wrapper这个目标,再编译cefsimple。3. 把 cefsimple 跑起来:从编译到窗口弹出3.1 编译 libcef_dll_wrapper 的坑libcef_dll_wrapper是 CEF 的 C++ 包装静态库,所有 C++ 接口都依赖它。编译时最常见的报错是error C2039: 'unique_ptr': is not a member of 'std',这是因为 VS2013 对 C++11 支持不完整,而 CEF 头文件里用了std::unique_ptr。解决办法是在项目属性里把C++ Language Standard设为Default,或者手动在stdafx.h里加#include <memory>。另一个坑是CEF_USE_SANDBOX宏,如果你不需要沙箱,在 CMake 里加-DUSE_SANDBOX=OFF,否则会链接cef_sandbox.lib失败。3.2 cefsimple 的入口逻辑cefsimple的main函数在cefsimple_win.cc里,核心流程是:初始化 CEF 命令行参数、加载CefApp实现、创建浏览器窗口、进入消息循环。关键代码段如下:// 初始化 CEF CefMainArgs main_args(hInstance); CefRefPtr<SimpleApp> app(new SimpleApp); int exit_code = CefExecuteProcess(main_args, app.get(), nullptr); if (exit_code >= 0) { return exit_code; } CefSettings settings; settings.no_sandbox = true; settings.multi_threaded_message_loop = false; CefInitialize(main_args, settings, app.get(), nullptr); // 创建浏览器窗口 CefWindowInfo window_info; window_info.SetAsPopup(nullptr, L"cefsimple"); CefBrowserSettings browser_settings; CefRefPtr<SimpleHandler> handler(new SimpleHandler); CefBrowserHost::CreateBrowser(window_info, handler, L"http://localhost:8080", browser_settings, nullptr); CefRunMessageLoop(); CefShutdown();CefExecuteProcess是子进程入口,必须放在CefInitialize之前。settings.no_sandbox = true在调试时建议打开,否则沙箱会拦截一些文件访问。multi_threaded_message_loop设为false表示用主线程跑消息循环,适合简单场景。CreateBrowser的第三个参数是初始 URL,你可以改成自己的页面。3.3 运行时资源缺失的排查编译通过后,直接运行cefsimple.exe大概率会闪退。最常见的原因是icudtl.dat、cef.pak、cef_100_percent.pak没有拷到 exe 同级目录。CEF 在初始化时会去 exe 所在目录找这些文件,找不到就静默退出。我一般会在 VS 的“生成后事件”里加一条拷贝命令:xcopy /Y /E "$(SolutionDir)Resources\*" "$(OutDir)"另外,libcef.dll也要在 exe 同级目录。如果你把libcef.dll放在Release/里,记得一起拷过去。还有一点,cefsimple默认加载的页面是http://www.google.com,在国内网络环境下可能一直转圈,改成about:blank或本地页面能更快看到窗口。4. NPAPI 插件加载:老插件的最后一班车4.1 NPAPI 在 CEF 3.2357 里的状态这个版本里 NPAPI 还没有被完全移除,但默认是关闭的。你需要在CefSettings里设置settings.plugin_policy = PLUGIN_POLICY_ALLOW,或者在命令行加--enable-npapi。NPAPI 插件在 Windows 上通常以.dll形式存在,注册方式有两种:一种是写注册表HKEY_LOCAL_MACHINE\SOFTWARE\MozillaPlugins,另一种是通过CefRegisterPlugin动态注册。我一般用后者,因为不污染系统环境。4.2 动态注册 NPAPI 插件的代码模板// 注册 NPAPI 插件 CefRefPtr<CefPluginInfo> plugin_info(new CefPluginInfo); plugin_info->name = "MyLegacyPlugin"; plugin_info->path = L"C:\\plugins\\myplugin.dll"; plugin_info->version = "1.0.0"; plugin_info->description = "Legacy NPAPI plugin for internal use"; plugin_info->mime_types.push_back("application/x-myplugin"); CefRegisterPlugin(plugin_info);path必须是绝对路径,mime_types里的类型要和插件内部注册的一致。注册成功后,在页面里用<embed type="application/x-myplugin">就能加载。注意,NPAPI 插件运行在独立进程里,如果插件崩溃,浏览器窗口不会挂,但插件功能会失效。调试时可以在CefSettings里加settings.log_severity = LOGSEVERITY_VERBOSE,把插件加载日志打到debug.log里。4.3 插件加载失败的常见原因现象:页面里<embed>标签显示空白,控制台没有报错。原因:插件 DLL 依赖的 VC 运行库缺失,或者位数不匹配(32 位 CEF 只能加载 32 位插件)。解决:用Dependency Walker查 DLL 依赖,确认插件是 32 位编译的。另一个现象是插件加载后立即崩溃,原因通常是插件内部用了不兼容的线程模型。CEF 的 NPAPI 插件运行在单独的线程里,插件如果直接操作 UI 线程的资源,就会崩。解决:在插件代码里用NPN_PluginThreadAsyncCall把操作抛回主线程。5. 避坑与排查:那些让我加班到凌晨的细节5.1 现象:编译报错LNK2019: unresolved external symbol __imp__...原因:libcef_dll_wrapper没有正确链接,或者libcef.lib的路径不对。解决:检查 VS 项目属性里的“附加依赖项”是否包含libcef.lib和libcef_dll_wrapper.lib,库目录是否指向Release/和build/libcef_dll_wrapper/Release/。如果用的是 CMake 生成的工程,这些会自动配好,手动改过工程配置就容易出这个问题。5.2 现象:程序启动后白屏,日志里写Failed to load resource原因:cef.pak和icudtl.dat没有放在 exe 同级目录,或者locales/文件夹缺失。解决:把Resources/下的所有文件拷到 exe 目录,并在CefSettings里设置settings.locale = "zh-CN",同时确保locales/zh-CN.pak存在。如果不需要多语言,可以把locales/里除了en-US.pak之外的全删掉,减小体积。5.3 现象:NPAPI 插件在页面里加载了,但调用方法没反应原因:插件没有正确处理NPP_New和NPP_GetValue,或者 MIME 类型注册不匹配。解决:用chrome://plugins页面(这个版本还支持)查看插件是否被识别。如果识别到了但调用无效,检查插件是否实现了NP_Initialize和NP_GetEntryPoints。另外,CEF 的 NPAPI 实现和 Firefox 有细微差别,插件如果只针对 Firefox 开发,可能需要改NPP_GetValue里对NPPVpluginScriptableNPObject的处理。5.4 现象:多进程模式下,渲染进程频繁崩溃原因:32 位进程地址空间有限,Chromium 的多进程架构在 32 位下容易触发 OOM。解决:在CefSettings里设置settings.single_process = true,强制单进程模式。代价是稳定性下降,但能绕过地址空间限制。另一个办法是加--renderer-process-limit=1命令行参数,限制渲染进程数量。5.5 现象:升级 VS 版本后,CEF 头文件报大量 C4996 警告原因:新版 VS 把很多 C 运行时函数标记为不安全。解决:在项目属性里加_CRT_SECURE_NO_WARNINGS宏,或者用#pragma warning(disable:4996)包住 CEF 头文件。但注意,这只是屏蔽警告,不要真的去改 CEF 源码,否则升级版本时你会哭。6. 进阶:把 CEF 嵌入自己的 MFC 或 Qt 工程6.1 在 MFC 对话框里嵌入浏览器窗口MFC 工程里嵌入 CEF,核心是拿到对话框的HWND,然后传给CefWindowInfo::SetAsChild。代码片段:// 在对话框的 OnInitDialog 里 CefWindowInfo window_info; CRect rect; GetDlgItem(IDC_BROWSER_PLACEHOLDER)->GetWindowRect(&rect); ScreenToClient(&rect); window_info.SetAsChild(GetDlgItem(IDC_BROWSER_PLACEHOLDER)->GetSafeHwnd(), rect); CefBrowserSettings browser_settings; CefBrowserHost::CreateBrowser(window_info, handler, L"http://localhost:8080", browser_settings, nullptr);IDC_BROWSER_PLACEHOLDER是一个静态控件,用来占位。SetAsChild的第二个参数是矩形区域,CEF 会把浏览器窗口嵌到这个区域里。注意,MFC 的消息循环和 CEF 的消息循环要整合,否则浏览器窗口不刷新。我一般会在CWinApp::Run里调CefRunMessageLoop,或者用CefDoMessageLoopWork在OnIdle里手动泵消息。6.2 在 Qt 里嵌入 CEF 的注意事项Qt 的窗口句柄获取方式和 MFC 不同,需要用QWidget::winId()拿到WId,再转成HWND。另外,Qt 的事件循环和 CEF 的消息循环冲突更明显。常见做法是开一个单独的线程跑CefRunMessageLoop,或者用CefDoMessageLoopWork配合QTimer定时调用。我试过在 Qt 里用QTimer每 10ms 调一次CefDoMessageLoopWork,CPU 占用会上去,但兼容性最好。6.3 验证嵌入是否成功的三个检查点第一,浏览器窗口是否随父窗口缩放。如果父窗口拉伸时浏览器区域不跟着变,说明没有处理WM_SIZE消息,需要在OnSize里调CefBrowserHost::GetBrowser()->GetHost()->WasResized()。第二,输入焦点是否正常。点击浏览器区域后,键盘输入是否被浏览器接收。如果不行,检查父窗口是否拦截了WM_SETFOCUS。第三,关闭父窗口时,CEF 是否正常退出。如果进程残留,检查是否在OnDestroy里调了CefShutdown。这三个点过了,嵌入基本就稳了。6.4 一个我常用的调试技巧在CefSettings里设置settings.remote_debugging_port = 8088,然后浏览器里访问http://localhost:8088,就能用 DevTools 调试嵌入的页面。这个端口只在调试时开,发布时记得关掉。另外,settings.log_file = L"debug.log"可以把 CEF 内部日志写到文件里,排查初始化失败特别有用。从那以后我每次集成 CEF 到新工程,都强制走一遍“编译 wrapper → 拷资源 → 跑 cefsimple → 开远程调试 → 嵌到目标工程”这个流程,少一步都可能翻车。希望帮到你。本文还有配套的精品资源,点击获取
简介:这份资源是CEF(Chromium Embedded Framework)3.2357.1271.g8e0674e的Windows 32位官方二进制包备份,面向需要在C++项目中嵌入浏览器内核、且依赖NPAPI插件能力的开发者。由于官方渠道已无法下载,该版本成为CEF支持NPAPI的最高版本,对维护旧插件体系或兼容历史项目的团队具有不可替代的参考价值。压缩包共580个文件,约120.41MB,以310个h头文件与156个cc源文件为主体,便于查阅接口定义与实现细节;同时包含57个pak资源包、12个dll动态库、4个lib导入库及若干manifest、gypi、cmake构建配置,可直接用于工程集成与编译验证。目前已有515人学习下载,适合具备一定C++与浏览器内核基础的中高级开发者研究使用。1. 拿到 cef_binary_3.2357.1271 这个包,先搞清楚它能干什么如果你正在维护一套基于 CEF 的 Windows 桌面客户端,尤其是那种需要嵌入浏览器控件、还要跟 NPAPI 插件打交道的旧项目,那你大概率绕不开cef_binary_3.2357.1271.g8e0674e_windows32这个版本。它对应的是 CEF 3.2357 分支,Chromium 内核大约在 43 到 45 之间,属于 CEF 3 时代中后期一个相对稳定的节点。这个包解决的核心问题很具体:在 32 位 Windows 上,用 C++ 把 Chromium 嵌入到自己的进程里,同时保留对 NPAPI 插件的兼容能力。适合谁?适合那些不能随便升级内核、业务代码里还挂着 Flash 或自定义 NPAPI 插件、编译环境停留在 VS2013 或 VS2015 的团队。如果你是新项目,直接上 CEF 4 或 WebView2 更省事;但如果你手里就是这套老代码,这个包就是你的“后悔药”。2. 拆包看结构:cef_binary 里到底有什么2.1 目录布局与关键文件识别下载完解压,你会看到类似这样的结构:cef_binary_3.2357.1271.g8e0674e_windows32/ ├── cmake/ ├── include/ ├── libcef_dll/ ├── Release/ ├── Debug/ ├── Resources/ ├── tests/ ├── tools/ └── CMakeLists.txtinclude/里是 CEF 的公共头文件,libcef_dll/是 C++ 包装层的源码,Release/和Debug/里放着libcef.dll、libcef.lib以及cef_sandbox.lib。Resources/下有icudtl.dat、cef.pak、cef_100_percent.pak这些运行时资源。tests/里有一个cefsimple和cefclient,前者是最小可运行示例,后者是功能演示。很多人拿到包直接去翻tests/cefsimple,这是对的,但别急着编译,先把CMakeLists.txt里的CEF_ROOT和PROJECT_ARCH看清楚。2.2 版本号里的信息量3.2357.1271.g8e0674e这个版本串不是随便编的。3表示 CEF 3,2357是 Chromium 的 branch 号,1271是 CEF 自己的修订号,g8e0674e是 git commit 短哈希。windows32明确告诉你这是 32 位构建。这个版本对应的 Chromium 内核大约在 43.0.2357 附近,NPAPI 还没有被完全移除,但已经处于“可用但不推荐”的状态。如果你需要确认某个 API 是否存在,直接去include/里搜头文件,比查文档快。2.3 编译前的环境准备我一般会先确认三件事:VS 版本、CMake 版本、Windows SDK 版本。这个包官方推荐 VS2013 Update 5 或 VS2015 Update 3。CMake 用 3.5 以上就行,但别用太新的,CMake 3.20 之后有些策略变更会导致老项目报错。Windows SDK 用 8.1 或 10 的 10586 版本比较稳。下面是我常用的 CMake 生成命令:mkdir build cd build cmake -G "Visual Studio 14 2015" -A Win32 -DCEF_ROOT="D:/cef_binary_3.2357.1271.g8e0674e_windows32" ..-G指定生成器,-A Win32强制 32 位,-DCEF_ROOT指向解压目录。注意路径里不要有中文和空格,否则 CMake 会给你脸色看。生成成功后,用 VS 打开cef.sln,先编译libcef_dll_wrapper这个目标,再编译cefsimple。3. 把 cefsimple 跑起来:从编译到窗口弹出3.1 编译 libcef_dll_wrapper 的坑libcef_dll_wrapper是 CEF 的 C++ 包装静态库,所有 C++ 接口都依赖它。编译时最常见的报错是error C2039: 'unique_ptr': is not a member of 'std',这是因为 VS2013 对 C++11 支持不完整,而 CEF 头文件里用了std::unique_ptr。解决办法是在项目属性里把C++ Language Standard设为Default,或者手动在stdafx.h里加#include <memory>。另一个坑是CEF_USE_SANDBOX宏,如果你不需要沙箱,在 CMake 里加-DUSE_SANDBOX=OFF,否则会链接cef_sandbox.lib失败。3.2 cefsimple 的入口逻辑cefsimple的main函数在cefsimple_win.cc里,核心流程是:初始化 CEF 命令行参数、加载CefApp实现、创建浏览器窗口、进入消息循环。关键代码段如下:// 初始化 CEF CefMainArgs main_args(hInstance); CefRefPtr<SimpleApp> app(new SimpleApp); int exit_code = CefExecuteProcess(main_args, app.get(), nullptr); if (exit_code >= 0) { return exit_code; } CefSettings settings; settings.no_sandbox = true; settings.multi_threaded_message_loop = false; CefInitialize(main_args, settings, app.get(), nullptr); // 创建浏览器窗口 CefWindowInfo window_info; window_info.SetAsPopup(nullptr, L"cefsimple"); CefBrowserSettings browser_settings; CefRefPtr<SimpleHandler> handler(new SimpleHandler); CefBrowserHost::CreateBrowser(window_info, handler, L"http://localhost:8080", browser_settings, nullptr); CefRunMessageLoop(); CefShutdown();CefExecuteProcess是子进程入口,必须放在CefInitialize之前。settings.no_sandbox = true在调试时建议打开,否则沙箱会拦截一些文件访问。multi_threaded_message_loop设为false表示用主线程跑消息循环,适合简单场景。CreateBrowser的第三个参数是初始 URL,你可以改成自己的页面。3.3 运行时资源缺失的排查编译通过后,直接运行cefsimple.exe大概率会闪退。最常见的原因是icudtl.dat、cef.pak、cef_100_percent.pak没有拷到 exe 同级目录。CEF 在初始化时会去 exe 所在目录找这些文件,找不到就静默退出。我一般会在 VS 的“生成后事件”里加一条拷贝命令:xcopy /Y /E "$(SolutionDir)Resources\*" "$(OutDir)"另外,libcef.dll也要在 exe 同级目录。如果你把libcef.dll放在Release/里,记得一起拷过去。还有一点,cefsimple默认加载的页面是http://www.google.com,在国内网络环境下可能一直转圈,改成about:blank或本地页面能更快看到窗口。4. NPAPI 插件加载:老插件的最后一班车4.1 NPAPI 在 CEF 3.2357 里的状态这个版本里 NPAPI 还没有被完全移除,但默认是关闭的。你需要在CefSettings里设置settings.plugin_policy = PLUGIN_POLICY_ALLOW,或者在命令行加--enable-npapi。NPAPI 插件在 Windows 上通常以.dll形式存在,注册方式有两种:一种是写注册表HKEY_LOCAL_MACHINE\SOFTWARE\MozillaPlugins,另一种是通过CefRegisterPlugin动态注册。我一般用后者,因为不污染系统环境。4.2 动态注册 NPAPI 插件的代码模板// 注册 NPAPI 插件 CefRefPtr<CefPluginInfo> plugin_info(new CefPluginInfo); plugin_info->name = "MyLegacyPlugin"; plugin_info->path = L"C:\\plugins\\myplugin.dll"; plugin_info->version = "1.0.0"; plugin_info->description = "Legacy NPAPI plugin for internal use"; plugin_info->mime_types.push_back("application/x-myplugin"); CefRegisterPlugin(plugin_info);path必须是绝对路径,mime_types里的类型要和插件内部注册的一致。注册成功后,在页面里用<embed type="application/x-myplugin">就能加载。注意,NPAPI 插件运行在独立进程里,如果插件崩溃,浏览器窗口不会挂,但插件功能会失效。调试时可以在CefSettings里加settings.log_severity = LOGSEVERITY_VERBOSE,把插件加载日志打到debug.log里。4.3 插件加载失败的常见原因现象:页面里<embed>标签显示空白,控制台没有报错。原因:插件 DLL 依赖的 VC 运行库缺失,或者位数不匹配(32 位 CEF 只能加载 32 位插件)。解决:用Dependency Walker查 DLL 依赖,确认插件是 32 位编译的。另一个现象是插件加载后立即崩溃,原因通常是插件内部用了不兼容的线程模型。CEF 的 NPAPI 插件运行在单独的线程里,插件如果直接操作 UI 线程的资源,就会崩。解决:在插件代码里用NPN_PluginThreadAsyncCall把操作抛回主线程。5. 避坑与排查:那些让我加班到凌晨的细节5.1 现象:编译报错LNK2019: unresolved external symbol __imp__...原因:libcef_dll_wrapper没有正确链接,或者libcef.lib的路径不对。解决:检查 VS 项目属性里的“附加依赖项”是否包含libcef.lib和libcef_dll_wrapper.lib,库目录是否指向Release/和build/libcef_dll_wrapper/Release/。如果用的是 CMake 生成的工程,这些会自动配好,手动改过工程配置就容易出这个问题。5.2 现象:程序启动后白屏,日志里写Failed to load resource原因:cef.pak和icudtl.dat没有放在 exe 同级目录,或者locales/文件夹缺失。解决:把Resources/下的所有文件拷到 exe 目录,并在CefSettings里设置settings.locale = "zh-CN",同时确保locales/zh-CN.pak存在。如果不需要多语言,可以把locales/里除了en-US.pak之外的全删掉,减小体积。5.3 现象:NPAPI 插件在页面里加载了,但调用方法没反应原因:插件没有正确处理NPP_New和NPP_GetValue,或者 MIME 类型注册不匹配。解决:用chrome://plugins页面(这个版本还支持)查看插件是否被识别。如果识别到了但调用无效,检查插件是否实现了NP_Initialize和NP_GetEntryPoints。另外,CEF 的 NPAPI 实现和 Firefox 有细微差别,插件如果只针对 Firefox 开发,可能需要改NPP_GetValue里对NPPVpluginScriptableNPObject的处理。5.4 现象:多进程模式下,渲染进程频繁崩溃原因:32 位进程地址空间有限,Chromium 的多进程架构在 32 位下容易触发 OOM。解决:在CefSettings里设置settings.single_process = true,强制单进程模式。代价是稳定性下降,但能绕过地址空间限制。另一个办法是加--renderer-process-limit=1命令行参数,限制渲染进程数量。5.5 现象:升级 VS 版本后,CEF 头文件报大量 C4996 警告原因:新版 VS 把很多 C 运行时函数标记为不安全。解决:在项目属性里加_CRT_SECURE_NO_WARNINGS宏,或者用#pragma warning(disable:4996)包住 CEF 头文件。但注意,这只是屏蔽警告,不要真的去改 CEF 源码,否则升级版本时你会哭。6. 进阶:把 CEF 嵌入自己的 MFC 或 Qt 工程6.1 在 MFC 对话框里嵌入浏览器窗口MFC 工程里嵌入 CEF,核心是拿到对话框的HWND,然后传给CefWindowInfo::SetAsChild。代码片段:// 在对话框的 OnInitDialog 里 CefWindowInfo window_info; CRect rect; GetDlgItem(IDC_BROWSER_PLACEHOLDER)->GetWindowRect(&rect); ScreenToClient(&rect); window_info.SetAsChild(GetDlgItem(IDC_BROWSER_PLACEHOLDER)->GetSafeHwnd(), rect); CefBrowserSettings browser_settings; CefBrowserHost::CreateBrowser(window_info, handler, L"http://localhost:8080", browser_settings, nullptr);IDC_BROWSER_PLACEHOLDER是一个静态控件,用来占位。SetAsChild的第二个参数是矩形区域,CEF 会把浏览器窗口嵌到这个区域里。注意,MFC 的消息循环和 CEF 的消息循环要整合,否则浏览器窗口不刷新。我一般会在CWinApp::Run里调CefRunMessageLoop,或者用CefDoMessageLoopWork在OnIdle里手动泵消息。6.2 在 Qt 里嵌入 CEF 的注意事项Qt 的窗口句柄获取方式和 MFC 不同,需要用QWidget::winId()拿到WId,再转成HWND。另外,Qt 的事件循环和 CEF 的消息循环冲突更明显。常见做法是开一个单独的线程跑CefRunMessageLoop,或者用CefDoMessageLoopWork配合QTimer定时调用。我试过在 Qt 里用QTimer每 10ms 调一次CefDoMessageLoopWork,CPU 占用会上去,但兼容性最好。6.3 验证嵌入是否成功的三个检查点第一,浏览器窗口是否随父窗口缩放。如果父窗口拉伸时浏览器区域不跟着变,说明没有处理WM_SIZE消息,需要在OnSize里调CefBrowserHost::GetBrowser()->GetHost()->WasResized()。第二,输入焦点是否正常。点击浏览器区域后,键盘输入是否被浏览器接收。如果不行,检查父窗口是否拦截了WM_SETFOCUS。第三,关闭父窗口时,CEF 是否正常退出。如果进程残留,检查是否在OnDestroy里调了CefShutdown。这三个点过了,嵌入基本就稳了。6.4 一个我常用的调试技巧在CefSettings里设置settings.remote_debugging_port = 8088,然后浏览器里访问http://localhost:8088,就能用 DevTools 调试嵌入的页面。这个端口只在调试时开,发布时记得关掉。另外,settings.log_file = L"debug.log"可以把 CEF 内部日志写到文件里,排查初始化失败特别有用。从那以后我每次集成 CEF 到新工程,都强制走一遍“编译 wrapper → 拷资源 → 跑 cefsimple → 开远程调试 → 嵌到目标工程”这个流程,少一步都可能翻车。希望帮到你。本文还有配套的精品资源,点击获取