当前位置: 首页 > 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 …...

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…...

C++实现分布式网络通信框架RPC(3)--rpc调用端

目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中&#xff0c;我们已经大致实现了rpc服务端的各项功能代…...

基于大模型的 UI 自动化系统

基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...

【Oracle APEX开发小技巧12】

有如下需求&#xff1a; 有一个问题反馈页面&#xff0c;要实现在apex页面展示能直观看到反馈时间超过7天未处理的数据&#xff0c;方便管理员及时处理反馈。 我的方法&#xff1a;直接将逻辑写在SQL中&#xff0c;这样可以直接在页面展示 完整代码&#xff1a; SELECTSF.FE…...

1688商品列表API与其他数据源的对接思路

将1688商品列表API与其他数据源对接时&#xff0c;需结合业务场景设计数据流转链路&#xff0c;重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点&#xff1a; 一、核心对接场景与目标 商品数据同步 场景&#xff1a;将1688商品信息…...

论文阅读:LLM4Drive: A Survey of Large Language Models for Autonomous Driving

地址&#xff1a;LLM4Drive: A Survey of Large Language Models for Autonomous Driving 摘要翻译 自动驾驶技术作为推动交通和城市出行变革的催化剂&#xff0c;正从基于规则的系统向数据驱动策略转变。传统的模块化系统受限于级联模块间的累积误差和缺乏灵活性的预设规则。…...

智能职业发展系统:AI驱动的职业规划平台技术解析

智能职业发展系统&#xff1a;AI驱动的职业规划平台技术解析 引言&#xff1a;数字时代的职业革命 在当今瞬息万变的就业市场中&#xff0c;传统的职业规划方法已无法满足个人和企业的需求。据统计&#xff0c;全球每年有超过2亿人面临职业转型困境&#xff0c;而企业也因此遭…...

AD学习(3)

1 PCB封装元素组成及简单的PCB封装创建 封装的组成部分&#xff1a; &#xff08;1&#xff09;PCB焊盘&#xff1a;表层的铜 &#xff0c;top层的铜 &#xff08;2&#xff09;管脚序号&#xff1a;用来关联原理图中的管脚的序号&#xff0c;原理图的序号需要和PCB封装一一…...

【记录坑点问题】IDEA运行:maven-resources-production:XX: OOM: Java heap space

问题&#xff1a;IDEA出现maven-resources-production:operation-service: java.lang.OutOfMemoryError: Java heap space 解决方案&#xff1a;将编译的堆内存增加一点 位置&#xff1a;设置setting-》构建菜单build-》编译器Complier...

第22节 Node.js JXcore 打包

Node.js是一个开放源代码、跨平台的、用于服务器端和网络应用的运行环境。 JXcore是一个支持多线程的 Node.js 发行版本&#xff0c;基本不需要对你现有的代码做任何改动就可以直接线程安全地以多线程运行。 本文主要介绍JXcore的打包功能。 JXcore 安装 下载JXcore安装包&a…...