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

CMake+QT+大漠插件的桌面应用开发

文章目录

  • CMake+QT+大漠插件的桌面应用开发
    • 说明
    • 环境
    • 项目结构
    • 配置编译环境
    • 代码

CMake+QT+大漠插件的桌面应用开发

说明

  • 在CMake+大漠插件的应用开发——处理dm.dll,免注册调用大漠插件中已经说明了如何免注册调用大漠插件,以及做了几个简单的功能调用(查找窗口、截图)
  • 下面来利用QT做一个简单的窗口查找、截图的桌面工具应用,功能点如下
    • 点击“注册”选项完成大漠插件的注册。
    • 用户在文本框输入窗口标题后,点击“查询”按钮,可对包含该标题的窗口进行查询。
    • 提供表格展示查询到的窗口信息。
    • 点击“截图”按钮,对选中的窗口进行截图并保存。
  • 界面如下

image.png

  • 目前主窗口的UI操作和大漠的调用是在一个线程里面的,当大漠调用时间过长时会出现UI界面卡顿的现象,下一篇将会给出如何处理这种问题的示例。

环境

版本/规范备注
平台win32操作系统为Windows10
CMake3.27.8CLion自带
C++17
ToolchainVisualStudio 2022只用其工具链,记得先安装好
QT5.12.12安装时选择msvc2017,不要64位的
DM7.2353
CLion2023.3.2你也可以用其他IDE工具
  • 启动IDE时,记得以管理员模式启动

项目结构

  • 新建一个项目 qt_dm_demo_x_01
  • 将下载好的 dm.dll 文件以及处理好的 dm.tlh、dm.tli 文件放置到项目的 external 目录下
    • 注:dm.tlh、dm.tli 文件的生成请参考 CMake+大漠插件的应用开发——处理dm.dll,免注册调用大漠插件
qt_dm_demo_x_01					     # 项目目录
--|cmake-build-debug-visual-studio	 # 工程构建目录,存临时生成的文件
--|--|...
--|external					         # 引入第三方库文件的所在的文件夹
--|--|dm.dll                         # 大漠插件的dll
--|--|dm.tlh
--|--|dm.tli
--CMakeLists.txt		             # CMake脚本文件
--dmutil.cpp                         # 大漠的功能封装工具
--dmutil.h                           # 大漠的功能封装工具
--main.cpp					         # 程序入口
--mymainwindow.cpp                   # 主窗口
--mymainwindow.h                     # 主窗口
--mymainwindow.ui                    # 主窗口的UI文件
--strutils.cpp                       # 字符串工具
--strutils.h                         # 字符串工具

配置编译环境

  • 配置工具链
    • 和CMake+大漠插件的应用开发——处理dm.dll,免注册调用大漠插件中保持一致即可
  • CMakeLists.txt 文件
