Qt设置软件的使用期限

作者:billy
版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处

前言

当我们发布商业软件时,为了获取更多的盈利,我们会设置用户使用软件的期限。比如我们给到用户的软件试用期是3个月,过期之后就无法使用了,需要向销售方支付费用,开发者给与授权之后才能继续使用。

对于软件开发者,就博主个人而言,我是非常乐意做这种事情的。博主整理了自己项目中使用的方法,在这里分享一下,也方便自己后期回顾。

功能预览

在这里插入图片描述

操作流程

  1. 获取设备信息(网卡地址、硬盘序列号、主板序列号、处理器ID、BIOS序列号、CPUID等)
  2. 选择使用期限
  3. 根据设备信息、使用期限、当前日期生成唯一的 key
  4. 把key和所需信息写入注册表
  5. 运行程序读取注册表检测是否过期,并更新日期

封装的类 BMachineControl

#include <QString>
#include <QAxObject>
#include <QDebug>
#include <QUuid>
#include <QNetworkInterface>
#include <QCryptographicHash>
#include <QDateTime>
#include <QSettings>
#include <QFile>
#include <QFileInfo>
#include <QDir>
#include <QDataStream>
#include <QList>
#include <Windows.h>

class BMachineControl
{
public:
    BMachineControl();

    QString getWMIHWInfo(int type);

    QString getCPUID1();

    QString getCPUID2();

    QString getHDLogicalID();

    QString getMac();

    QString getCPUManID();

    QString getInfo();

    // 根据设备信息、日期、可使用月份生成key
    QString getKey(QString machineinfo, QString ddMMyyyy, int months);

    // 注册key
    bool activeKey(QString key);

    // 拷贝至文件
    void copyToFile(QSettings* reg, bool magic = false);

    // 无注册表信息则初始化并返回true, 否则直接返回false
    bool initializeReg();

    // 比较是否与文件一致
    bool judgeFile();

    // 判断日期是否被故意修改
    bool judgeDate();

    // 判断key,返回剩余天数,过期则为负
    int judgeKey();

    // 刷新 DT1
    void refreshDT1();

private:
    const QString kReg = "HKEY_CURRENT_USER\\Software\\Lenovo\\App";
    const QString kKey = "K";
    const QString kDateTime0 = "DT0";
    const QString kDateTime1 = "DT1";
    const QString kDateTime2 = "DT2";
    const QString kMonths = "M";

    const int kForever = 1000000;
    const QList<int> kValidity = {1, 3, 6, 12, kForever};

    const QString kFile = "C:/ProgramData/Lenovo/app.dat";
};

获取设备信息

这里用到了 QAxObject 和 QNetworkInterface,记得在pro中导入Qt模块
QT += network axcontainer

