前言
在Windows桌面应用开发中,经常需要在程序中嵌入网页浏览功能。虽然微软提供了WebBrowser控件(基于IE内核),但IE早已跟不上现代Web技术的发展。而Chromium Embedded Framework(CEF3)则为我们提供了一个完美的替代方案——它基于Chromium内核,支持现代HTML5/CSS3/JavaScript特性,与Chrome浏览器表现一致。
本文将详细介绍如何用CEF3配合MFC,开发一个简易但功能完整的浏览器应用。所有代码和配置都会详细说明,方便你快速上手。
软件效果图

一、原理概述
CEF3是什么?
CEF3是一个开源框架,它将Chromium浏览器引擎封装成易于嵌入的库。简单来说,它让我们可以在自己的桌面应用中,嵌入一个完整的Chrome浏览器内核。
架构特点
CEF3采用多进程架构:
主进程(Browser进程):负责UI界面、管理浏览器实例
子进程(Render进程):负责页面渲染、JavaScript执行
这种架构保证了浏览器的稳定性:即使某个标签页崩溃,也不会影响整个应用。
MFC集成思路
在MFC中集成CEF3的核心步骤:
在应用启动时初始化CEF环境
在对话框/视图中创建浏览器窗口
处理CEF的消息循环
应用退出时清理CEF资源
二、环境准备
1. 下载CEF3
从CEF官方下载页面获取:https://cef-builds.spotifycdn.com/index.html
建议选择:
分支:
stable(稳定版)平台:
Windows 64-bit(根据你的项目配置选择)构建类型:
Standard Distribution
2. 编译libcef_dll_wrapper.lib
CEF3自带的libcef_dll_wrapper.lib需要我们手动编译。关于如何编译这个库,我在之前的文章中已经详细讲解过:
简单来说,需要用CMake生成VS项目,然后编译生成静态库文件。
三、项目配置
1. 包含目录和库目录设置
在Visual Studio中,为你的MFC项目添加:
包含目录(项目属性 → C/C++ → 常规 → 附加包含目录):
$(ProjectDir)cef\include
库目录(项目属性 → 链接器 → 常规 → 附加库目录):
$(ProjectDir)cef\Debug # 或 Release,取决于你的配置
附加依赖项(项目属性 → 链接器 → 输入 → 附加依赖项):
libcef_dll_wrapper.lib libcef.lib
2. 运行时库设置
由于CEF3是动态链接到运行时库的,需要将项目属性中的”运行库”设置为多线程(/MT)或多线程DLL(/MD),与CEF的编译方式保持一致。
四、代码实现
在InitInstance中初始化CEF
// 在应用的 InitInstance 函数中
BOOL CMyA:InitInstance() {
// MFC 的初始化代码...
// 创建 ShellManager 等(MFC 自动生成的代码)
// ...
// ========== CEF 初始化开始 ==========
// 1. 创建 CefMainArgs
CefMainArgs mainArgs(AfxGetInstanceHandle());
// 2. 创建客户端处理器
CefRefPtr<CSimpleApp> app(new CSimpleApp());
// 3. 执行 CEF 子进程处理
// 如果是子进程(render进程等),CefExecuteProcess 会处理并返回 >=0 的值
// 此时程序应该退出,不再继续执行 MFC 的主流程
int exitCode = CefExecuteProcess(mainArgs, app.get(), nullptr);
if (exitCode >= 0) {
// 这是子进程,退出 MFC 应用程序
if (pShellManager != nullptr) {
delete pShellManager;
}
return FALSE; // 子进程直接退出
}
// 4. 配置 CEF 设置(仅在主进程中执行)
CefSettings settings;
settings.multi_threaded_message_loop = true; // 让 CEF 自己管理消息循环
settings.no_sandbox = true; // 禁用沙箱(开发时必须)
settings.windowless_rendering_enabled = false; // 使用窗口渲染
// 设置缓存路径(强烈建议设置,能显著提升性能)
CefString(&settings.cache_path) = L"D:\\C++\\MFC_WebBrowser\\x64\\Release\\cache";
// 设置日志文件路径(方便调试)
CefString(&settings.log_file) = L"D:\\C++\\MFC_WebBrowser\\x64\\Release\\cef.log";
settings.log_severity = LOGSEVERITY_WARNING; // 只记录警告和错误
// 设置语言
CefString(&settings.locale) = L"zh-CN";
// 5. 初始化 CEF
if (!CefInitialize(mainArgs, settings, app.get(), nullptr)) {
AfxMessageBox("CEF 初始化失败!请检查相关文件是否完整。");
if (pShellManager != nullptr) {
delete pShellManager;
}
return FALSE;
}
// ========== CEF 初始化结束 ==========
// 继续 MFC 的正常流程,显示主对话框
CMainDialog dlg;
m_pMainWnd = &dlg;
dlg.DoModal();
// 注意:当对话框关闭后,需要在 ExitInstance 中清理 CEF
return FALSE; // 因为使用了 DoModal,这里返回 FALSE
}在对话框中创建浏览器
在主对话框的OnInitDialog中创建浏览器窗口:
// MainDialog.cpp
BOOL CMainDialog::OnInitDialog() {
CDialogEx::OnInitDialog();
// ... 其他初始化代码(菜单、工具栏等)
// ========== 创建浏览器 ==========
// 1. 获取对话框的客户区矩形(或指定一个子窗口作为浏览器容器)
CRect rect;
GetClientRect(&rect);
// 如果地址栏、工具栏占用了空间,需要调整矩形
// rect.top += 40; // 假设地址栏高度40像素
// 2. 配置窗口信息
CefWindowInfo windowInfo;
windowInfo.SetAsChild(this->GetSafeHwnd(), rect);
// 3. 配置浏览器设置
CefBrowserSettings browserSettings;
browserSettings.file_access_from_file_urls = STATE_ENABLED; // 允许文件访问
browserSettings.universal_access_from_file_urls = STATE_ENABLED; // 允许跨域
browserSettings.web_security = STATE_DISABLED; // 开发时可禁用安全策略
browserSettings.javascript = STATE_ENABLED; // 启用JS
// 4. 创建浏览器
CefBrowserHost::CreateBrowser(
windowInfo, // 窗口信息
nullptr, // 客户端处理器(也可以用 SimpleApp 实例)
L"https://www.baidu.com", // 起始URL
browserSettings, // 浏览器设置
nullptr, // 附加信息
nullptr // 请求上下文
);
return TRUE;
}至此你已经得到了一个可以运行的浏览器 后面就是根据文档来实现更多功能 例如跟随窗口改变浏览器大小等等功能
void CMainDialog::OnSize(UINT nType, int cx, int cy) {
CDialogEx::OnSize(nType, cx, cy);
if (m_browserHost) {
// 获取浏览器窗口句柄
HWND hBrowserWnd = m_browserHost->GetWindowHandle();
if (hBrowserWnd && IsWindow(hBrowserWnd)) {
// 调整浏览器窗口大小
CRect rect;
GetClientRect(&rect);
// 减去工具栏/地址栏占用的高度
// rect.top += TOOLBAR_HEIGHT;
::SetWindowPos(hBrowserWnd, NULL, rect.left, rect.top,
rect.Width(), rect.Height(), SWP_NOZORDER);
}
}
}五、部署运行
1. 必需的运行时文件
编译完成后,需要将CEF3的运行时文件复制到程序目录:
| 文件/目录 | 说明 |
|---|---|
libcef.dll | 核心库文件(最大,约100MB) |
chrome_elf.dll | Chrome错误处理库 |
icudtl.dat | ICU国际化数据 |
locales/ | 多语言资源文件夹(必须包含zh-CN.pak) |
resources.pak | 资源包 |
*.dll | 其他依赖DLL |
重要提示:icudtl.dat文件和locales文件夹必须放在程序可执行文件同目录下。
注意事项
沙箱模式:开发阶段务必设置
no_sandbox = true,否则可能无法正常运行缓存路径:使用绝对路径,避免相对路径导致的问题
DPI感知:如果程序在高DPI显示器上显示异常,需要在清单文件中设置DPI感知
常见问题
Q1: 程序启动后闪退,或者只显示空白窗口?
检查:
是否在
InitInstance中正确处理了子进程返回逻辑?所有CEF运行时DLL是否已复制到程序目录?
icudtl.dat和locales文件夹是否存在?是否设置了
no_sandbox = true?
Q2: 编译时报链接错误?
检查:
libcef_dll_wrapper.lib是否已正确链接?项目运行库设置是否与CEF一致(/MD 或 /MDd)?
是否包含了所有必要的头文件路径?
总结
通过以上步骤,我们就成功地在MFC应用中嵌入了CEF3浏览器内核。整个过程看似复杂,但核心只有三步:
初始化CEF(处理多进程,配置设置)
创建浏览器(指定父窗口和URL)
清理资源(应用退出时调用CefShutdown)
CEF3的强大之处在于它完全兼容Chrome浏览器,这意味着你的MFC应用可以无缝支持最新的Web技术。无论是嵌入网页、开发混合应用,还是作为自动化工具,CEF3都能满足需求。
后续我还会继续分享更多CEF3的高级用法,比如:
JS与C++双向通信
自定义协议拦截
实现完整的下载管理器
DevTools调试工具集成
如果你在集成过程中遇到任何问题,欢迎在评论区留言讨论!
感谢您的来访,获取更多精彩文章请收藏本站。
















暂无评论内容