WebView2教程(基于C++)【一】环境初始化
创建一个VisualStudio C++项目,通过NuGet包管理器安装两个包:

注意,在项目属性页设置项目使用:C++ 20,子系统设置成窗口(相应的预处理器也要改变),DPI识别设置成每个监视器高DPI识别。
附加依赖项设置以下几项:
dwmapi.lib
shell32.lib
comctl32.lib
usp10.lib
kernel32.lib
user32.lib
新建一个main.cpp代码如下:
#include <Windows.h>
#include "App.h"int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance,_In_ LPTSTR lpCmdLine, _In_ int nCmdShow)
{auto result = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);if (result != S_OK) {return 0;}App::init();MSG msg;while (GetMessage(&msg, NULL, 0, 0)){TranslateMessage(&msg);DispatchMessage(&msg);}CoUninitialize();return 0;
}
这是入口方法,我们在入口方法里初始化了App类
下面是App类的头文件代码如下:
#pragma once
#include <Windows.h>
#include <fstream>
#include <filesystem>
#include <wrl.h>
#include <wil/com.h>
#include <WebView2.h>
#include <Shlobj.h>
#include <shellapi.h>class App
{
public:~App();static void init();static void dispose();static App* get();static ICoreWebView2Environment* getWebViewEnv();static std::wstring getAppPath();
private:App();void initConfig();void regScheme();bool checkRuntime();bool checkRegKey(const HKEY& key, const std::wstring& subKey);bool ensureAppFolder();HRESULT envCallBack(HRESULT result, ICoreWebView2Environment* env);
};
先看来看看这个类的一部分代码(不是全部):
#include "App.h"
#include <rapidjson/document.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <filesystem>
#include <fstream>
#include "Util.h"
#include <string>
#include <vector>
#include <WebView2EnvironmentOptions.h>
#include "Win.h"using namespace Microsoft::WRL;namespace {static App* app;static rapidjson::Document d;static std::vector<Win*> wins;static std::filesystem::path appPath;static ICoreWebView2Environment* webViewEnv;
}App::App()
{initConfig();if (!checkRuntime()) {return;}if (!ensureAppFolder()) {return;}regScheme();auto envCBInstance = Callback<ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler>(this, &App::envCallBack);HRESULT result = CreateCoreWebView2EnvironmentWithOptions(nullptr, appPath.c_str(), nullptr/*options.Get()*/, envCBInstance.Get());if (FAILED(result)) {return;}
}
App::~App()
{for (size_t i = 0; i < wins.size(); i++){delete wins[i];}
}
void App::init() {if (app) {return;}app = new App();
}
App* App::get() {return app;
}
void App::dispose()
{delete app;
}
App::init();执行之后,就创建了一个App对象,这个对象被保存在静态变量app中,在App的构造函数中,先初始化了应用程序的配置信息。代码如下:
void App::initConfig()
{std::ifstream file("config.json");std::string content((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());d.Parse(content.c_str());
}
这段代码读取应用程序(exe文件)所在目录下的config.json文件,并把这个json文件存储在静态变量:static rapidjson::Document d;中,以后我们会从这个d中获取配置信息。
这个config.json文件的代码如下:
{"appName": "WebView2JS","windows": [{"id": "FirstWindow","w": 1200,"h": 800,"miniWidth": 1200,"miniHeight": 800,"resizable": true,"title": "WebView2JS窗口","frame": false,"shadow": true,"position": {"x": 100,"y": 100,"centerOfScreen": true},"webviews": [{"id": "FirstWebView","url": "https://wv2js/index.html","disableWindowOpen": null,"area": {"left": 0,"right": 0,"top": 0,"bottom": 0,"width": -1,"height": -1}}]}]
}
这里配置了窗口和webview的一些基本信息。
需要注意的是,我们读取JSON用到了RapidJSON,至于怎么用这个库,我们这里就不多做介绍了。甚至你可以完全不用json配置文件。
initConfig之后,就会执行checkRuntime方法,代码如下:
bool App::checkRuntime()
{std::wstring regSubKey = L"\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}";bool hasRuntime = checkRegKey(HKEY_LOCAL_MACHINE, L"SOFTWARE\WOW6432Node" + regSubKey);if (hasRuntime) return true;hasRuntime = checkRegKey(HKEY_CURRENT_USER, L"Software" + regSubKey);if (!hasRuntime) {auto result = MessageBox(nullptr, L"error", L"error", MB_OKCANCEL | MB_ICONINFORMATION | MB_DEFBUTTON1);if (result == IDOK) {ShellExecute(0, 0, L"https://go.microsoft.com/fwlink/p/?LinkId=2124703", 0, 0, SW_SHOW);}return false;}return true;
}
这个方法会判断当前的用户环境,是否安装了WebView2的运行时,如果没有,则打开一个网页,让用户去下载WebView2的运行时。
接下去执行ensureAppFolder方法,代码如下:
bool App::ensureAppFolder() { PWSTR pathTmp;auto ret = SHGetKnownFolderPath(FOLDERID_RoamingAppData, 0, nullptr, &pathTmp);if (ret != S_OK) {CoTaskMemFree(pathTmp);auto result = MessageBox(nullptr, L"error", L"error", MB_OK | MB_ICONINFORMATION | MB_DEFBUTTON1);exit(1);return false;}appPath = pathTmp;CoTaskMemFree(pathTmp);appPath /= convertToWideChar(d["appName"].GetString());if (!std::filesystem::exists(appPath)) {auto flag = std::filesystem::create_directory(appPath);if (!flag) {MessageBox(nullptr, L"error", L"error", MB_OK | MB_ICONINFORMATION | MB_DEFBUTTON1);exit(1);return false;}}return true;
}
这个方法会初始化一个应用程序缓存目录,:C:Users[user name]AppDataRoamingWebView2JS,其中WebView2JS是从配置文件中读取的。
目录中的文件如下图所示,这与Electron应用差不多

这个路径被保存到appPath静态变量中了。
接下去会执行regScheme方法:
void App::regScheme()
{auto options = Microsoft::WRL::Make<CoreWebView2EnvironmentOptions>();options->put_AdditionalBrowserArguments(L"--allow-file-access-from-files");Microsoft::WRL::ComPtr<ICoreWebView2EnvironmentOptions4> options4;HRESULT oeResult = options.As(&options4);const WCHAR* allowed_origins[1] = { L"*" };auto defaultRegistration = Microsoft::WRL::Make<CoreWebView2CustomSchemeRegistration>(L"wv2js");defaultRegistration->put_HasAuthorityComponent(TRUE);defaultRegistration->put_TreatAsSecure(TRUE);defaultRegistration->SetAllowedOrigins(1, allowed_origins);ICoreWebView2CustomSchemeRegistration* registrations[1] = { defaultRegistration.Get() };options4->SetCustomSchemeRegistrations(1, static_cast<ICoreWebView2CustomSchemeRegistration**>(registrations));
}
这个方法会为WebView注册一个自定义协议,这样我们就可以用:https://wv2js这个域名加载我们的自定义页面了。
App类构造函数中最后几行代码以异步的方式创建WebView2的环境变量对象,异步回调方法为:envCallBack,这个方法的代码如下:
HRESULT App::envCallBack(HRESULT result, ICoreWebView2Environment* env)
{webViewEnv = env;rapidjson::Value& winConfigs = d["windows"].GetArray();for (size_t i = 0; i < winConfigs.Size(); i++){wins.push_back(new Win(winConfigs[i]));}return S_OK;
}
在这个方法中,webview2的环境对象被保存到静态变量webViewEnv中了,接着创建了窗口对象,并保存到一个容器wins中(静态变量)。
如你所见,依据我们的配置文件,我们是可以在应用程序启动时,直接创建多个窗口的。
App类还有几个简单的方法,如下所示:
ICoreWebView2Environment* App::getWebViewEnv()
{return webViewEnv;
}std::wstring App::getAppPath()
{return appPath.wstring();
}
这两个方法用于给其他类提供全局信息。
相关文章:
WebView2教程(基于C++)【一】环境初始化
创建一个VisualStudio C项目,通过NuGet包管理器安装两个包: 注意,在项目属性页设置项目使用:C 20,子系统设置成窗口(相应的预处理器也要改变),DPI识别设置成每个监视器高DPI识别。 …...
go语言中context的用法
0 概述 Context 是 Go 语言中非常重要的一个概念,它主要用于跨多个函数或 goroutine 传递 取消信号、超时控制、截止时间 和 请求范围数据。在并发编程中,Context 提供了更好的控制和管理,尤其是当你需要在多个 goroutine 之间传递状态或进行…...
概括网络给社会生活带来的种种影响
题目 【2002年国考申论】给定资料反映了网络给社会生活带来的种种影响,用不超过200字对这些影响进行概括。 要求:全面,有条理,有层次。(20分) 审题 特定事实:网络给社会生活带来的种种影响基本题型:单一…...
OpenCV相机标定与3D重建(16)将点从齐次坐标转换为非齐次坐标函数convertPointsFromHomogeneous()的使用
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 cv::convertPointsFromHomogeneous 是 OpenCV 库中的一个函数,用于将点从齐次坐标(homogeneous coordinates)…...
Jmeter如何对UDP协议进行测试?
Jmeter如何对UDP协议进行测试? 1 jmeter-plugins安装2 UDP-Protocol Support安装3 UDP协议测试 1 jmeter-plugins安装 jmeter-plugins是Jmeter的插件管理器;可以组织和管理Jmeter的所有插件;直接进入到如下页面,选择如图的选项进…...
Unix 传奇 | 谁写了 Linux | Unix birthmark
注:本文为 “左耳听风”陈皓的 unix 相关文章合辑。 皓侠已走远,文章有点“年头”,但值得一阅。 文中部分超链已沉寂。 Unix 传奇 (上篇) 2010 年 04 月 09 日 陈皓 了解过去,我们才能知其然,更知所以然。总结过去…...
【网络】传输层协议UDP/TCP网络层IP数据链路层MACNAT详解
主页:醋溜马桶圈-CSDN博客 专栏:计算机网络原理_醋溜马桶圈的博客-CSDN博客 gitee:mnxcc (mnxcc) - Gitee.com 目录 1.传输层协议 UDP 1.1 传输层 1.2 端口号 1.3 UDP 协议 1.3.1 UDP 协议端格式 1.3.2 UDP 的特点 1.3.3 面向数据报 1…...
RTMP推流平台EasyDSS在无人机推流直播安防监控中的创新应用
无人机与低空经济的关系密切,并且正在快速发展。2024年中国低空经济行业市场规模达到5800亿元,其中低空制造产业占整个低空经济产业的88%。预计未来五年复合增速将达到16.03%。 随着科技的飞速发展,公共安防关乎每一个市民的生命财产安全。在…...
ORACLE逗号分隔的字符串字段,关联表查询
使用场景如下: oracle12 以前的写法: selectt.pro_ids,wm_concat(t1.name) pro_names from info t,product t1 where instr(,||t.pro_ids|| ,,,|| t1.id|| ,) > 0 group by pro_ids oracle12 以后的写法: selectt.pro_ids,listagg(DIS…...
1.5 多媒体系统简介
目录 多媒体系统声音图形与图像动画和视频 多媒体系统 多媒体可分为感觉媒体、表示媒体、表现媒体、交换媒体。 感觉媒体:直接使人产生感觉的媒体,比如声音、图像、视频。表示媒体:计算机中记录感觉的数据格式。表现媒体:记录感觉…...
数据分析学习Day1-使用matplotlib生成2小时每分钟的气温可视化分析图
注意:需要提前下载matplotlib包 pip install matplotlib -i https://pypi.tuna.tsinghua.edu.cn/simple import matplotlib.pyplot as plt import random from matplotlib import font_manager # 数据准备 x list(range(121)) # 使用 list() 转换为列表 y [rando…...
ansible部署nginx:1个简单的playbook脚本
文章目录 hosts--ventoryroles执行命令 使用ansible向3台centos7服务器上安装nginx hosts–ventory [rootstand playhook1]# cat /root/HOSTS # /root/HOSTS [webservers] 192.168.196.111 ansible_ssh_passpassword 192.168.196.112 ansible_ssh_passpassword 192.168.196.1…...
三、汇总统计
1.SUM、COUNT、AVERAGE 注意:count函数是计算区域中包含数字的单元格的个数,以上案例中两个空白单元格和一个中文列标题都是没有计算在内的。 平均函数AVERAGE也是按照17进行求平均值的。所以在使用平均值的函数时候,可以根据实际情况看是…...
opencv实现给图像加上logo图像
要用Python和OpenCV给图片加上logo,可以按照以下步骤实现: 读取logo和image图片。 调整logo的大小以适应image。 将logo放置在image的指定位置。 将logo和image合并。 以下是实现代码: import cv2# 读取logo和image图片 logo cv2.imre…...
亚马逊云科技2024 re:Invent大会亮点:Nova大模型与AI基础设施全面升级
引言 作为云计算领域的年度盛会,亚马逊云科技(AWS)的re:Invent大会一直是业界瞩目的焦点。2024年的大会不负众望,推出了一系列重磅产品和服务,尤其是在人工智能和大模型方面的创新令人印象深刻。本文将为您深入解析此次大会的主要亮点,探讨AWS在AI时代的最新布局及其对行业的潜…...
总结与提升
今天学习了ai,对今天学习的内容进行总结。 本文参考chat gpt-4的训练文献。 模型架构基础 Transformer 架构:ChatGPT 采用了 Transformer 架构,这是一种基于自注意力机制的深度学习模型架构。它能够并行计算文本中的长期依赖关系ÿ…...
入门pytorch-Transformer
前言 虽然Transformer是2017年由Google推出,如果按照读论文只读近两年的思路看,那它无疑是过时的,但可惜的是,目前很多论文的核心依然是Transformer,或者由其进行改进的,故本文使用pytorch来搭建一下Trans…...
泛型编程--
auto自动推导数据类型 函数模板 定义和调用 函数模板具体化 函数模板通用版本之外的一个特殊版本 函数模板 具体化函数 ,它们的声明和定义都可以分开写。 声明 定义 函数模板写变量 模板参数缺省 类成员函数作为函数模板 类构造函数是函数模板 函数模板重载 函数模…...
【大语言模型】LangChain 核心模块介绍(Agents)
【大语言模型】LangChain 核心模块介绍(Agents) 一、简介二、Agents 的核心概念三、实战案例3.1、需求说明3.2、实现思路3.3、完整源码 一、简介 我们都知道四肢的绝大部分动作都是由大脑决定的,大脑通过中枢神经下发自己的操作指令…...
19C-RAC 环境mgmtca.trc.1过大
客户监控告警/u01使用率超过80%,通过一层层目录查看,发现是mgmtca.trc.1过大导致的告警 [rootgsdb1 ~]# du -sh /u01/app/grid/cfgtoollogs/mgmtca/mgmtca.trc.1 103G /u01/app/grid/cfgtoollogs/mgmtca/mgmtca.trc.1 查看MOS文档:Huge …...
HTML 语义化
目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案: 语义化标签: <header>:页头<nav>:导航<main>:主要内容<article>&#x…...
应用升级/灾备测试时使用guarantee 闪回点迅速回退
1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间, 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点,不需要开启数据库闪回。…...
云计算——弹性云计算器(ECS)
弹性云服务器:ECS 概述 云计算重构了ICT系统,云计算平台厂商推出使得厂家能够主要关注应用管理而非平台管理的云平台,包含如下主要概念。 ECS(Elastic Cloud Server):即弹性云服务器,是云计算…...
(十)学生端搭建
本次旨在将之前的已完成的部分功能进行拼装到学生端,同时完善学生端的构建。本次工作主要包括: 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...
C++:std::is_convertible
C++标志库中提供is_convertible,可以测试一种类型是否可以转换为另一只类型: template <class From, class To> struct is_convertible; 使用举例: #include <iostream> #include <string>using namespace std;struct A { }; struct B : A { };int main…...
React Native 开发环境搭建(全平台详解)
React Native 开发环境搭建(全平台详解) 在开始使用 React Native 开发移动应用之前,正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南,涵盖 macOS 和 Windows 平台的配置步骤,如何在 Android 和 iOS…...
k8s从入门到放弃之Ingress七层负载
k8s从入门到放弃之Ingress七层负载 在Kubernetes(简称K8s)中,Ingress是一个API对象,它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress,你可…...
Linux-07 ubuntu 的 chrome 启动不了
文章目录 问题原因解决步骤一、卸载旧版chrome二、重新安装chorme三、启动不了,报错如下四、启动不了,解决如下 总结 问题原因 在应用中可以看到chrome,但是打不开(说明:原来的ubuntu系统出问题了,这个是备用的硬盘&a…...
【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统
目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...
关键领域软件测试的突围之路:如何破解安全与效率的平衡难题
在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件,这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下,实现高效测试与快速迭代?这一命题正考验着…...