cmake_minimum_required(VERSION 3.27)
project(qt_dm_demo_x_01)set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /utf-8")set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)set(CMAKE_PREFIX_PATH "C:/Qt/Qt5.12.12/5.12.12/msvc2017")find_package(Qt5 COMPONENTSCoreGuiWidgetsREQUIRED)add_executable(${PROJECT_NAME} main.cppstrutils.cpp strutils.hdmutil.cpp dmutil.hmymainwindow.cpp mymainwindow.h mymainwindow.ui
)target_link_libraries(${PROJECT_NAME}Qt5::CoreQt5::GuiQt5::Widgets
)target_compile_definitions(${PROJECT_NAME} PRIVATE-DWIN32# -D_DEBUG-D_WINDOWS-D_UNICODE-DUNICODE
)message(STATUS "CMAKE_BUILD_TYPE = ${CMAKE_BUILD_TYPE}")if (WIN32 AND NOT DEFINED CMAKETOOLCHAIN_FILE)set(DEBUG_SUFFIX)if (MSVC AND CMAKE_BUILD_TYPE MATCHES "Debug")set(DEBUG_SUFFIX "d")endif ()set(QT_INSTALL_PATH "${CMAKE_PREFIX_PATH}")if (NOT EXISTS "${QT_INSTALL_PATH}/bin")set(QT_INSTALL_PATH "${QT_INSTALL_PATH}/..")if (NOT EXISTS "${QT_INSTALL_PATH}/bin")set(QT_INSTALL_PATH "${QT_INSTALL_PATH}/..")endif ()endif ()if (EXISTS "${QT_INSTALL_PATH}/plugins/platforms/qwindows${DEBUG_SUFFIX}.dll")add_custom_command(TARGET ${PROJECT_NAME} POST_BUILDCOMMAND ${CMAKE_COMMAND} -E make_directory"$<TARGET_FILE_DIR:${PROJECT_NAME}>/plugins/platforms/")add_custom_command(TARGET ${PROJECT_NAME} POST_BUILDCOMMAND ${CMAKE_COMMAND} -E copy"${QT_INSTALL_PATH}/plugins/platforms/qwindows${DEBUG_SUFFIX}.dll""$<TARGET_FILE_DIR:${PROJECT_NAME}>/plugins/platforms/")endif ()foreach (QT_LIB Core Gui Widgets)add_custom_command(TARGET ${PROJECT_NAME} POST_BUILDCOMMAND ${CMAKE_COMMAND} -E copy"${QT_INSTALL_PATH}/bin/Qt5${QT_LIB}${DEBUG_SUFFIX}.dll""$<TARGET_FILE_DIR:${PROJECT_NAME}>")endforeach (QT_LIB)
endif ()# 拷贝资源文件 dm.dll
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/external DESTINATION ${CMAKE_CURRENT_BINARY_DIR})

代码

  • dmutil.h
