当前位置: 首页 > news >正文

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项目&#xff0c;通过NuGet包管理器安装两个包&#xff1a; 注意&#xff0c;在项目属性页设置项目使用&#xff1a;C 20&#xff0c;子系统设置成窗口&#xff08;相应的预处理器也要改变&#xff09;&#xff0c;DPI识别设置成每个监视器高DPI识别。 …...

go语言中context的用法

0 概述 Context 是 Go 语言中非常重要的一个概念&#xff0c;它主要用于跨多个函数或 goroutine 传递 取消信号、超时控制、截止时间 和 请求范围数据。在并发编程中&#xff0c;Context 提供了更好的控制和管理&#xff0c;尤其是当你需要在多个 goroutine 之间传递状态或进行…...

概括网络给社会生活带来的种种影响

题目 【2002年国考申论】给定资料反映了网络给社会生活带来的种种影响&#xff0c;用不超过200字对这些影响进行概括。 要求&#xff1a;全面&#xff0c;有条理&#xff0c;有层次。(20分) 审题 特定事实&#xff1a;网络给社会生活带来的种种影响基本题型&#xff1a;单一…...

OpenCV相机标定与3D重建(16)将点从齐次坐标转换为非齐次坐标函数convertPointsFromHomogeneous()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 cv::convertPointsFromHomogeneous 是 OpenCV 库中的一个函数&#xff0c;用于将点从齐次坐标&#xff08;homogeneous coordinates&#xff09;…...

Jmeter如何对UDP协议进行测试?

Jmeter如何对UDP协议进行测试&#xff1f; 1 jmeter-plugins安装2 UDP-Protocol Support安装3 UDP协议测试 1 jmeter-plugins安装 jmeter-plugins是Jmeter的插件管理器&#xff1b;可以组织和管理Jmeter的所有插件&#xff1b;直接进入到如下页面&#xff0c;选择如图的选项进…...

Unix 传奇 | 谁写了 Linux | Unix birthmark

注&#xff1a;本文为 “左耳听风”陈皓的 unix 相关文章合辑。 皓侠已走远&#xff0c;文章有点“年头”&#xff0c;但值得一阅。 文中部分超链已沉寂。 Unix 传奇 (上篇) 2010 年 04 月 09 日 陈皓 了解过去&#xff0c;我们才能知其然&#xff0c;更知所以然。总结过去…...

【网络】传输层协议UDP/TCP网络层IP数据链路层MACNAT详解

主页&#xff1a;醋溜马桶圈-CSDN博客 专栏&#xff1a;计算机网络原理_醋溜马桶圈的博客-CSDN博客 gitee&#xff1a;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在无人机推流直播安防监控中的创新应用

无人机与低空经济的关系密切&#xff0c;并且正在快速发展。2024年中国低空经济行业市场规模达到5800亿元&#xff0c;其中低空制造产业占整个低空经济产业的88%。预计未来五年复合增速将达到16.03%。 随着科技的飞速发展&#xff0c;公共安防关乎每一个市民的生命财产安全。在…...

ORACLE逗号分隔的字符串字段,关联表查询

使用场景如下&#xff1a; oracle12 以前的写法&#xff1a; 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 以后的写法&#xff1a; selectt.pro_ids,listagg(DIS…...

1.5 多媒体系统简介

目录 多媒体系统声音图形与图像动画和视频 多媒体系统 多媒体可分为感觉媒体、表示媒体、表现媒体、交换媒体。 感觉媒体&#xff1a;直接使人产生感觉的媒体&#xff0c;比如声音、图像、视频。表示媒体&#xff1a;计算机中记录感觉的数据格式。表现媒体&#xff1a;记录感觉…...

数据分析学习Day1-使用matplotlib生成2小时每分钟的气温可视化分析图

注意&#xff1a;需要提前下载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 注意&#xff1a;count函数是计算区域中包含数字的单元格的个数&#xff0c;以上案例中两个空白单元格和一个中文列标题都是没有计算在内的。 平均函数AVERAGE也是按照17进行求平均值的。所以在使用平均值的函数时候&#xff0c;可以根据实际情况看是…...

opencv实现给图像加上logo图像

要用Python和OpenCV给图片加上logo&#xff0c;可以按照以下步骤实现&#xff1a; 读取logo和image图片。 调整logo的大小以适应image。 将logo放置在image的指定位置。 将logo和image合并。 以下是实现代码&#xff1a; import cv2# 读取logo和image图片 logo cv2.imre…...

亚马逊云科技2024 re:Invent大会亮点:Nova大模型与AI基础设施全面升级

引言 作为云计算领域的年度盛会,亚马逊云科技(AWS)的re:Invent大会一直是业界瞩目的焦点。2024年的大会不负众望,推出了一系列重磅产品和服务,尤其是在人工智能和大模型方面的创新令人印象深刻。本文将为您深入解析此次大会的主要亮点,探讨AWS在AI时代的最新布局及其对行业的潜…...

总结与提升

