使用Qt封装C/C++ 动态库 用于第三方调用

具体程序如下:(贴得都是修改后得,用的是回调得方式获取到数据)

封装DLL库:需要注意: pro文件中不能包含任何Qt得库

然后修改文件global文件

复制代码
#ifndef EAGLE_RF_NOVASKY_Q5M_GLOBAL_H
#define EAGLE_RF_NOVASKY_Q5M_GLOBAL_H

#if defined(EAGLE_RF_NOVASKY_Q5MSHARED_EXPORT)
#  define EAGLE_RF_NOVASKY_Q5MSHARED_EXPORT __declspec(dllexport)
#else
#  define EAGLE_RF_NOVASKY_Q5MSHARED_EXPORT __declspec(dllimport)
#endif

#endif // EAGLE_RF_NOVASKY_Q5M_GLOBAL_H

h文件(对外得h文件,需要注意内外函数得对应)

复制代码
#ifndef EAGLE_RF_NOVASKY_Q5M_H
#define EAGLE_RF_NOVASKY_Q5M_H

#include "eagle_rf_novasky_q5m_global.h"

#ifdef __cplusplus
extern "C" {
#endif

// 不透明句柄
typedef void* eagle_rf_handle_t;

// 创建 / 销毁
EAGLE_RF_NOVASKY_Q5MSHARED_EXPORT eagle_rf_handle_t eagle_rf_create(void);
EAGLE_RF_NOVASKY_Q5MSHARED_EXPORT void eagle_rf_destroy(eagle_rf_handle_t h);

// 连接设备,成功返回 1,失败返回 0
EAGLE_RF_NOVASKY_Q5MSHARED_EXPORT int eagle_rf_init(eagle_rf_handle_t h,
                                                         const char* ip,
                                                         int port);
// 断开设备
EAGLE_RF_NOVASKY_Q5MSHARED_EXPORT void eagle_rf_deinit(eagle_rf_handle_t h);


// 收到数据解析后返回json
typedef void (*eagle_rf_json_cb)(void* user_data, const char* json);

typedef struct {
    eagle_rf_json_cb on_json;   // 每帧一个 JSON
    void*            user_data; // 原样回传
} eagle_rf_callbacks_t;

EAGLE_RF_NOVASKY_Q5MSHARED_EXPORT void eagle_rf_set_callbacks(
        eagle_rf_handle_t h, const eagle_rf_callbacks_t* cbs);

#ifdef __cplusplus
}
#endif

#endif // EAGLE_RF_NOVASKY_Q5M_H

cpp文件

复制代码
#define EAGLE_RF_NOVASKY_Q5M_LIBRARY
#include "eagle_rf_novasky_q5m.h"
#include "eagle_rf_novasky_q5m_impl.h"

#include <new>

extern "C" eagle_rf_handle_t eagle_rf_create()
{
    return new (std::nothrow) Eagle_rf_novasky_q5m();
}

extern "C" void eagle_rf_destroy(eagle_rf_handle_t h)
{
    delete static_cast<Eagle_rf_novasky_q5m*>(h);
}

extern "C" int eagle_rf_init(eagle_rf_handle_t h, const char *ip, int port)
{
    if (!h || !ip) return 0;
    return static_cast<Eagle_rf_novasky_q5m*>(h)->init(std::string(ip), port) ? 1 : 0;
}

extern "C" void eagle_rf_deinit(eagle_rf_handle_t h)
{
    if (h) static_cast<Eagle_rf_novasky_q5m*>(h)->deinit();
}

extern "C" void eagle_rf_set_callbacks(eagle_rf_handle_t h, const eagle_rf_callbacks_t *cbs)
{
    if (!h || !cbs) return;
    static_cast<Eagle_rf_novasky_q5m*>(h)->setCallbacks(*cbs);
}

h文件(内部实现函数得文件)

复制代码
#ifndef EAGLE_RF_NOVASKY_Q5M_IMPL_H
#define EAGLE_RF_NOVASKY_Q5M_IMPL_H

#include "eagle_rf_novasky_q5m.h"

#include <string>
#include <mutex>

class Eagle_rf_novasky_q5m
{
public:
    Eagle_rf_novasky_q5m();
    ~Eagle_rf_novasky_q5m();


    ///
    /// \brief init  连接设备
    /// \param ip   设备ip地址
    /// \param port 设备端口号
    /// \return true-连接成功 false-连接失败
    ///
    bool init(std::string ip, int port);

    ///
    /// \brief deinit 断连设备
    ///
    void deinit();

    // 回调注册
    void setCallbacks(const eagle_rf_callbacks_t& cbs);

private:
    eagle_rf_callbacks_t m_cbs{};
    mutable std::mutex m_cbMutex;
};

#endif // EAGLE_RF_NOVASKY_Q5M_IMPL_H

cpp文件

复制代码
#include "eagle_rf_novasky_q5m_impl.h"

Eagle_rf_novasky_q5m::Eagle_rf_novasky_q5m()
{

}

Eagle_rf_novasky_q5m::~Eagle_rf_novasky_q5m()
{

}