#ifndef DM_DEMO_X_DMUTIL_H
#define DM_DEMO_X_DMUTIL_H#include <string>
#include <vector>// #import "./external/dm.dll" no_namespace
#include "./external/dm.tlh"#define DM_LIB_PATH L"./external/dm.dll"using namespace std;struct MyWindow {long hwnd;wstring title;long processId;
};/*** 注册dm.dll,获取大漠实例* @return 大漠实例*/
Idmsoft *GetDmObject();/*** 初始化大漠插件,并注册用户VIP* @return 大漠实例*/
Idmsoft *initialDMAndRegVIP();/*** 获取匹配的窗口* @param baseVec 保存window的容器* @param pDm 大漠插件* @param title 窗口标题中的字段(模糊匹配)* @param processName 进程名称(精确匹配,不区分大小写),默认不会根据进程名筛选窗口*/
void getMatchedWindows(vector<MyWindow>& baseVec, Idmsoft *pDm, const wstring& title, const wstring& processName = L"");#endif //DM_DEMO_X_DMUTIL_H
  • dmutil.cpp(记得填入自己的 注册码附加码
#include <iostream>
#include <sstream>
#include <string_view>
#include <vector>
#include "dmutil.h"
#include "strutils.h"using namespace std;Idmsoft *GetDmObject() {Idmsoft *m_dm = nullptr;bool m_bInit = false;typedef HRESULT(_stdcall*pfnGCO)(REFCLSID, REFIID, void**);pfnGCO fnGCO = nullptr;HINSTANCE hdllInst = LoadLibrary(DM_LIB_PATH);if (hdllInst == nullptr) {cout << "Load library 'dm.dll' failed ! DM_LIB_PATH = " << DM_LIB_PATH << endl;return nullptr;}fnGCO = (pfnGCO) GetProcAddress(hdllInst, "DllGetClassObject");if (fnGCO != nullptr) {IClassFactory *pcf = nullptr;HRESULT hr = (fnGCO)(__uuidof(dmsoft), IID_IClassFactory, (void **) &pcf);if (SUCCEEDED(hr) && (pcf != nullptr)) {hr = pcf->CreateInstance(nullptr, __uuidof(Idmsoft), (void **) &m_dm);if ((SUCCEEDED(hr) && (m_dm != nullptr)) == FALSE) {cout << "Create instance 'Idmsoft' failed !" << endl;return nullptr;}}pcf->Release();m_bInit = true;}return m_dm;
}Idmsoft *initialDMAndRegVIP() {Idmsoft *pDm = GetDmObject();if (pDm == nullptr) {cout << "===> dm.dll registration failed !" << endl;return nullptr;}// 注册dm.dll成功,打印版本cout << "===> DM version: " << (char *) pDm->Ver() << endl;// 注册用户(同一程序下,只需注册一次,后续不用重复注册)long regResult = pDm->Reg(L"注册码", L"版本附加信息(附加码)");if (regResult != 1) {cout << "===> Account registration failed ! code = " << regResult << endl;return nullptr;}cout << "===> Account registration successful ! " << endl;// long releaseRes = pDm->ReleaseRef();// cout << "===> ReleaseCode = " << releaseRes << endl;return pDm;
}void getMatchedWindows(vector<MyWindow>& baseVec, Idmsoft *pDm, const wstring& title, const wstring& processName) {// 获取匹配的窗口句柄_bstr_t hwnds;if (!processName.empty()) {hwnds = pDm->EnumWindowByProcess(processName.c_str(), title.c_str(), L"", 1 + 8 + 16);} else {hwnds = pDm->EnumWindow(0, title.c_str(), L"", 1 + 4 + 8 + 16);}// 拆分找到的多个窗口句柄string content(hwnds);vector<string_view> hwndStrVec = splitSV(content, ",");// 装入容器vectorbaseVec.reserve(hwndStrVec.size());for (const string_view& element : hwndStrVec) {long curHwnd = viewToInt(element);// 获取窗口titleconst _bstr_t &curTitle = pDm->GetWindowTitle(curHwnd);// const _bstr_t &className = pDm->GetWindowClass(curHwnd);long processId = pDm->GetWindowProcessId(curHwnd);baseVec.push_back({curHwnd, {curTitle}, processId});}}
  • strutils.h
#ifndef DM_DEMO_X_STRUTILS_H
#define DM_DEMO_X_STRUTILS_H#include <string>
#include <string_view>
#include <iostream>
#include <vector>using namespace std;/*** 按分隔符拆分字符串内容为vector,string_view更加高效* @param content 待分隔的字符串* @param delim 分隔符,默认为空格* @return vector容器*/
vector<string_view> splitSV(string_view content, string_view delim = " ");/*** string_view 转 int,失败时抛出异常* @param content 字符串内容view* @return int值*/
int viewToInt(string_view content);#endif //DM_DEMO_X_STRUTILS_H
  • strutils.cpp
#include <sstream>
#include <string>
#include <vector>
#include <charconv>#include "strutils.h"vector<string_view> splitSV(string_view content, string_view delim) {vector<string_view> output;size_t first = 0;while (first < content.size()) {const auto second = content.find_first_of(delim, first);if (first != second)output.emplace_back(content.substr(first, second - first));if (second == string_view::npos)break;first = second + 1;}return output;
}int viewToInt(string_view content) {int num;auto result = std::from_chars(content.data(), content.data() + content.size(), num);if (result.ec == std::errc::invalid_argument) {throw std::runtime_error("Could not convert.");}return num;
}
  • mymainwindow.ui
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0"><class>MyMainWindow</class><widget class="QMainWindow" name="MyMainWindow"><property name="geometry"><rect><x>0</x><y>0</y><width>400</width><height>300</height></rect></property><property name="windowTitle"><string>窗口查询程序</string></property><widget class="QWidget" name="centralwidget"><layout class="QVBoxLayout" name="verticalLayout"><item><layout class="QHBoxLayout" name="horizontalLayout"><item><spacer name="horizontalSpacer"><property name="orientation"><enum>Qt::Horizontal</enum></property><property name="sizeHint" stdset="0"><size><width>40</width><height>20</height></size></property></spacer></item><item><widget class="QLabel" name="label"><property name="font"><font><weight>75</weight><bold>true</bold></font></property><property name="text"><string>窗口标题:</string></property></widget></item><item><widget class="QLineEdit" name="edtTitle"><property name="minimumSize"><size><width>200</width><height>0</height></size></property></widget></item><item><widget class="QPushButton" name="btnQuery"><property name="text"><string>模糊查询</string></property></widget></item><item><spacer name="horizontalSpacer_3"><property name="orientation"><enum>Qt::Horizontal</enum></property><property name="sizeHint" stdset="0"><size><width>40</width><height>20</height></size></property></spacer></item><item><widget class="QPushButton" name="btnCapture"><property name="text"><string>截图(选中行)</string></property></widget></item><item><spacer name="horizontalSpacer_2"><property name="orientation"><enum>Qt::Horizontal</enum></property><property name="sizeHint" stdset="0"><size><width>40</width><height>20</height></size></property></spacer></item></layout></item><item><widget class="QTableWidget" name="tableWidget"/></item></layout></widget><widget class="QMenuBar" name="menubar"><property name="geometry"><rect><x>0</x><y>0</y><width>400</width><height>21</height></rect></property><widget class="QMenu" name="menuOperation"><property name="title"><string>菜单</string></property><addaction name="actionReg"/></widget><addaction name="menuOperation"/></widget><widget class="QStatusBar" name="statusbar"/><action name="actionReg"><property name="text"><string>注册DM</string></property></action></widget><resources/><connections/>
</ui>
  • mymainwindow.h