今天学习了ai&#xff0c;对今天学习的内容进行总结。 本文参考chat gpt-4的训练文献。 模型架构基础 Transformer 架构&#xff1a;ChatGPT 采用了 Transformer 架构&#xff0c;这是一种基于自注意力机制的深度学习模型架构。它能够并行计算文本中的长期依赖关系&#xff…...

入门pytorch-Transformer

前言 虽然Transformer是2017年由Google推出&#xff0c;如果按照读论文只读近两年的思路看&#xff0c;那它无疑是过时的&#xff0c;但可惜的是&#xff0c;目前很多论文的核心依然是Transformer&#xff0c;或者由其进行改进的&#xff0c;故本文使用pytorch来搭建一下Trans…...

泛型编程--

auto自动推导数据类型 函数模板 定义和调用 函数模板具体化 函数模板通用版本之外的一个特殊版本 函数模板 具体化函数 &#xff0c;它们的声明和定义都可以分开写。 声明 定义 函数模板写变量 模板参数缺省 类成员函数作为函数模板 类构造函数是函数模板 函数模板重载 函数模…...

【大语言模型】LangChain 核心模块介绍(Agents)

【大语言模型】LangChain 核心模块介绍&#xff08;Agents&#xff09; 一、简介二、Agents 的核心概念三、实战案例3.1、需求说明3.2、实现思路3.3、完整源码 一、简介 我们都知道四肢的绝大部分动作都是由大脑决定的&#xff0c;大脑通过中枢神经下发自己的操作指令&#xf…...

19C-RAC 环境mgmtca.trc.1过大

客户监控告警/u01使用率超过80%&#xff0c;通过一层层目录查看&#xff0c;发现是mgmtca.trc.1过大导致的告警 [rootgsdb1 ~]# du -sh /u01/app/grid/cfgtoollogs/mgmtca/mgmtca.trc.1 103G /u01/app/grid/cfgtoollogs/mgmtca/mgmtca.trc.1 查看MOS文档&#xff1a;Huge …...

使用VSCode开发Django指南

使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架&#xff0c;专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用&#xff0c;其中包含三个使用通用基本模板的页面。在此…...

脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)

一、数据处理与分析实战 &#xff08;一&#xff09;实时滤波与参数调整 基础滤波操作 60Hz 工频滤波&#xff1a;勾选界面右侧 “60Hz” 复选框&#xff0c;可有效抑制电网干扰&#xff08;适用于北美地区&#xff0c;欧洲用户可调整为 50Hz&#xff09;。 平滑处理&…...

DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径

目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...

论文浅尝 | 基于判别指令微调生成式大语言模型的知识图谱补全方法(ISWC2024)

笔记整理&#xff1a;刘治强&#xff0c;浙江大学硕士生&#xff0c;研究方向为知识图谱表示学习&#xff0c;大语言模型 论文链接&#xff1a;http://arxiv.org/abs/2407.16127 发表会议&#xff1a;ISWC 2024 1. 动机 传统的知识图谱补全&#xff08;KGC&#xff09;模型通过…...

Unit 1 深度强化学习简介

Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库&#xff0c;例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体&#xff0c;比如 SnowballFight、Huggy the Do…...

python执行测试用例,allure报乱码且未成功生成报告

allure执行测试用例时显示乱码&#xff1a;‘allure’ &#xfffd;&#xfffd;&#xfffd;&#xfffd;&#xfffd;ڲ&#xfffd;&#xfffd;&#xfffd;&#xfffd;ⲿ&#xfffd;&#xfffd;&#xfffd;Ҳ&#xfffd;&#xfffd;&#xfffd;ǿ&#xfffd;&am…...

关键领域软件测试的突围之路:如何破解安全与效率的平衡难题

在数字化浪潮席卷全球的今天&#xff0c;软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件&#xff0c;这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下&#xff0c;实现高效测试与快速迭代&#xff1f;这一命题正考验着…...

无人机侦测与反制技术的进展与应用

国家电网无人机侦测与反制技术的进展与应用 引言 随着无人机&#xff08;无人驾驶飞行器&#xff0c;UAV&#xff09;技术的快速发展&#xff0c;其在商业、娱乐和军事领域的广泛应用带来了新的安全挑战。特别是对于关键基础设施如电力系统&#xff0c;无人机的“黑飞”&…...

C++课设:简易日历程序(支持传统节假日 + 二十四节气 + 个人纪念日管理)

名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 专栏介绍:《编程项目实战》 目录 一、为什么要开发一个日历程序?1. 深入理解时间算法2. 练习面向对象设计3. 学习数据结构应用二、核心算法深度解析…...

【堆垛策略】设计方法

堆垛策略的设计是积木堆叠系统的核心&#xff0c;直接影响堆叠的稳定性、效率和容错能力。以下是分层次的堆垛策略设计方法&#xff0c;涵盖基础规则、优化算法和容错机制&#xff1a; 1. 基础堆垛规则 (1) 物理稳定性优先 重心原则&#xff1a; 大尺寸/重量积木在下&#xf…...