在 MFC 应用中集成 WebView2

WebView2 是 Microsoft 提供的一个嵌入式浏览器控件,基于 Edge (Chromium) 内核,支持在桌面应用中加载 HTML、CSS 和 JavaScript,适用于现代化的桌面应用开发。而 Windows Implementation Library (WIL) 是一个帮助开发者简化 Windows API 使用的库,在 WebView2 开发中常用于管理 COM 资源和简化错误处理。


环境准备

安装 WebView2 运行时

WebView2 依赖于 Microsoft Edge (Chromium) 内核,因此需要确保 WebView2 运行时已安装。可以通过以下方式获取:

  • 下载安装 WebView2 Runtime
  • 在项目中使用固定版本运行时(Evergreen Standalone Installer)。
  • 如果希望在程序中检查 WebView2 运行时是否可用,可以使用 WebView2Loader.dll 提供的 API。

安装 WebView2 和 WIL

通过 NuGet 安装 WebView2 SDK

在 Visual Studio 中,打开"NuGet 包管理器"并运行以下命令:

powershell 复制代码
Install-Package Microsoft.Web.WebView2
通过 NuGet 安装 WIL(Windows Implementation Library)
powershell 复制代码
Install-Package Microsoft.Windows.ImplementationLibrary

这两个库分别用于:

  • Microsoft.Web.WebView2 提供 WebView2 控件的接口和 API。
  • Microsoft.Windows.ImplementationLibrary (WIL) 让 Windows API 的使用更简单,如 COM 资源管理、错误处理等。
packages.config 说明

在 NuGet 安装 WebView2 和 WIL 后,packages.config 文件会自动更新,记录所有依赖包及其版本。示例如下:

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="Microsoft.Web.WebView2" version="1.0.2098.22" targetFramework="native" />
  <package id="Microsoft.Windows.ImplementationLibrary" version="1.0.210902.1" targetFramework="native" />
</packages>

packages.config 的作用:

  • 记录 NuGet 依赖项,方便团队协作时安装相同版本的依赖包。
  • 便于在新环境中自动还原依赖项,确保构建时不会缺少库。

可以使用 nuget restore 命令自动安装 packages.config 里定义的所有包:

powershell 复制代码
nuget restore packages.config -PackagesDirectory packages
WebView2 依赖的 DLL 文件

WebView2 运行时通常包含多个 DLL 文件,最重要的是 WebView2Loader.dll。在使用 WebView2 时,需要确保这些动态库文件可用:

WebView2Loader.dll 位置

Microsoft.Web.WebView2 NuGet 包安装后,你可以在以下路径找到 WebView2Loader.dll

runtimes\win-x64\native\WebView2Loader.dll

这个文件必须包含在你的应用程序的可执行目录中,否则 WebView2 可能无法正常运行。你可以手动复制 DLL,或者在 CMake 或 MSBuild 配置中自动包含该文件。

如何确保 WebView2Loader.dll 在运行时可用?

  • WebView2Loader.dll 复制到应用程序的输出目录 (Debug/Release 目录)。
  • 在 C++ 代码中检查 WebView2Loader.dll 是否可用,如果缺失则提示用户安装 WebView2 运行时。

1. WebView2 的关键特点

  • 基于 Chromium:依赖 Microsoft Edge (Chromium) 引擎,支持最新的 Web 标准。
  • 双向通信:原生代码和 JavaScript 可以互相调用。
  • 独立版本:可以嵌入固定的 WebView2 运行时,避免依赖用户系统中的 Edge。
  • 多平台支持:适用于 Win32、WPF、WinForms 和 MFC 等不同框架。

2. WebView2 的使用场景

混合应用开发

  • 桌面程序中嵌入复杂的 Web 界面。
  • 提供与服务器通信的实时动态功能。

浏览器功能

  • 显示网页内容,比如帮助文档或在线资源。
  • 嵌入第三方服务(如支付网关或地图服务)。

调试工具

  • 在桌面工具中集成可定制的网页调试功能。

跨平台支持

  • 使用统一的 HTML/JavaScript/CSS 逻辑,实现跨平台开发。