#ifndef QT_DM_DEMO_X_MYMAINWINDOW_H
#define QT_DM_DEMO_X_MYMAINWINDOW_H#include <QMainWindow>#include "dmutil.h"QT_BEGIN_NAMESPACE
namespace Ui { class MyMainWindow; }
QT_END_NAMESPACEclass MyMainWindow : public QMainWindow {
Q_OBJECT
public:explicit MyMainWindow(QWidget *parent = nullptr);~MyMainWindow() override;public:void showInfo(const QString &message, const QString &title = "提示");void showWarn(const QString &message, const QString &title = "告警");/*** 注册大漠* @param pDm 大漠插件,待赋值*/void doRegDM(Idmsoft **pDm);/*** 查询匹配的窗口* @param pDm 大漠插件* @param title 窗口标题(模糊查询)*/void doFindWindow(Idmsoft *pDm, const QString &title);/*** 对窗口截图* @param pDm 大漠插件* @param hwnd 窗口句柄*/void doCaptureWindow(Idmsoft *pDm, long hwnd);public slots:void showMessageBox(bool result, const QString &message);void showTableView(bool result, const QString &msg, const vector<MyWindow> &windowVec);private:Ui::MyMainWindow *ui;Idmsoft *pCommonDm = nullptr;
};#endif //QT_DM_DEMO_X_MYMAINWINDOW_H
  • mymainwindow.cpp