bool Eagle_rf_novasky_q5m::init(std::string ip, int port)
{
    return true;
}

void Eagle_rf_novasky_q5m::deinit()
{

}

void Eagle_rf_novasky_q5m::setCallbacks(const eagle_rf_callbacks_t &cbs)
{
    std::lock_guard<std::mutex> lock(m_cbMutex);
    m_cbs = cbs;
}

具体使用方法:需要将生成得dll文件放到生成得执行文件同级目录中

h文件

复制代码
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

#include "eagle_rf_novasky_q5m.h"

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = nullptr);
    ~Widget();

private slots:
    // 主线程槽:接收 DLL 推来的 JSON
    void onJsonFrame(const QString& json);

    void on_pushButton_1_clicked();

private:
    Ui::Widget *ui;

    // 静态回调,签名必须和 detect_rf_json_cb 一致
    static void cbJson(void* user_data, const char* json);

    eagle_rf_handle_t m_handle;

    bool m_connect;
};

#endif // WIDGET_H

cpp文件

复制代码
#include "widget.h"
#include "ui_widget.h"

#include <QDebug>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonValue>
#include <QMetaObject>

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);

    m_connect = false;

    // 创建 DLL 内部对象
    m_handle = eagle_rf_create();
    if (!m_handle) {
        qDebug() << "eagle_rf_create failed";
    }

    // 注册回调
    eagle_rf_callbacks_t cbs{};
    cbs.on_json   = &Widget::cbJson;   // 函数指针
    cbs.user_data = this;              // 把 this 传给回调
    eagle_rf_set_callbacks(m_handle, &cbs);
}

Widget::~Widget()
{
    if (m_handle) {
        // 先清掉回调,避免 DLL 析构过程中还有数据回调到已销毁的 Widget
        eagle_rf_callbacks_t empty{};
        eagle_rf_set_callbacks(m_handle, &empty);

        eagle_rf_deinit(m_handle);
        eagle_rf_destroy(m_handle);
        m_handle = nullptr;
    }

    delete ui;
}

void Widget::onJsonFrame(const QString &json)
{
    QJsonParseError err{};
    QJsonDocument doc = QJsonDocument::fromJson(json.toUtf8(), &err);
    if (err.error != QJsonParseError::NoError || !doc.isObject()) {
        qDebug() << "json parse error:" << err.errorString() << json;
        return;
    }

    qDebug()<<json;
}

void Widget::cbJson(void *user_data, const char *json)
{
    Widget* self = static_cast<Widget*>(user_data);
    if (!self || !json) return;

    // 立即拷贝成 QString(json 指针在回调返回后失效)
    QString s = QString::fromUtf8(json);

    // 切回主线程,异步调用 onJsonFrame
    QMetaObject::invokeMethod(self, "onJsonFrame", Qt::QueuedConnection,
                              Q_ARG(QString, s));
}

void Widget::on_pushButton_1_clicked()
{
    static int m_click = 0;

    if (!m_handle) {
        qDebug() << "handle is null";
        return;
    }

    if (((m_click++) % 2) == 0) {
        // ---- 连接 ----
        QString ip = ui->lineEdit_1->text().trimmed();
        int port = ui->lineEdit_2->text().toInt();

        int ok = eagle_rf_init(m_handle, ip.toUtf8().constData(), port);
        m_connect = (ok != 0);
        qDebug() << "init result:" << m_connect;

        if (m_connect) {
            ui->pushButton_1->setText(QStringLiteral("关闭"));
        } else {
            ui->pushButton_1->setText(QStringLiteral("开启"));
        }
    } else {
        // ---- 断开 ----
        eagle_rf_deinit(m_handle);
        m_connect = false;
        ui->pushButton_1->setText(QStringLiteral("开启"));
    }
}

执行文件界面

相关推荐
syagain_zsx1 小时前
ODB 与 MySQL:C++ 里的 ORM 实践(类即表、事务铁律与查询封装)
开发语言·数据库·c++·mysql·工具库·1024程序员节
晚风予卿云月2 小时前
【C++高并发内存池】 1.定长内存池的实现
开发语言·c++·内存管理
闻缺陷则喜何志丹3 小时前
【c++20】协程与屏障
c++·算法·c++20·携程·屏障
会编程的小孩3 小时前
C++ 内存分区、堆与栈、static、union 完整修正版文档
c++
多弗朗皮卡丘3 小时前
C++的类型转换
开发语言·c++
扶尔魔ocy3 小时前
【QT OpenGL】知识点编目及传送门
qt·opengl·osg
FLJwu4 小时前
运动相机图像传感器选型实战|第二篇:参数看着一模一样,为什么骑行录像疯狂果冻、拖影翻车?
android·c语言·开发语言·数码相机·运动相机·oem 量产
Escalating_xu4 小时前
【C语言项目实战】贪吃蛇(下):移动、碰撞与计分,完成一局可玩的游戏
c语言·开发语言·游戏
火2254 小时前
# C++ 微服务即时通讯系统(三):网关设计——HTTP 请求、Session 鉴权与 WebSocket 通知上一篇
c++·http·微服务