C++使用WebView2控件,通过IPC通信与Javascript交互
引言
在现代桌面应用程序开发中,Web技术与原生应用的融合变得越来越普遍。Microsoft的WebView2控件为C++开发者提供了一个强大的工具,使他们能够在桌面应用中嵌入基于Chromium的Web浏览器引擎。本文将详细介绍如何在C++应用程序中使用WebView2控件,并通过IPC(进程间通信)机制实现C++与JavaScript之间的双向交互。
WebView2简介
WebView2是Microsoft推出的新一代Web视图控件,基于Chromium引擎,替代了旧的MSHTML(IE)引擎。它允许开发者在Windows应用程序中嵌入Web内容,并提供了丰富的API用于控制Web视图和与Web内容交互。
WebView2的主要优势
- 现代Web标准支持:基于Chromium引擎,支持最新的HTML5、CSS3和JavaScript特性
- 与系统浏览器独立:不依赖于系统安装的浏览器版本
- 强大的通信机制:提供多种方式实现本地代码与Web内容的通信
- 安全性:Web内容在独立的进程中运行,提高了应用的稳定性和安全性
环境准备
在开始开发之前,需要准备以下环境:
- Visual Studio:推荐使用Visual Studio 2019或更高版本
- WebView2 SDK:可以通过NuGet包管理器安装
- C++开发环境:确保已安装C++桌面开发工作负载
安装WebView2 SDK
使用NuGet包管理器安装WebView2 SDK:
Install-Package Microsoft.Web.WebView2
或者在Visual Studio的NuGet包管理器中搜索并安装"Microsoft.Web.WebView2"。
创建基本WebView2应用
首先,我们来创建一个基本的WebView2应用程序。以下是一个简单的示例,展示如何在Win32应用程序中嵌入WebView2控件:
#include <windows.h>
#include <wrl.h>
#include <wil/com.h>
#include <WebView2.h>
#include <WebView2EnvironmentOptions.h>using namespace Microsoft::WRL;// WebView2控件
static wil::com_ptr<ICoreWebView2Controller> webViewController;
static wil::com_ptr<ICoreWebView2> webView;// 初始化WebView2
HRESULT InitializeWebView(HWND hWnd)
{// 创建WebView2环境return CreateCoreWebView2EnvironmentWithOptions(nullptr, nullptr, nullptr,Callback<ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler>([hWnd](HRESULT result, ICoreWebView2Environment* env) -> HRESULT {// 创建WebView2控制器env->CreateCoreWebView2Controller(hWnd, Callback<ICoreWebView2CreateCoreWebView2ControllerCompletedHandler>([hWnd](HRESULT result, ICoreWebView2Controller* controller) -> HRESULT {if (controller != nullptr) {webViewController = controller;webViewController->get_CoreWebView2(&webView);// 设置WebView2的大小RECT bounds;GetClientRect(hWnd, &bounds);webViewController->put_Bounds(bounds);// 导航到初始URLwebView->Navigate(L"https://www.example.com");}return S_OK;}).Get());return S_OK;}).Get());
}// 窗口过程
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{switch (message){case WM_CREATE:InitializeWebView(hWnd);return 0;case WM_SIZE:if (webViewController != nullptr) {RECT bounds;GetClientRect(hWnd, &bounds);webViewController->put_Bounds(bounds);}return 0;case WM_DESTROY:PostQuitMessage(0);return 0;default:return DefWindowProc(hWnd, message, wParam, lParam);}
}// 程序入口点
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{// 注册窗口类WNDCLASSEX wcex = {};wcex.cbSize = sizeof(WNDCLASSEX);wcex.style = CS_HREDRAW | CS_VREDRAW;wcex.lpfnWndProc = WindowProc;wcex.hInstance = hInstance;wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);wcex.lpszClassName = L"WebView2Sample";RegisterClassEx(&wcex);// 创建窗口HWND hWnd = CreateWindow(L"WebView2Sample", L"WebView2 Sample",WS_OVERLAPPEDWINDOW,CW_USEDEFAULT, CW_USEDEFAULT, 1200, 900,nullptr, nullptr, hInstance, nullptr);if (!hWnd) {return 1;}// 显示窗口ShowWindow(hWnd, nCmdShow);UpdateWindow(hWnd);// 消息循环MSG msg = {};while (GetMessage(&msg, nullptr, 0, 0)) {TranslateMessage(&msg);DispatchMessage(&msg);}return (int)msg.wParam;
}
这段代码创建了一个简单的窗口,并在其中嵌入了WebView2控件,导航到example.com网站。
实现C++与JavaScript的IPC通信
WebView2提供了多种方式实现C++与JavaScript之间的通信。最常用的两种方式是:
- PostMessage/AddScriptToExecuteOnDocumentCreated:用于在C++和JavaScript之间传递消息
- WebMessage API:提供了更结构化的消息传递机制
从C++调用JavaScript
可以使用ExecuteScript
方法从C++调用JavaScript代码:
// 从C++调用JavaScript函数
void CallJavaScriptFunction(const std::wstring& functionName, const std::wstring& parameter)
{if (webView) {std::wstring script = functionName + L"('" + parameter + L"');";webView->ExecuteScript(script.c_str(), nullptr);}
}// 示例:调用JavaScript函数
CallJavaScriptFunction(L"updateStatus", L"Connected from C++");
从JavaScript调用C++
要从JavaScript调用C++代码,我们可以使用AddHostObjectToScript
或WebMessageReceived
事件。以下是使用WebMessageReceived
的示例:
// 设置WebMessage处理程序
void SetupWebMessageHandler()
{if (webView) {// 注册消息处理程序webView->add_WebMessageReceived(Callback<ICoreWebView2WebMessageReceivedEventHandler>([](ICoreWebView2* sender, ICoreWebView2WebMessageReceivedEventArgs* args) -> HRESULT {LPWSTR message;args->TryGetWebMessageAsString(&message);// 处理来自JavaScript的消息ProcessMessageFromJs(message);CoTaskMemFree(message);return S_OK;}).Get(), nullptr);// 注入JavaScript代码,使Web页面能够向C++发送消息webView->AddScriptToExecuteOnDocumentCreated(L"window.chrome.webview.postMessage = function(message) {"L" window.chrome.webview.postMessage(message);"L"};"L"window.callNative = function(functionName, parameter) {"L" window.chrome.webview.postMessage(JSON.stringify({function: functionName, param: parameter}));"L"};",nullptr);}
}// 处理来自JavaScript的消息
void ProcessMessageFromJs(const std::wstring& message)
{// 这里可以解析JSON消息,执行相应的本地功能// 例如,可以使用JSON库解析message,然后根据function字段调用不同的C++函数// 简单示例:打印消息OutputDebugString((L"Message from JS: " + message + L"\n").c_str());// 响应消息(可选)if (webView) {webView->PostWebMessageAsString(L"Message received by C++");}
}
在JavaScript端,可以这样调用C++:
// 调用C++函数
function callCppFunction(functionName, parameter) {window.chrome.webview.postMessage(JSON.stringify({function: functionName,param: parameter}));
}// 示例:调用C++函数
callCppFunction('saveData', 'This is data from JavaScript');// 接收C++的响应
window.chrome.webview.addEventListener('message', function(event) {console.log('Response from C++:', event.data);
});
完整的IPC通信示例
下面是一个更完整的示例,展示了C++和JavaScript之间的双向通信:
C++部分
#include <windows.h>
#include <wrl.h>
#include <wil/com.h>
#include <WebView2.h>
#include <WebView2EnvironmentOptions.h>
#include <string>
#include <sstream>
#include <nlohmann/json.hpp>using namespace Microsoft::WRL;
using json = nlohmann::json;// WebView2控件
static wil::com_ptr<ICoreWebView2Controller> webViewController;
static wil::com_ptr<ICoreWebView2> webView;// 处理来自JavaScript的消息
void ProcessMessageFromJs(const std::wstring& messageW)
{// 将wstring转换为string以便使用JSON库std::string message(messageW.begin(), messageW.end());try {auto jsonData = json::parse(message);std::string function = jsonData["function"];std::string param = jsonData["param"];// 根据function字段调用不同的C++函数if (function == "saveData") {// 保存数据的示例实现OutputDebugStringA(("Saving data: " + param + "\n").c_str());// 响应JavaScriptif (webView) {webView->PostWebMessageAsString(L"Data saved successfully");}}else if (function == "getData") {// 获取数据的示例实现std::string data = "Sample data from C++ - " + param;OutputDebugStringA(("Getting data for: " + param + "\n").c_str());// 调用JavaScript函数返回数据if (webView) {std::wstring script = L"receiveDataFromCpp('" + std::wstring(data.begin(), data.end()) + L"');";webView->ExecuteScript(script.c_str(), nullptr);}}}catch (const std::exception& e) {OutputDebugStringA(("Error parsing JSON: " + std::string(e.what()) + "\n").c_str());}
}// 初始化WebView2
HRESULT InitializeWebView(HWND hWnd)
{// 创建WebView2环境return CreateCoreWebView2EnvironmentWithOptions(nullptr, nullptr, nullptr,Callback<ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler>([hWnd](HRESULT result, ICoreWebView2Environment* env) -> HRESULT {// 创建WebView2控制器env->CreateCoreWebView2Controller(hWnd, Callback<ICoreWebView2CreateCoreWebView2ControllerCompletedHandler>([hWnd](HRESULT result, ICoreWebView2Controller* controller) -> HRESULT {if (controller != nullptr) {webViewController = controller;webViewController->get_CoreWebView2(&webView);// 设置WebView2的大小RECT bounds;GetClientRect(hWnd, &bounds);webViewController->put_Bounds(bounds);// 设置WebMessage处理程序webView->add_WebMessageReceived(Callback<ICoreWebView2WebMessageReceivedEventHandler>([](ICoreWebView2* sender, ICoreWebView2WebMessageReceivedEventArgs* args) -> HRESULT {LPWSTR message;args->TryGetWebMessageAsString(&message);// 处理来自JavaScript的消息ProcessMessageFromJs(message);CoTaskMemFree(message);return S_OK;}).Get(), nullptr);// 注入JavaScript代码webView->AddScriptToExecuteOnDocumentCreated(L"window.callNative = function(functionName, parameter) {"L" window.chrome.webview.postMessage(JSON.stringify({function: functionName, param: parameter}));"L"};"L"window.receiveDataFromCpp = function(data) {"L" document.getElementById('result').innerText = data;"L"};",nullptr);// 导航到本地HTML文件webView->Navigate(L"file:///C:/path/to/your/index.html");}return S_OK;}).Get());return S_OK;}).Get());
}// 窗口过程
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{switch (message){case WM_CREATE:InitializeWebView(hWnd);return 0;case WM_SIZE:if (webViewController != nullptr) {RECT bounds;GetClientRect(hWnd, &bounds);webViewController->put_Bounds(bounds);}return 0;case WM_DESTROY:PostQuitMessage(0);return 0;default:return DefWindowProc(hWnd, message, wParam, lParam);}
}// 程序入口点
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{// 注册窗口类WNDCLASSEX wcex = {};wcex.cbSize = sizeof(WNDCLASSEX);wcex.style = CS_HREDRAW | CS_VREDRAW;wcex.lpfnWndProc = WindowProc;wcex.hInstance = hInstance;wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);wcex.lpszClassName = L"WebView2IPCSample";RegisterClassEx(&wcex);// 创建窗口HWND hWnd = CreateWindow(L"WebView2IPCSample", L"WebView2 IPC Sample",WS_OVERLAPPEDWINDOW,CW_USEDEFAULT, CW_USEDEFAULT, 1200, 900,nullptr, nullptr, hInstance, nullptr);if (!hWnd) {return 1;}// 显示窗口ShowWindow(hWnd, nCmdShow);UpdateWindow(hWnd);// 消息循环MSG msg = {};while (GetMessage(&msg, nullptr, 0, 0)) {TranslateMessage(&msg);DispatchMessage(&msg);}return (int)msg.wParam;
}
HTML/JavaScript部分 (index.html)
<!DOCTYPE html>
<html>
<head><title>WebView2 IPC Demo</title><style>body {font-family: Arial, sans-serif;margin: 20px;}button {margin: 10px 0;padding: 8px 16px;}#result {margin-top: 20px;padding: 10px;border: 1px solid #ccc;min-height: 100px;}</style>
</head>
<body><h1>WebView2 IPC通信演示</h1><div><input type="text" id="inputData" placeholder="输入数据"><button onclick="saveData()">保存数据到C++</button><button onclick="getData()">从C++获取数据</button></div><div><h3>结果:</h3><div id="result"></div></div><script>// 保存数据到C++function saveData() {const data = document.getElementById('inputData').value;window.callNative('saveData', data);}// 从C++获取数据function getData() {const query = document.getElementById('inputData').value || 'default';window.callNative('getData', query);}// 接收C++的响应window.chrome.webview.addEventListener('message', function(event) {document.getElementById('result').innerText = event.data;});</script>
</body>
</html>
高级IPC通信技术
除了基本的消息传递外,WebView2还提供了一些高级的IPC通信技术:
1. 使用AddHostObjectToScript
AddHostObjectToScript
允许将C++对象直接暴露给JavaScript,使JavaScript可以直接调用C++对象的方法:
// 定义要暴露给JavaScript的COM对象
class HostObject : public Microsoft::WRL::RuntimeClass<Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>,IDispatch> {
public:// IDispatch实现...// 示例方法HRESULT Add(int a, int b, int* result) {*result = a + b;return S_OK;}
};// 将对象暴露给JavaScript
void ExposeHostObjectToJs()
{if (webView) {auto hostObject = Make<HostObject>();webView->AddHostObjectToScript(L"cppObject", hostObject.Get());}
}
在JavaScript中:
// 直接调用C++对象的方法
const result = window.chrome.webview.hostObjects.cppObject.Add(5, 3);
console.log('Result:', result);
2. 使用DevToolsProtocol
WebView2还支持Chrome DevTools Protocol (CDP),可以用于高级调试和控制:
// 使用CDP发送命令
void SendDevToolsCommand()
{if (webView) {webView->CallDevToolsProtocolMethod(L"Network.enable", L"{}", nullptr);}
}
3. 使用自定义事件
可以使用自定义事件在C++和JavaScript之间建立更结构化的通信:
// C++中发送事件
void SendEventToJs(const std::wstring& eventName, const std::wstring& eventData)
{if (webView) {std::wstring script = L"document.dispatchEvent(new CustomEvent('" + eventName + L"', { detail: " + eventData + L" }));";webView->ExecuteScript(script.c_str(), nullptr);}
}
在JavaScript中:
// 监听来自C++的事件
document.addEventListener('myCustomEvent', function(event) {console.log('Event received:', event.detail);
});
性能优化与最佳实践
在使用WebView2进行IPC通信时,有一些性能优化和最佳实践需要注意:
1. 批量处理消息
对于频繁的通信,应该考虑批量处理消息,而不是每次都单独发送:
// C++批量发送数据
void SendBatchData(const std::vector<std::wstring>& dataItems)
{if (webView && !dataItems.empty()) {std::wstringstream ss;ss << L"[";for (size_t i = 0; i < dataItems.size(); ++i) {ss << L"'" << dataItems[i] << L"'";if (i < dataItems.size() - 1) {ss << L",";}}ss << L"]";std::wstring script = L"processBatchData(" + ss.str() + L");";webView->ExecuteScript(script.c_str(), nullptr);}
}
2. 使用二进制数据传输
对于大量数据,考虑使用二进制格式而不是文本格式:
// 在JavaScript中使用ArrayBuffer
function sendBinaryData() {const buffer = new ArrayBuffer(1024);const view = new Uint8Array(buffer);// 填充数据...// 将ArrayBuffer转换为Base64const base64 = arrayBufferToBase64(buffer);window.callNative('processBinaryData', base64);
}function arrayBufferToBase64(buffer) {let binary = '';const bytes = new Uint8Array(buffer);for (let i = 0; i < bytes.byteLength; i++) {binary += String.fromCharCode(bytes[i]);}return window.btoa(binary);
}
在C++中:
// 处理二进制数据
void ProcessBinaryData(const std::string& base64Data)
{// 解码Base64数据// 处理二进制数据...
}
3. 避免频繁的DOM操作
在JavaScript中,避免频繁的DOM操作,可以使用虚拟DOM或批量更新:
// 批量更新DOM
function updateElements(dataArray) {const fragment = document.createDocumentFragment();dataArray.forEach(item => {const div = document.createElement('div');div.textContent = item;fragment.appendChild(div);});document.getElementById('container').appendChild(fragment);
}
4. 使用异步通信
对于不需要立即响应的操作,使用异步通信可以提高性能:
// C++中异步处理消息
void ProcessMessageAsync(const std::wstring& message)
{// 在另一个线程中处理消息std::thread([message]() {// 处理消息...// 处理完成后通知JavaScript// 注意:需要在UI线程中调用ExecuteScript}).detach();
}
安全性考虑
在使用WebView2进行IPC通信时,需要注意以下安全问题:
1. 输入验证
始终验证从JavaScript接收的数据,防止注入攻击:
// 验证输入数据
bool ValidateInput(const std::wstring& input)
{// 实现适当的验证逻辑return true; // 示例
}
2. 限制JavaScript访问权限
只暴露必要的功能给JavaScript:
// 限制JavaScript访问权限
void LimitJsAccess()
{if (webView) {// 设置WebView2的权限ICoreWebView2Settings* settings;webView->get_Settings(&settings);// 禁用JavaScript对文件系统的访问settings->put_IsWebMessageEnabled(TRUE);settings->put_AreDefaultScriptDialogsEnabled(FALSE);settings->put_IsScriptEnabled(TRUE);settings->put_AreDevToolsEnabled(FALSE);}
}
3. 使用内容安全策略
在HTML中使用内容安全策略限制JavaScript的行为:
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
调试技巧
调试WebView2应用程序中的IPC通信可能具有挑战性。以下是一些有用的调试技巧:
1. 启用开发者工具
在开发过程中启用WebView2的开发者工具:
// 启用开发者工具
void EnableDevTools()
{if (webView) {ICoreWebView2Settings* settings;webView->get_Settings(&settings);settings->put_AreDevToolsEnabled(TRUE);// 打开开发者工具webView->OpenDevToolsWindow();}
}
2. 日志记录
在C++和JavaScript中添加详细的日志记录:
// C++日志记录
void LogMessage(const std::wstring& message)
{OutputDebugString((L"[C++] " + message + L"\n").c_str());
}
// JavaScript日志记录
function logMessage(message) {console.log(`[JS] ${message}`);
}
3. 使用事件监听器调试通信
在JavaScript中添加事件监听器来监视通信:
// 监视所有WebMessage通信
window.chrome.webview.addEventListener('message', function(event) {console.log('Message from C++:', event.data);
});
实际应用场景
WebView2的IPC通信机制可以应用于多种场景:
1. 混合桌面应用
创建具有原生性能和Web界面优势的混合应用:
- 使用C++处理复杂计算、文件操作和系统集成
- 使用Web技术创建现代化、响应式的用户界面
2. 离线Web应用
创建可以在没有互联网连接的情况下工作的Web应用:
- 使用C++处理本地数据存储和同步
- 使用Web技术提供用户界面
3. 扩展现有应用
为现有的C++应用程序添加Web功能:
- 逐步将传统应用程序的部分UI迁移到Web技术
- 保留现有的C++业务逻辑
结论
WebView2为C++开发者提供了一个强大的工具,使他们能够在桌面应用中嵌入现代Web技术,并通过IPC机制实现C++与JavaScript之间的无缝通信。通过本文介绍的技术,开发者可以创建兼具原生性能和Web灵活性的应用程序。
参考资料
- Microsoft WebView2 官方文档
- WebView2 Samples
- WebView2 API Reference
- C++/WinRT Documentation
- Windows App SDK
相关文章:
C++使用WebView2控件,通过IPC通信与Javascript交互
引言 在现代桌面应用程序开发中,Web技术与原生应用的融合变得越来越普遍。Microsoft的WebView2控件为C开发者提供了一个强大的工具,使他们能够在桌面应用中嵌入基于Chromium的Web浏览器引擎。本文将详细介绍如何在C应用程序中使用WebView2控件ÿ…...
算法中Hash备胎——LRU的设计与实现
核心内容1.理解LRU的原理2.理解LRU是如何实现的3.能够通过代码实现LRU 缓存是应用软件的必备功能之一,在操作系统、Java里的Spring、mybatis、redis、mysql等软件中都有自己的内部缓存模块,而缓存是如何实现的? 在操作系统教科书里我们知道…...
Profinet邂逅ModbusRTU:印刷厂有网关“一键打通”通信链路
Profinet邂逅ModbusRTU:印刷厂有网关“一键打通”通信链路 在现代化印刷厂的生产线上,高效稳定的设备通信是保障印刷质量和生产效率的关键。某印刷厂的印刷机控制系统采用了西门子PLC进行自动化控制,同时还有众多基于ModbusRTU协议的传感器和…...
Spring中使用Kafka的详细配置,以及如何集成 KRaft 模式的 Kafka
在 Spring 中使用 Apache Kafka 的配置主要涉及 Spring Boot Starter for Kafka,而开启 KRaft 模式(Kafka 的元数据管理新模式,替代 ZooKeeper)需要特定的 Kafka Broker 配置。以下是详细步骤: 一、Spring 中集成 …...
C++之继承
本节我们将要学习C作为面向对象语言的三大特性之一的继承。 前言 一、继承的概念 二、继承的定义 2.1 定义格式 2.2 继承基类成员访问方式的变化 2.3 继承类模板 三、基类和派生类之间的转换 四、继承中的作用域 五、派生类的默认成员函数 六、实现一个不能被继承的类 七、继承…...
服务器申请 SSL 证书注意事项
一、确认证书类型 基础域名型(DV):这类证书验证速度最快,通常只需验证域名所有权,几分钟到几小时即可颁发。适用于个人博客、小型企业展示网站等对安全性要求不是顶级严苛,且急需启用 HTTPS 的场景。但它仅…...
【资料分享】全志T536(异构多核ARMCortex-A55+玄铁E907 RISC-V)工业核心板说明书
核心板简介 创龙科技SOM-TLT536是一款基于全志科技T536MX-CEN2/T536MX-CXX四核ARM Cortex-A55 +...
博途 TIA Portal之1200做从站与调试助手的TCP通讯
其实,1200做从站与调试助手做TCP通讯很简单,只需要在组态时把“主动建立连接”放在对侧即可。但是我们还是要从头讲起,以方便没有基础的朋友能直接上手操作。 1、硬件准备 1200PLC一台,带调试助手的PC机一台,调试助手…...
移动端六大语言速记:第9部分 - 并发与多线程
移动端六大语言速记:第9部分 - 并发与多线程 本文将对比Java、Kotlin、Flutter(Dart)、Python、ArkTS和Swift这六种移动端开发语言在并发与多线程方面的特性,帮助开发者理解和掌握各语言的并发编程机制。 9. 并发与多线程 9.1 线程与进程 各语言线程与进程的创建和管理方…...
基于大模型的ALS预测与手术优化系统技术方案
目录 技术方案文档:基于大模型的ALS预测与手术优化系统1. 数据预处理与特征工程模块流程图伪代码2. 多模态融合预测模型模型架构图伪代码3. 术中实时监测与动态干预系统系统流程图伪代码4. 统计验证与可解释性模块验证流程图伪代码示例(SHAP分析)5. 健康教育与交互系统系统架…...
【Vue3知识】组件间通信的方式
组件间通信的方式 概述**1. 父子组件通信****父组件向子组件传递数据(Props)****子组件向父组件发送事件(自定义事件)** **2. 兄弟组件通信****通过父组件中转****使用全局状态管理(如 Pinia 或 Vuex)** **…...
【数据挖掘】岭回归(Ridge Regression)和线性回归(Linear Regression)对比实验
这是一个非常实用的 岭回归(Ridge Regression)和线性回归(Linear Regression)对比实验,使用了 scikit-learn 中的 California Housing 数据集 来预测房价。 📦 第一步:导入必要的库 import num…...
RuntimeError: Error(s) in loading state_dict for ChartParser
一 bug错误 最近使用千问大模型有一个bug,报错信息如下 raise RuntimeError(Error(s) in loading state_dict for {}:\n\t{}.format( RuntimeError: Error(s) in loading state_dict for ChartParser:Unexpected key(s) in state_dict: "pretrained_model.em…...
汽车无钥匙启动125KHz低频发射天线工作原理
汽车智能钥匙低频天线是无钥匙进入(PE)及无钥匙启动(PS)系统的一部分,主要负责发送低频信号,探测智能钥匙与各低频天线间的相对位置,判断车内是否存在智能钥匙。 支持PEPS系统实现便捷操作 无…...
【Docker基础-镜像】--查阅笔记2
目录 Docker镜像概述base镜像镜像的分层结构镜像的理解镜像的构建docker commit 制作镜像DockerfileDockerfile 指令FROMLABELRUNARGENVADDCOPYWORKDIRUSERVOLUMEEXPOSECMD 和 ENTRYPOINT Docker镜像概述 镜像是Docker容器的基石,容器是镜像的运行实例,…...
LeetCode 第47题:旋转数组
LeetCode 第47题:旋转数组 题目描述 给定一个 n n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。 你必须在 原地 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。 示例1: 输入…...
数据库管理工具实战:IDEA 与 DBeaver 连接 TDengine(二)
五、DBeaver 连接 TDengine 实战 5.1 安装 DBeaver 下载安装包:访问 DBeaver 官方网站(https://dbeaver.io/download/ ),根据你的操作系统选择合适的安装包。如果是 Windows 系统,下载.exe 格式的安装文件࿱…...
4S店汽车维修保养管理系统 (源码+lw+部署文档+讲解),源码可白嫖!
摘要 二十一世纪我们的社会进入了信息时代,信息管理系统的建立,大大提高了人们信息化水平。传统的管理方式已经与当今4S店汽车维修保养管理系统的业务需求不相适应,也与4S店汽车维修保养管理系统化建设的发展趋势不相适应。本文针对这一需求设计并实现了…...
【Mysql】主从复制部署(保姆级)
本次部署用到三台Ubuntu虚拟机(一主两从): Master服务器:192.168.166.107 Slave1服务器:192.168.166.101 Slave2服务器:192.168.166.103 一、部署思路 首先我们要先捋清主从复制的部署思路…...
华为AR1200密码忘记
1、通过Console口连接设备并重启设备。在设备启动过程中,看到提示信息“Press CtrlB to break auto startup...”时,在三秒内按下CtrlB,输入BootLoader密码后,默认密码:Adminhuawei ,进入BootLoader主菜单…...
高级java每日一道面试题-2025年3月26日-微服务篇[Nacos篇]-在Spring Cloud项目中如何集成Nacos?
如果有遗漏,评论区告诉我进行补充 面试官: 在Spring Cloud项目中如何集成Nacos? 我回答: 在Spring Cloud项目中集成Nacos,可以充分利用Nacos作为服务注册与发现中心以及配置管理中心的功能。以下是详细的步骤和说明,帮助你完成这一集成过程…...
YOLO-LLTS:低光照实时交通标志检测算法详解
论文地址:https://arxiv.org/pdf/2503.13883 目录 一、论文概述 1.1 研究背景 1.2 论文结构 二、核心创新点 2.1 CNTSSS数据集 2.2 HRFM-TOD模块 2.3 MFIA模块 2.4 PGFE模块 三、实验与结果 3.1 实验设置 3.2 性能对比 编辑3.3 消融实验 四、代码复现建议 4.…...
golang 性能优化分析工具 pprof
pprof简介 pprof 是 Go 语言标准库提供的一个强大的性能分析工具,它能帮助开发者深入了解程序的运行时行为,找出性能瓶颈,进而对代码进行优化。下面从多个方面对 pprof 进行详细介绍: 主要功能 CPU 性能分析:能够记…...
机器学习 Day09 线性回归
1.线性回归简介 线性回归知识讲解 定义与公式 定义:线性回归是利用回归方程(函数)对自变量(特征值)和因变量(目标值)之间关系进行建模的分析方式 。自变量只有一个时是单变量回归,…...
2025高频面试算法总结篇【字符串】
文章目录 直接刷题链接直达如何找出一个字符串中的最大不重复子串给定一个数,删除K位得到最大值字符串的排列至少有K个重复字符的最长子串 直接刷题链接直达 如何找出一个字符串中的最大不重复子串 滑动窗口 --> 滑动窗口直到最后一个元素,每当碰到重…...
JavaScript性能优化(上)
1. 减少 DOM 操作 减少 DOM 操作是优化 JavaScript 性能的重要方法,因为频繁的 DOM 操作会导致浏览器重绘和重排,从而影响性能。以下是一些具体的策略和技术,可以帮助有效减少 DOM 操作: 1.1. 批量更新 DOM 亲切与母体ÿ…...
数据结构与算法——链表OJ题详解(1)
文章目录 一、前言二、OJ题分享2.1移除链表元素——非val尾插法2.2反转链表2.2.1头插法2.2.2三指针法 2.3链表的中间结点——快慢指针法2.4合并两个有序链表2.4.1空链表法2.4.2非空链表法 2.5链表的回文结构2.5.1投机取巧数组法2.5.2反转链表法 三、总结 一、前言 前几天博主已…...
sedex认证2025年变化重点
近日,SEDEX突然宣布:2025年7月1日起,全通知审核正式退出历史舞台,取而代之的是至少3周窗口期的半通知突击审核。这场被业内称为“供应链透明化革命”的调整,或将重塑全球工厂合规生态。 三大变化划重点: 1…...
Scala课后总结(8)
集合计算高级函数 过滤(filter) 从集合里挑出符合特定条件元素组成新集合 。比如从整数集合里选出偶数, list.filter(x > x % 2 0) ,就是筛选出能被2整除的元素。 转化/映射(map) 对集合每个元素应…...
老硬件也能运行的Win11 IoT LTSC (OEM)物联网版
#记录工作 Windows 11 IoT Enterprise LTSC 2024 属于物联网相关的版本。 Windows 11 IoT Enterprise 是为物联网设备和场景设计的操作系统版本。它通常针对特定的工业控制、智能设备等物联网应用进行了优化和定制,以满足这些领域对稳定性、安全性和长期支持的需求…...
蓝桥杯冲刺题单--二分
二分 知识点 二分: 1.序列二分:在序列中查找(不怎么考,会比较难?) 序列二分应用的序列必须是递增或递减,但可以非严格 只要r是mid-1,就对应mid(lr1)/2 2.答…...
计网 2025/4/8
CDMA? CRC循环冗余检验 PPP协议的帧格式 字节填充(异步传输、7E->7D5E)零比特填充(同步传输、确保不会出现连续6个1) CSMA/CD协议 多点接入载波监听碰撞检测 一些概念: 争用期 一些公式: 最短有效帧…...
java设计模式-工厂模式
工厂模式 简单工厂模式 请看类: org.xwb.springcloud.factory.simple.PizzaStore 1、简单工厂模式是属于创建型模式,是工厂模式的一种,简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实力。简单来工厂模式就是工厂模式家族中最简单最…...
2025年客运从业资格证备考刷题题库
题库中通常包含大量的题目,以全面覆盖考试的知识点。通过做大量的题目,考生可以熟悉各种考试题型和命题方式,提高答题的速度和准确性,同时也能发现自己在知识掌握上的薄弱环节,有针对性地进行复习和强化训练。 1、驾驶…...
Zephyr、FreeRTOS、RT-Thread 任务创建对比分析
一、任务模型与核心概念 特性ZephyrFreeRTOSRT-Thread任务术语线程(Thread)任务(Task)线程(Thread)执行单元线程(单地址空间)任务(共享内存空间)线程&#x…...
RK-realtime Linux
rk3562实时性数据:最大76us rk3568实时性数据:最大126us rk3588实时性数据:最大30us 注意事项 (1)RK3568 需要使用RT版本的BL31,实时性能更好 a)rkbin需要更新到最新,且包含这个补丁:...
Ubuntu 22 Linux上部署DeepSeek+RAG知识库操作详解(Dify方式)之1
一、安装Docker 1. 更新你的包索引 首先,确保你的包列表是最新的。打开终端并运行以下命令: sudo apt update 2. 安装必要的依赖项 安装Docker之前,你需要安装一些必要的依赖项。运行以下命令来安装它们: sudo apt install apt…...
将飞帆制作的网页作为 div 集成到自己的网页中
并且自己的网页可以和飞帆中的控件相互调用函数。效果: 上链接 将飞帆制作的网页作为 div 集成到自己的网页中 - 文贝 进入可以复制、运行代码...
【C++游戏引擎开发】《几何算法》(3)AABB/OBB碰撞检测
一、AABB(轴对齐包围盒) 1.1 定义 最小点: m i n = ( x min , y min , z min ) \mathbf{min} = (x_{\text{min}}, y_{\text{min}}, z_{\text{min}}) min=(xmin,ymin,zmin)最大点: m a x = ( x max , y max , z max ) \mathbf{max} = (x_{\text{max}}, y_{\text{…...
基于人工智能的高中教育评价体系重构研究
基于人工智能的高中教育评价体系重构研究 一、引言 1.1 研究背景 在科技飞速发展的当下,人工智能技术已广泛渗透至各个领域,教育领域亦不例外。人工智能凭借其强大的数据处理能力、智能分析能力和个性化服务能力,为教育评价体系的创新与发…...
【C++游戏引擎开发】数学计算库GLM(线性代数)、CGAL(几何计算)的安装与使用指南
写在前面 两天都没手搓实现可用的凸包生成算法相关的代码,自觉无法手搓相关数学库,遂改为使用成熟数学库。 一、GLM库安装与介绍 1.1 vcpkg安装GLM 跨平台C包管理利器vcpkg完全指南 在PowerShell中执行命令: vcpkg install glm# 集成到系…...
Python 字典和集合(常见的映射方法)
本章内容的大纲如下: 常见的字典方法 如何处理查找不到的键 标准库中 dict 类型的变种set 和 frozenset 类型 散列表的工作原理 散列表带来的潜在影响(什么样的数据类型可作为键、不可预知的 顺序,等等) 常见的映射方法 映射类型…...
Qt 自带的QSqlDatabase 模块中使用的 SQLite 和 SQLite 官方提供的 C 语言版本(sqlite.org)对比
Qt 自带的 QSqlDatabase 模块中使用的 SQLite 和 SQLite 官方提供的 C 语言版本(sqlite.org)在核心功能上是相同的,但它们在集成方式、API 封装、功能支持以及版本更新上存在一些区别。以下是主要区别: 1. 核心 SQLite 引擎 Qt 的…...
按键长按代码
这些代码都存放在定时器中断中。中断为100ms中断一次。 数据判断,看的懂就看吧...
zk源码—3.单机和集群通信原理一
大纲 1.单机版的zk服务端的启动过程 (1)预启动阶段 (2)初始化阶段 2.集群版的zk服务端的启动过程 (1)预启动阶段 (2)初始化阶段 (3)Leader选举阶段 (4)Leader和Follower启动阶段 1.单机版的zk服务端的启动过程 (1)预启动阶段 (2)初始化阶段 单机版zk服务端的启动&…...
车企数字化转型:从“制造工厂”到“移动科技平台”的升维路径
一、战略重构:政策与产业变革的双重倒逼 中国《智能网联汽车技术路线图2.0》明确要求2030年L4级自动驾驶新车渗透率达20%,而麦肯锡数据显示,全球车企数字化投入占比已从2018年的7%跃升至2025年的18%。当前车企面临三大核心挑战:用…...
C++-Mongoose(2)-https-server-openssl
OpenSSL生成HTTPS自签名证书 - 简书 1.Openssl windowsubuntu下载http://www.openssl.vip/download1.VS2019编译OpenSSL 2.VS2019编译第一个OpenSSL项目 1.ubuntu编译OpenSSL 3.0 2.编写第一个OpenSSL 1.windows下编译OpenSSL 安装vs2019 perl nasm安装activePerl…...
nginx正向代理https
一、需求 公司内部服务器向外访问腾讯接口:https://qyapi.weixin.qq.com/cgi-bin,不能使用http直接访问。并且不支持域名,还需要设置互联网出口-出向白名单ip。 如何在尽量少改动代码的情况下实现应用的出向访问链接,考虑使用正向…...
Flask中的蓝图(Blueprint)浅讲
BluePrint Flask中的蓝图(Blueprint)是一种强大的组织工具,能够将大型应用拆分为可重用的模块化组件 1. 模块化组织 用途:将应用按功能拆分为独立模块,提升代码可维护性。示例: # user/views.py fr…...
虚拟表、TDgpt、JDBC 异步写入…TDengine 3.3.6.0 版本 8 大升级亮点
近日,TDengine 3.3.6.0 版本正式发布。除了此前已亮相的时序数据分析 AI 智能体 TDgpt,本次更新还带来了多个针对性能与易用性的重要增强:虚拟表全面上线,支持更灵活的一设备一表建模;JDBC 写入机制全新升级࿰…...