// You may need to build the project (run Qt uic code generator) to get "ui_MyMainWindow.h" resolved#include <QFont>
#include <QHeaderView>
#include <QMessageBox>
#include <QPushButton>
#include <QAction>
#include <QString>
#include <QTableWidgetItem>
#include <QObject>
#include <QVector>
#include <iostream>
#include "mymainwindow.h"
#include "ui_MyMainWindow.h"using namespace std;MyMainWindow::MyMainWindow(QWidget *parent) :QMainWindow(parent), ui(new Ui::MyMainWindow) {ui->setupUi(this);// Init ViewssetFixedSize(1280, 720);ui->tableWidget->setColumnCount(3);ui->tableWidget->setHorizontalHeaderLabels(QStringList() << "进程ID" << "句柄" << "标题");ui->tableWidget->horizontalHeader()->setStretchLastSection(true); // 最后一列自动铺满表格// ui->tableWidget->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch);ui->tableWidget->horizontalHeader()->setHighlightSections(false);ui->tableWidget->horizontalHeader()->setStyleSheet("QHeaderView::section{background:gray;}");ui->tableWidget->setSelectionMode(QAbstractItemView::SingleSelection);QFont font = ui->tableWidget->horizontalHeader()->font();font.setBold(true);ui->tableWidget->horizontalHeader()->setFont(font);ui->tableWidget->setStyleSheet("QTableWidget::item:hover { background-color: lightblue; }");ui->tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers); // 禁止编辑ui->tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows); // 选中整行// Init Listener// 注册大漠connect(ui->actionReg, &QAction::triggered, [this]() {ui->actionReg->setEnabled(false);this->doRegDM(&this->pCommonDm);ui->actionReg->setEnabled(true);});// 查找窗口connect(ui->btnQuery, &QPushButton::clicked, [this]() {ui->btnQuery->setEnabled(false);this->doFindWindow(this->pCommonDm, ui->edtTitle->text());ui->btnQuery->setEnabled(true);});// 截图connect(ui->btnCapture, &QPushButton::clicked, [this]() {ui->btnCapture->setEnabled(false);// 获取选中行的句柄列的字段const QList<QTableWidgetItem *> &selectedItems = ui->tableWidget->selectedItems();if (selectedItems.size() >= 2) {QTableWidgetItem *item = selectedItems.at(1);const QString &hwnd = item->data(Qt::DisplayRole).toString();bool res = false;long hwndL = hwnd.toLong(&res, 0);cout << res << endl;if (res) {this->doCaptureWindow(this->pCommonDm, hwndL);} else {this->showWarn("选中行的窗口句柄解析异常!");}} else {this->showWarn("请选中列表中的其中一行!");}ui->btnCapture->setEnabled(true);});}MyMainWindow::~MyMainWindow() {delete ui;
}void MyMainWindow::showInfo(const QString &message, const QString &title) {QMessageBox::information(this, title, message);
}void MyMainWindow::showWarn(const QString &message, const QString &title) {QMessageBox::critical(this, title, message);
}void MyMainWindow::showMessageBox(const bool result, const QString& message) {if (result) {this->showInfo(message);} else {this->showWarn(message);}
}void MyMainWindow::showTableView(bool result, const QString &msg, const vector<MyWindow> &windowVec) {if (result) {auto rowNum = windowVec.size();ui->tableWidget->setRowCount(rowNum);for (int i = 0; i < rowNum; ++i) {const MyWindow &item = windowVec[i];ui->tableWidget->setItem(i, 0, new QTableWidgetItem(QString::number(item.processId)));ui->tableWidget->setItem(i, 1, new QTableWidgetItem(QString::number(item.hwnd)));ui->tableWidget->setItem(i, 2, new QTableWidgetItem(QString::fromStdWString(item.title)));}} else {this->showWarn(msg);}
}void MyMainWindow::doRegDM(Idmsoft **pDm) {cout << "========== Initial DM ............ ==========" << endl;*pDm = initialDMAndRegVIP();if (*pDm == nullptr) {cout << "========== Initial DM <Failed>     ==========" << endl;showMessageBox(false, "DM 注册失败!");return;}cout << "========== Initial DM <Successful> ==========" << endl;cout << endl;showMessageBox(true, "DM 注册完成!");
}void MyMainWindow::doFindWindow(Idmsoft *pDm, const QString &title) {vector<MyWindow> windowVec;if (pDm == nullptr) {cout << "this->pCommonDm == nullptr" << endl;this->showTableView(false, "请先在菜单中完成注册!", windowVec);return;}// 找一下title包含findStr的窗口,并打印信息getMatchedWindows(windowVec, pDm, title.toStdWString());if (windowVec.empty()) {cout << "can not find such window" << endl;this->showTableView(false, "没有找到包含该标题的窗口!", windowVec);return;}this->showTableView(true, "成功!", windowVec);
}void MyMainWindow::doCaptureWindow(Idmsoft *pDm, long hwnd) {if (pDm == nullptr) {cout << "this->pCommonDm == nullptr" << endl;this->showMessageBox(false, "请先在菜单中完成注册!");return;}// 绑定窗口句柄long dmBind = pDm->BindWindowEx(hwnd,"normal","normal","normal","",0);if (dmBind == 1) {// 恢复并激活指定窗口,置顶窗口,pDm->SetWindowState(hwnd, 12);pDm->SetWindowState(hwnd, 8);pDm->delay(600);// 延迟一下截图,存到相对路径wstring filename = wstring(L"./capture_window_").append(std::to_wstring(hwnd)).append(L".bmp");long retCap = pDm->Capture(0, 0, 2000, 2000, filename.c_str());if (retCap != 1) {cout << "capture failed" << endl;this->showMessageBox(false, "截图失败!");} else {cout << "capture success" << endl;this->showMessageBox(true, QString::fromStdWString(L"截图成功,保存地址为: " + filename));}// 取消置顶窗口pDm->SetWindowState(hwnd, 9);} else {cout << "DM BindWindow failed" << endl;this->showMessageBox(false, "绑定窗口异常!");}pDm->UnBindWindow();
}
  • main.cpp