3. WebView2 的主要组成部分

  • ICoreWebView2:核心接口,用于管理 WebView2 控件。
  • ICoreWebView2Controller:用于控制 WebView2 的外观(例如大小和位置)。
  • WebView2 环境:托管 WebView2 实例,并加载 Chromium 运行时。

4. 头文件与全局变量

在 MFC 项目中,需要包含以下头文件:

cpp 复制代码
#include <wrl.h>
#include <wil/com.h>
#include "WebView2.h"

定义全局变量(用于管理 WebView2 控件):

cpp 复制代码
using namespace Microsoft::WRL;

// 指向 WebView2 控制器
static wil::com_ptr<ICoreWebView2Controller> webViewController;
// 指向 WebView2 窗口
static wil::com_ptr<ICoreWebView2> webView;

5. 初始化 WebView2

初始化 COM 和 WebView2

OnInitDialog 方法中初始化 COM 并创建 WebView2:

cpp 复制代码
BOOL CMyDialog::OnInitDialog() {
    CDialogEx::OnInitDialog();

	// 初始化 COM
    CoInitialize(NULL);
    				
	// 传入窗口句柄
    InitWebView2(this->GetSafeHwnd());

    return TRUE;
}

创建 WebView2 控件

创建 InitWebView2 方法,在 MFC 窗口中加载 WebView2。

cpp 复制代码
void CMyDialog::InitWebView2(HWND hwnd) {
    CreateCoreWebView2EnvironmentWithOptions(
        nullptr, nullptr, nullptr,
        Microsoft::WRL::Callback<ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler>(
            [hwnd](HRESULT result, ICoreWebView2Environment* env) -> HRESULT {
                if (env) {
                    env->CreateCoreWebView2Controller(hwnd,
                        Microsoft::WRL::Callback<ICoreWebView2CreateCoreWebView2ControllerCompletedHandler>(
                            [hwnd](HRESULT result, ICoreWebView2Controller* controller) -> HRESULT {
                                if (controller) {
                                    webViewController = controller;
                                    webViewController->get_CoreWebView2(&webView);

                                    // 设置 WebView2 的大小
									RECT bounds;
									GetClientRect(&bounds);
                                    webViewController->put_Bounds(bounds);

                                    // 加载网页
                                    webView->Navigate(L"https://www.baidu.com");
                                }
                                return S_OK;
                            }).Get());
                }
                return S_OK;
            }).Get());
}

6. 释放 WebView2 和 COM 组件

OnDestroy 方法中调用 CoUninitialize() 释放 COM 组件,以确保 WebView2 资源正确释放。

cpp 复制代码
void CMyDialog::OnDestroy() {
    CDialogEx::OnDestroy();

    webViewController = nullptr;
    webView = nullptr;

    CoUninitialize();  // 释放 COM
}

7. 处理窗口大小变化 (OnSize)

在 MFC 窗口调整大小时,WebView2 需要随之调整大小,否则窗口内容可能会显示不完整。你可以在 OnSize 事件中更新 WebView2 控件的大小:

cpp 复制代码
void CMyDialog::OnSize(UINT nType, int cx, int cy)
{
    CDialogEx::OnSize(nType, cx, cy);

    if (webViewController != nullptr) {
        RECT bounds;
        GetClientRect(&bounds);
        webViewController->put_Bounds(bounds);
    }
}

关键点解析

  • OnSize 是 MFC 窗口大小调整时的回调函数。
  • GetClientRect 获取窗口的客户区大小,并调整 WebView2 的 Bounds 以匹配窗口大小。
  • 只有在 webViewController 已初始化的情况下,才进行调整,避免空指针错误。

8. 与 JavaScript 通信

C++ 调用 JavaScript

cpp 复制代码
webView->ExecuteScript(L"alert('Hello from C++!');", nullptr);

JavaScript 调用 C++

在 C++ 中注册事件处理程序

cpp 复制代码
webView->add_WebMessageReceived(
    Callback<ICoreWebView2WebMessageReceivedEventHandler>(
        [](ICoreWebView2* sender, ICoreWebView2WebMessageReceivedEventArgs* args) -> HRESULT {
            wil::unique_cotaskmem_string message;
            args->get_WebMessageAsString(&message);
            MessageBox(nullptr, message.get(), L"Message from JavaScript", MB_OK);
            return S_OK;
        }).Get(), nullptr);