QString BMachineControl::getWMIHWInfo(int type)
{
    /*
     * 注意:qt调用wmi时,对查询语句要求很严格,所以like之类的句子务必精确才能有结果出来
     *
     * 1. 当前原生网卡地址
     *    SELECT MACAddress ...
     *
     * 2. 硬盘序列号
     *    SELECT PNPDeviceID ...
     *
     * 3. 获取主板序列号
     *    SELECT SerialNumber ...
     *
     * 4. 处理器ID
     *    SELECT ProcessorId ...
     *
     * 5. BIOS序列号
     *    SELECT SerialNumber ...
     *
     * 6. 主板型号
     *    SELECT Product ...
     */

    QString hwInfo;
    QStringList sqlCmd;
    sqlCmd.clear();
    sqlCmd << "SELECT MACAddress FROM Win32_NetworkAdapter WHERE (MACAddress IS NOT NULL) AND (NOT (PNPDeviceID LIKE 'ROOT%'))";
    sqlCmd << "SELECT PNPDeviceID FROM Win32_DiskDrive WHERE( PNPDeviceID IS NOT NULL) AND (MediaType LIKE 'Fixed%')";
    sqlCmd << "SELECT SerialNumber FROM Win32_BaseBoard WHERE (SerialNumber IS NOT NULL)";
    sqlCmd << "SELECT ProcessorId FROM Win32_Processor WHERE (ProcessorId IS NOT NULL)";
    sqlCmd << "SELECT SerialNumber FROM Win32_BIOS WHERE (SerialNumber IS NOT NULL)";
    sqlCmd << "SELECT Product FROM Win32_BaseBoard WHERE (Product IS NOT NULL)";

    QStringList columnName;
    columnName.clear();
    columnName << "MACAddress";
    columnName << "PNPDeviceID";
    columnName << "SerialNumber";
    columnName << "ProcessorId";
    columnName << "SerialNumber";
    columnName << "Product";

    QAxObject *objIWbemLocator = new QAxObject("WbemScripting.SWbemLocator");
    QAxObject *objWMIService = objIWbemLocator->querySubObject("ConnectServer(QString&,QString&)",QString("."), QString("root\\cimv2"));
    QString query;
    if ( type < sqlCmd.size() ) {
        query = sqlCmd.at(type);
    }

    QAxObject *objInterList = objWMIService->querySubObject("ExecQuery(QString&))", query);
    QAxObject *enum1 = objInterList->querySubObject("_NewEnum");

    IEnumVARIANT *enumInterface = 0;
    enum1->queryInterface(IID_IEnumVARIANT, (void**)&enumInterface);
    enumInterface->Reset();

    for ( int i = 0; i < objInterList->dynamicCall("Count").toInt(); ++i )
    {
        VARIANT *theItem = (VARIANT*)malloc(sizeof(VARIANT));
        if ( enumInterface->Next(1, theItem, NULL) != S_FALSE )
        {
            QAxObject *item = new QAxObject((IUnknown *)theItem->punkVal);
            if (item) {
                if ( type<columnName.size() ) {
                    QByteArray datagram(columnName.at(type).toLatin1());
                    const char* tempConstChar = datagram.data();
                    hwInfo=item->dynamicCall(tempConstChar).toString();
                }
            }
        }
    }

    return hwInfo;
}

生成key

QString BMachineControl::getKey(QString machineinfo, QString ddMMyyyy, int months)
{
    QString originalStr120;
    if ( machineinfo.isEmpty() ) {
        originalStr120 = QString("machineinfo") + ddMMyyyy + QString::number(months);
    } else {
        originalStr120 = machineinfo + ddMMyyyy + QString::number(months);
    }
    QCryptographicHash sha1(QCryptographicHash::Sha1);

    QByteArray datagram(originalStr120.toLatin1());

    for ( int i = 0; i != datagram.size(); ++i )
    {
        datagram[i] = datagram[i] ^ 'q' ^ 'y';
    }

    const char* tempConstChar = datagram.data();
    sha1.addData(tempConstChar);

    QString activeCode = sha1.result().toHex();

    return activeCode;
}

在软件启动时检测是否过期

#include "mainwindow.h"
#include <QApplication>
#include <QMessageBox>
#include "bmachinecontrol.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    // 读取注册表中设置的软件使用期限
    BMachineControl m_machine;

    if ( m_machine.initializeReg() ) {
        QMessageBox::information(nullptr, "Error", "No key !  ", QMessageBox::Ok);
        return 0;
    }

    if ( !m_machine.judgeFile() ) {
        QMessageBox::information(nullptr, "Error", "File Corruption !  ", QMessageBox::Ok);
        return 0;
    }

    if ( !m_machine.judgeDate() ) {
        QMessageBox::information(nullptr, "Error", "Invalid Key ! 0  ", QMessageBox::Ok);
        return 0;
    }

    int days = m_machine.judgeKey();
    if ( days == -1 ) {
        QMessageBox::information(nullptr, "Error", "Invalid Key ! -1  ", QMessageBox::Ok);
        return 0;
    } else if ( days == -2 ) {
        QMessageBox::information(nullptr, "Error", "Invalid Key ! -2  ", QMessageBox::Ok);
        return 0;
    } else {
        if (days <= 7) {
            QMessageBox::information(nullptr, "Info", "Days Remaining: " + QString::number(days) + " !  ", QMessageBox::Ok);
        }
    }

    m_machine.refreshDT1();

    MainWindow w;
    w.show();
    return a.exec();
}

清空注册表

在这里插入图片描述

  • 48
    点赞
  • 125
    收藏
    觉得还不错? 一键收藏
  • 335
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 335
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值