#include <QApplication>
#include <iostream>
#include "mymainwindow.h"
using namespace std;int main(int argc, char *argv[]) {setlocale(LC_ALL, "chs");QApplication a(argc, argv);MyMainWindow mainWindow;mainWindow.show();return QApplication::exec();
}

相关文章:

CMake+QT+大漠插件的桌面应用开发

文章目录 CMakeQT大漠插件的桌面应用开发说明环境项目结构配置编译环境代码 CMakeQT大漠插件的桌面应用开发 说明 在CMake大漠插件的应用开发——处理dm.dll&#xff0c;免注册调用大漠插件中已经说明了如何免注册调用大漠插件&#xff0c;以及做了几个简单的功能调用&#x…...

OpenCV-24双边滤波

一、概念 双边滤波对于图像的边缘信息能够更好的保存。其原理为一个与空间距离相关的高斯函数与一个灰度距离相关的高斯函数相乘。 空间距离&#xff1a;指的是当前点与中心点的欧式距离。空间域的高斯函数及其数学形式为&#xff1a; 其中&#xff08;xi&#xff0c;yi&…...

AI智能分析网关V4:太阳能+4G智慧水库远程可视化智能监管方案

一、背景需求分析 由于水库位置分散的原因&#xff0c;水库视频监控建设在立杆、布线等方面都存在一定的难度&#xff0c;且需要人力、物力的前期投入和后期维护。目前水库的监管存在一定的问题&#xff0c;管理人员工作强度大但管理质量并不高&#xff0c;人为巡检无法实时发…...

第8章-第8节-Java中的文件类File的简单介绍

1、我们已经写过File的相关代码&#xff1a; BufferedReader bf new BufferedReader(new FileReader(new File("aa.txt"))); 2、其实FIle这个类自身也是非常强大的&#xff0c;封装了很多操作文件/目录的方法&#xff0c;今天我们就需要去详细的学习这个类&#x…...

CTF-PWN-沙箱逃脱-【seccomp和prtcl-2】

文章目录 沙箱逃脱prtcl题HITCON CTF 2017 Quals Impeccable Artifact libc 2.24flag文件对应prctl函数检查源码思路exp 沙箱逃脱prtcl题 HITCON CTF 2017 Quals Impeccable Artifact libc 2.24 flag文件 此时的flag文件在本文件夹建一个即可 此时的我设置的flag为 对应prc…...

【Docker篇】使用Docker操作镜像

