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

news2025/4/25 16:36:59

文章目录

  • 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 COMPONENTS
        Core
        Gui
        Widgets
        REQUIRED)

add_executable(${PROJECT_NAME} main.cpp
        strutils.cpp strutils.h
        dmutil.cpp dmutil.h
        mymainwindow.cpp mymainwindow.h mymainwindow.ui
)

target_link_libraries(${PROJECT_NAME}
        Qt5::Core
        Qt5::Gui
        Qt5::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_BUILD
                COMMAND ${CMAKE_COMMAND} -E make_directory
                "$<TARGET_FILE_DIR:${PROJECT_NAME}>/plugins/platforms/")
        add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
                COMMAND ${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_BUILD
                COMMAND ${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, ",");

    // 装入容器vector
    baseVec.reserve(hwndStrVec.size());
    for (const string_view& element : hwndStrVec) {
        long curHwnd = viewToInt(element);
        // 获取窗口title
        const _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_NAMESPACE

class 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 Views
    setFixedSize(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();
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1382108.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

响应式Web开发项目教程(HTML5+CSS3+Bootstrap)第2版 第1章 HTML5+CSS3初体验 项目1-1 三栏布局页面

项目展示 三栏布局是一种常用的网页布局结构。 除了头部区域、底部区域外&#xff0c;中间的区域&#xff08;主体区域&#xff09;划分成了三个栏目&#xff0c;分别是左侧边栏、内容区域和右侧边栏&#xff0c;这三个栏目就构成了三栏布局。当浏览器的宽度发声变化时&#x…

最全对象存储(云盘)挂载本地主机或服务器

1.对象存储介绍 1.1 分类 分布式存储的应用场景相对于其存储接口&#xff0c;现在流行分为三种: 块存储: 这种接口通常以QEMU Driver或者Kernel Module的方式存在&#xff0c;这种接口需要实现Linux的Block Device的接口或者QEMU提供的Block Driver接口&#xff0c;块存储一般…

androidkiller的两种异常情况

第一种反编译时异常&#xff1a; Exception in thread “main” org.jf.dexlib2.dexbacked.DexBackedDexFile$NotADexFile: Not a valid dex magic value: cf 77 4c c7 9b 21 01 修改方法&#xff1a; 编辑 AndroidKiller 的 bin/apktool 目录下有一个 apktool.bat 文件 修改成…

nmealib 库移植 - -编译报错不完全类型 error: field ‘st_atim’ has incomplete type

一、报错提示-不完全类型(has incomplete type) Compiling obj/main.o from main.c.. arm-linux-gcc -g -w -stdgnu99 -DLINUX -I./ -Inmealib/inc/ -c -o obj/main.o main.c In file included from /home/user/Desktop/nuc980-sdk/sdk/arm_linux_4.8/usr/include/sys/stat…

豆包ai介绍

豆包是字节跳动基于云雀模型开发的AI工具&#xff0c;具有强大的语言处理能力和广泛的应用场景&#xff0c;无论是在学习、工作、生活中&#xff0c;都能派上用场。 豆包可以帮助打工人和创作者提升效率&#xff0c;完成各种工作任务&#xff0c;又能扮演各类AI角色进行高情商…

2003-2021年地级市知识产权保护水平数据

2003-2021年地级市知识产权保护水平数据 1、时间&#xff1a;2003-2021年 2、指标&#xff1a;city、year、地方知识产权审判结案数、地方GDP、国内知识产权审判结案数、国内GDP、知识产权保护水平 3、来源&#xff1a;北大法宝、城市年鉴、统计年鉴、历年知识产权保护状况白…

SpringMVC(六)RESTful

1.RESTful简介 REST:Representational State Transfer,表现层资源状态转移 (1)资源 资源是一种看待服务器的方式,即,将服务器看作是由很多离散的资源组成。每个资源是服务器上一个可命名的抽象概念。因为资源是一个抽象的概念,所以它不仅仅能代表服务器文件系统中的一个文件…

场效应管在电路中如何控制电流大小

场效应管的概念 场效应晶体管&#xff08;FieldEffectTransistor缩写&#xff08;FET&#xff09;&#xff09;简称场效应管。主要有两种类型&#xff08;juncTIonFET—JFET&#xff09;和金属-氧化物半导体场效应管&#xff08;metal-oxidesemiconductorFET&#xff0c;简称M…

Linux完全卸载Anaconda3和MiniConda3

如何安装Anaconda3和MiniConda3请看这篇文章&#xff1a; 安装Anaconda3和MiniConda3_minianaconda3-CSDN博客文章浏览阅读474次。MiniConda3官方版是一款优秀的Python环境管理软件。MiniConda3最新版只包含conda及其依赖项如果您更愿意拥有conda以及超过720个开源软件包&…

关联规则分析(Apriori算法2

目录 1.核心术语&#xff1a;2.强关联规则&#xff1a;小结&#xff1a; 1.核心术语&#xff1a; 支持度&#xff08;Support&#xff09;&#xff1a;指项集出现的频繁程度&#xff08;相当于项集出现的概率&#xff09; 最小支持度有绝对值和占比两种表示方式 置信度&#…

一个月带你手撕LLM理论与实践,并获得面试or学术指导!

大家好&#xff0c;我是zenRRan&#xff0c;是本号的小号主。 从该公众号的名字就能看出&#xff0c;运营已经好多年了&#xff0c;这些年当中直接或间接帮助很多同学从NLP入门到进阶&#xff0c;理论到实践&#xff0c;学校到企业&#xff0c;本科到硕士甚至博士。 每天习惯性…

buuctf-Misc 题目解答分解115-117

115.派大星的烦恼 解压下载文件时一个 bmp 文件&#xff0c;用notepad 打开有没有发现什么 &#xff0c;提示位图什么的 用Stegsolve.jar 打开 发现很多. 和- 第一时间想到了 电报码 但提示不是电报码&#xff0c;除了这个那就是很像二进制了 0,1 什么的&#xff0c;但这个感觉…

Vue中v-if与v-show区别详解

✨ 专栏介绍 在当今Web开发领域中&#xff0c;构建交互性强、可复用且易于维护的用户界面是至关重要的。而Vue.js作为一款现代化且流行的JavaScript框架&#xff0c;正是为了满足这些需求而诞生。它采用了MVVM架构模式&#xff0c;并通过数据驱动和组件化的方式&#xff0c;使…

ElasticSearch分布式搜索引擎(两万字详解)

文章目录 ElasticSearch分布式搜索引擎1.了解ESELK技术栈elasticsearch和lucene为什么不是其他搜索技术&#xff1f;总结倒排索引正向索引倒排索引正向和倒排 es的一些概念文档和字段索引和映射mysql与elasticsearch 2.安装elasticsearch1.部署单点es1.1.创建网络1.2.拉取镜像1…

运用AI搭建中间服务层(五)

其他文件的修改 ValuesControllers.cs 注意Post的参数从[FromBody]变成了[FromForm]&#xff0c;以便接收上传的图片流数据 using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading.Tasks; using CognitiveMi…

SFP/SFP+/QSFP/QSFP+光模块和GTP/GTX/GTH/GTZ/GTY/GTM高速收发器

SFP/SFP/QSFP/QSFP光模块和GTP/GTX/GTH/GTZ/GTY/GTM高速收发器 SFP/SFP/QSFP/QSFP光模块概述SFPSFPQSFPQSFP关键参数说明 GTP/GTX/GTH/GTZ/GTY/GTM高速收发器区别XILINX 7系列FPGA中高速收发器使用 SFP/SFP/QSFP/QSFP光模块 概述 SFP&#xff08; small form-factor pluggabl…

小程序基础学习(多插槽)

先创建插槽 定义多插槽的每一个插槽的属性 在js文件中启用多插槽 在页面使用多插槽 组件代码 <!--components/my-slots/my-slots.wxml--><view class"container"><view class"left"> <slot name"left" ></slot>&…

人声处理用什么软件好 FL Studio 怎么修人声 人声处理软件 人声处理步骤

一、人声处理用什么软件好 现在人声处理软件还是非常多的&#xff0c;有专门的人声处理软件&#xff0c;也有具备人声处理功能的编曲软件。专门人声处理的软件操作比较简单&#xff0c;但是处理后的人声在使用的时候可能还需要进行再处理&#xff0c;这会比较麻烦。具备人声处…

nacos配置中心只能获取部分配置的问题

检查配置中心&#xff0c;在配置中心里是可以看到监听的服务地址的&#xff0c;但是却获取不到配置 nacos配置中心主要是在这个NacosConfigService的这个类下面。该接口下面主要有一些获取配置&#xff0c;发布配置&#xff0c;增加监听器&#xff0c;删除配置&#xff0c;删…

迅腾文化用网络集成化生态系统助力品牌之路的坚实后盾

商业竞争激烈&#xff0c;品牌不仅是企业的标志和形象&#xff0c;更是其核心价值和竞争力的体现。然而&#xff0c;企业在品牌推广过程中面临着诸多如缺乏有效的渠道管理、品牌形象模糊以及竞争激烈的市场环境等。这些阻碍着企业的品牌发展和市场占有率的提升。本文将通过企业…