在 JavaScript 中发送消息

javascript 复制代码
window.chrome.webview.postMessage("Hello from JavaScript!");

9. 设置 WebView 的外观和行为

调整大小

cpp 复制代码
RECT bounds;
GetClientRect(&bounds);
webViewController->put_Bounds(bounds);

禁用右键菜单和缩放

cpp 复制代码
webView->put_Settings(
    Callback<ICoreWebView2Settings>(
        [](ICoreWebView2Settings* settings) -> HRESULT {
            settings->put_IsZoomControlEnabled(FALSE);
            settings->put_AreDefaultContextMenusEnabled(FALSE);
            return S_OK;
        }).Get());

10. 加载本地内容

加载本地 HTML 文件

cpp 复制代码
webView->Navigate(L"file:///C:/path/to/your/file.html");

加载嵌入 HTML

cpp 复制代码
webView->NavigateToString(L"<html><body><h1>Hello, WebView2!</h1></body></html>");

11. 高级功能

注入 JavaScript

cpp 复制代码
webView->AddScriptToExecuteOnDocumentCreated(
    L"console.log('Injected Script');", nullptr);

拦截网络请求

可以通过 ICoreWebView2AddWebResourceRequestedFilter 方法拦截并处理网络请求。


总结

在本指南中,我们详细介绍了如何在 MFC 应用中集成 WebView2,并结合 WIL 进行高效开发。

关键步骤总结:

  1. 安装 WebView2 运行时 - 确保 WebView2 依赖的运行时已安装,并了解 WebView2Loader.dll 的路径。
  2. 安装 WebView2 和 WIL - 通过 NuGet 安装 Microsoft.Web.WebView2Microsoft.Windows.ImplementationLibrary,并确保 packages.config 记录了所有依赖项。
  3. 初始化 WebView2 - 在 OnInitDialog 方法中调用 CoInitialize(NULL) 并创建 WebView2 控件。
  4. 管理窗口大小变化 - 在 OnSize 事件中调整 WebView2 控件的 Bounds,确保窗口调整时 WebView2 能正确更新大小。
  5. 清理 WebView2 资源 - 在 OnDestroy 方法中调用 CoUninitialize() 释放资源,避免内存泄漏。
  6. 加载本地或远程网页 - 使用 Navigate 加载 URL,或者 NavigateToString 加载 HTML 字符串。
  7. 与 JavaScript 通信 - 通过 ExecuteScript 在 WebView2 中执行 JavaScript,并使用 add_WebMessageReceived 监听来自 JavaScript 的消息。
  8. 确保必要的 DLL 存在 - 复制 WebView2Loader.dll 到应用的 Debug/Release 目录,确保 WebView2 能正常运行。

通过以上步骤,可以成功在 MFC 桌面应用中集成 WebView2,并利用 WIL 进行高效的 Windows API 交互。如果在实际开发过程中遇到问题,可以参考 WebView2 官方文档或 NuGet 相关文档获取更多帮助。

相关推荐
钟离墨笺2 小时前
【c++】四种类型转换形式
开发语言·c++
汤姆和杰瑞在瑞士吃糯米粑粑3 小时前
【C++学习篇】C++11
开发语言·c++
_extraordinary_3 小时前
C++智能指针的使用
c++·智能指针
zjkzjk77113 小时前
C++ 左值引用 & 右值引用 && std::move()左值改右值 移动构造函数()
开发语言·c++
knowledgebao3 小时前
OHOS(HarmonyOS) 编译 C/C++ 库
c语言·c++·harmonyos
HL_LOVE_C3 小时前
全面理解-c++11中的智能指针
开发语言·c++
KAI77384 小时前
2月10日QT
c++
清泓y6 小时前
UE5--浅析委托原理(Delegate)
c++·ue5·ue4
RangoLei_Lzs7 小时前
C++性能优化—AI润色版
开发语言·c++·性能优化