文章目录 &#x1f6f8;镜像&#x1f33a;基本操作⭐docker --help⭐docker pull [ 参数 ]⭐docker images⭐docker save -- 导出⭐docker rmi -- 删除⭐docker load -- 导入 &#x1f6f8;镜像 镜像是指在计算机领域中&#xff0c;通过复制和创建一个与原始对象相似的副本的过…...

css宽度适应内容

废话不多说,看如下demo,我需要将下面这个盒子的宽度变成内容自适应 方法有很多,如下 父元素设置display:flex 实现子元素宽度适应内容 如下给父元素设置flex能实现宽度自适应内容 <!DOCTYPE html><html lang"en"><head><meta charset"U…...

粒子物理和原子核物理的理论在模拟和分析电路中的粒子束和辐射效应中的应用

粒子物理和原子核物理的理论可以应用于模拟和分析电路中的粒子束和辐射效应&#xff0c;特别是在粒子加速器和辐射探测器的设计和优化方面。通过这些理论的应用&#xff0c;可以提高加速器和探测器的性能&#xff0c;推动粒子物理和原子核物理的研究进展。粒子物理和原子核物理…...

Opentsdb官方优化文档 - 翻译

文档地址 : Tuning — OpenTSDB 2.4 documentation Tuning As with any database there are many tuning parameters for OpenTSDB that can be used to improve write and read performance. Some of these options are specific to certain backends, others are global. …...

JavaScript深拷贝与浅拷贝的全面解析

&#x1f9d1;‍&#x1f393; 个人主页&#xff1a;《爱蹦跶的大A阿》 &#x1f525;当前正在更新专栏&#xff1a;《VUE》 、《JavaScript保姆级教程》、《krpano》 ​ ​ 目录 ✨ 前言 ✨ 正文 浅拷贝 对象的浅拷贝 数组的浅拷贝 浅拷贝的问题 深拷贝 什么是深拷贝…...

ESU毅速丨制造企业需不需要建设增材制造中心?

随着科技的不断发展&#xff0c;增材制造技术已经成为制造行业的新宠。越来越多的企业开始考虑建设增材制造中心&#xff0c;以提高生产效率、降低成本、加速产品创新。但是&#xff0c;对于制造企业来说&#xff0c;是否需要建设增材制造中心呢&#xff1f; 首先&#xff0c;我…...

Linux shell编程学习笔记39:df命令

0 前言1 df命令的功能、格式和选项说明 1.1 df命令的功能1.2 df命令的格式1.3 df命令选项说明 2 df命令使用实例 2.1 df&#xff1a;显示主要文件系统信息2.2 df -a&#xff1a;显示所有文件系统信息2.3 df -t[]TYPE或--type[]TYPE&#xff1a;显示TYPE指定类型的文件系统信…...

简单高效 LaTeX 科学排版 第004集 命令与环境

这是《简单高效LaTeX》的第四个视频&#xff0c;主要演示讨论基本命令与排版环境&#xff0c;还有保留字符。 视频地址&#xff1a;https://www.ixigua.com/7298100920137548288?id7298102807985390120&logTagf853f23a668f8a2ee405...

初识XSS漏洞

目录 一、XSS的原理和分类 二、Xss漏洞分类 1. 反射性xss 简单的演示&#xff1a; 2.基于DOM的XSS 简单的演示&#xff1a; 3.存储型XSS ​编辑简单的演示 4、self xss 三、XSS漏洞的危害 四、XSS漏洞的验证 五、XSS漏洞的黑盒测试 六、XSS漏洞的白盒测试 七、XS…...

白嫖aws创建Joplin server服务器

网上有很多的Joplin服务器的搭建教程&#xff0c;但是基本都是抄来抄去&#xff0c;对初学者实在是太不友好了。 话不多说&#xff0c;说干就干&#xff0c;自己从头找资料搭了一个&#xff0c;这可能是全网最好的Joplin服务器搭建教程了。 aws服务器 aws的服务器还是很香的&…...

metartc5_jz源码阅读-p2p通过stun服务器进行通信

