用CEF3+MFC打造自己的简易浏览器:从原理到实践

用CEF3+MFC打造自己的简易浏览器:从原理到实践-可达鸭小栈
libcef_dll_wrapper静态库 含32&64位
此内容为付费资源,请付费后查看
30积分
积分资源免费
付费资源可享->
免费更新
协助部署
在线答疑
CEF3版本145.0.7632.160
语言C++
付费资源
智谱
AI 正在加载摘要

前言

在Windows桌面应用开发中,经常需要在程序中嵌入网页浏览功能。虽然微软提供了WebBrowser控件(基于IE内核),但IE早已跟不上现代Web技术的发展。而Chromium Embedded Framework(CEF3)则为我们提供了一个完美的替代方案——它基于Chromium内核,支持现代HTML5/CSS3/JavaScript特性,与Chrome浏览器表现一致。

本文将详细介绍如何用CEF3配合MFC,开发一个简易但功能完整的浏览器应用。所有代码和配置都会详细说明,方便你快速上手。

软件效果图

df58d9d9-81db-4904-9c58-7320552e620d_compressed

一、原理概述

CEF3是什么?

CEF3是一个开源框架,它将Chromium浏览器引擎封装成易于嵌入的库。简单来说,它让我们可以在自己的桌面应用中,嵌入一个完整的Chrome浏览器内核。

架构特点

CEF3采用多进程架构:

  • 主进程(Browser进程):负责UI界面、管理浏览器实例

  • 子进程(Render进程):负责页面渲染、JavaScript执行

这种架构保证了浏览器的稳定性:即使某个标签页崩溃,也不会影响整个应用。

MFC集成思路

在MFC中集成CEF3的核心步骤:

  1. 在应用启动时初始化CEF环境

  2. 在对话框/视图中创建浏览器窗口

  3. 处理CEF的消息循环

  4. 应用退出时清理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需要我们手动编译。关于如何编译这个库,我在之前的文章中已经详细讲解过:

也可以从上方直接下载我编译好的,但注意版本 我是用的是145.0.7632.160版本 一定要下载这个版本才能使用

简单来说,需要用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.dllChrome错误处理库
icudtl.datICU国际化数据
locales/多语言资源文件夹(必须包含zh-CN.pak)
resources.pak资源包
*.dll其他依赖DLL

重要提示icudtl.dat文件和locales文件夹必须放在程序可执行文件同目录下。

注意事项

  • 沙箱模式:开发阶段务必设置no_sandbox = true,否则可能无法正常运行

  • 缓存路径:使用绝对路径,避免相对路径导致的问题

  • DPI感知:如果程序在高DPI显示器上显示异常,需要在清单文件中设置DPI感知

常见问题

Q1: 程序启动后闪退,或者只显示空白窗口?

检查

  1. 是否在InitInstance中正确处理了子进程返回逻辑?

  2. 所有CEF运行时DLL是否已复制到程序目录?

  3. icudtl.datlocales文件夹是否存在?

  4. 是否设置了no_sandbox = true

Q2: 编译时报链接错误?

检查

  1. libcef_dll_wrapper.lib是否已正确链接?

  2. 项目运行库设置是否与CEF一致(/MD 或 /MDd)?

  3. 是否包含了所有必要的头文件路径?

总结

通过以上步骤,我们就成功地在MFC应用中嵌入了CEF3浏览器内核。整个过程看似复杂,但核心只有三步:

  1. 初始化CEF(处理多进程,配置设置)

  2. 创建浏览器(指定父窗口和URL)

  3. 清理资源(应用退出时调用CefShutdown)

CEF3的强大之处在于它完全兼容Chrome浏览器,这意味着你的MFC应用可以无缝支持最新的Web技术。无论是嵌入网页、开发混合应用,还是作为自动化工具,CEF3都能满足需求。

后续我还会继续分享更多CEF3的高级用法,比如:

  • JS与C++双向通信

  • 自定义协议拦截

  • 实现完整的下载管理器

  • DevTools调试工具集成

如果你在集成过程中遇到任何问题,欢迎在评论区留言讨论!

------本页内容已结束,喜欢请分享------

感谢您的来访,获取更多精彩文章请收藏本站。

© 版权声明
THE END
看完了?看完了愣着啊点赞干什么
点赞8 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容