1. YangIpc.c/yang_create_ipc 需要设置stun服务器的ip地址和端口号 设置iceCandidateType为2&#xff0c;表示走stun&#xff0c;即向stun服务器发起请求获取本机的公网ip地址。 //设置iceServerIP和端口号&#xff0c;设置iceCandidate类型。 strcpy(session->avinfo.rtc…...

总结:Java程序员读书清单顺序

总结&#xff1a;Java程序员读书清单顺序&#xff0c;持续更新中。。。。。。 一经验提示&#xff1a;1.零基础不建议直接看计算机专业书籍&#xff0c;建议先去看视频教程2.本书单目录用作自学顺序记录&#xff0c;也适用于有Java开发基础的同志3.看计算机书籍可以完善自己的技…...

ubuntu通过virtualbox安装win虚拟机

系统&#xff1a;Ubuntu22.04 需要准备&#xff1a;下载你想用的windows的iso镜像&#xff0c;官方传送门。 一、安装virtualbox sudo apt-get install virtualbox安装完成后&#xff0c;打开Applications&#xff0c;找到virtualbox&#xff0c;点击启动 二、安装windows虚…...

云流量回溯的工作原理及关键功能

云计算和网络技术的快速发展为企业提供了更灵活、高效的业务运营环境&#xff0c;同时也引发了一系列网络安全挑战。在这个背景下&#xff0c;云流量回溯成为网络安全领域的一个关键技术&#xff0c;为企业提供了对网络活动的深入洞察和实时响应的能力。 一、 云流量回溯的基本…...

DCP文件传输的重要性与应用

在数字时代&#xff0c;文件传输已成为商业运作中不可或缺的一环。随着企业越来越多地采用云基础设施和服务&#xff0c;有效地在云和团队之间传输大文件和数据集变得至关重要。在这一背景下&#xff0c;数据复制协议&#xff08;DCP&#xff09;文件传输应运而生&#xff0c;引…...

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…...

多模态2025:技术路线“神仙打架”,视频生成冲上云霄

文&#xff5c;魏琳华 编&#xff5c;王一粟 一场大会&#xff0c;聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中&#xff0c;汇集了学界、创业公司和大厂等三方的热门选手&#xff0c;关于多模态的集中讨论达到了前所未有的热度。其中&#xff0c;…...

【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密

在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...

解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八

现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet&#xff0c;点击确认后如下提示 最终上报fail 解决方法 内核升级导致&#xff0c;需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...

基于服务器使用 apt 安装、配置 Nginx

&#x1f9fe; 一、查看可安装的 Nginx 版本 首先&#xff0c;你可以运行以下命令查看可用版本&#xff1a; apt-cache madison nginx-core输出示例&#xff1a; nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...

django filter 统计数量 按属性去重

在Django中&#xff0c;如果你想要根据某个属性对查询集进行去重并统计数量&#xff0c;你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求&#xff1a; 方法1&#xff1a;使用annotate()和Count 假设你有一个模型Item&#xff0c;并且你想…...

376. Wiggle Subsequence

376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...

vue3 字体颜色设置的多种方式

在Vue 3中设置字体颜色可以通过多种方式实现&#xff0c;这取决于你是想在组件内部直接设置&#xff0c;还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法&#xff1a; 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...

Nginx server_name 配置说明

Nginx 是一个高性能的反向代理和负载均衡服务器&#xff0c;其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机&#xff08;Virtual Host&#xff09;。 1. 简介 Nginx 使用 server_name 指令来确定…...

高防服务器能够抵御哪些网络攻击呢?

高防服务器作为一种有着高度防御能力的服务器&#xff0c;可以帮助网站应对分布式拒绝服务攻击&#xff0c;有效识别和清理一些恶意的网络流量&#xff0c;为用户提供安全且稳定的网络环境&#xff0c;那么&#xff0c;高防服务器一般都可以抵御哪些网络攻击呢&#xff1f;下面…...