在很多商業軟件中,需要提供一些可以試運行的版本,這樣就需要配套密鑰機制來控制,縱觀大部分的試用版軟件,基本上采用以下幾種機制來控制。
1:遠程聯網激活,每次啟動都聯網查看使用時間等,這種方法最完美,缺點是沒法聯網的設備就歇菜了。
2:通過獲取本地的硬盤+CPU等硬件的編號,做一個運算,生成一個激活碼,超過半數的軟件會采用此方法,缺點是不能自由控制軟件的其他參數,比如軟件中添加的設備數量的控制。
3:設定一個運行到期時間+數量限制+已運行時間的密鑰文件,發給用戶配套軟件使用,缺點是如果僅僅設置的是運行到期時間,用戶可以更改電腦時間來獲取更長的使用時間,在電腦不聯網的情況下。
本demo采用拋磚引玉的形式,用第三種方法來實現,密鑰文件采用最簡單的異或加密,可以自行改成其他加密方法。
完整代碼下載地址:https://download.csdn.net/download/feiyangqingyun/10975625
核心代碼:
1 #include "frmmain.h" 2 #include "ui_frmmain.h" 3 #include "qmessagebox.h" 4 #include "qfile.h" 5 6 frmMain::frmMain(QWidget *parent) : QWidget(parent), ui(new Ui::frmMain) 7 { 8 ui->setupUi(this); 9 this->initForm(); 10 } 11 12 frmMain::~frmMain() 13 { 14 delete ui; 15 } 16 17 void frmMain::initForm() 18 { 19 QStringList min; 20 min << "1" << "5" << "10" << "20" << "30"; 21 for (int i = 1; i <= 24; i++) { 22 min << QString::number(i * 60); 23 } 24 25 ui->cboxMin->addItems(min); 26 ui->cboxMin->setCurrentIndex(1); 27 ui->dateEdit->setDate(QDate::currentDate()); 28 29 for (int i = 5; i <= 150; i = i + 5) { 30 ui->cboxCount->addItem(QString("%1").arg(i)); 31 } 32 } 33 34 QString frmMain::getXorEncryptDecrypt(const QString &data, char key) 35 { 36 //采用異或加密,也可以自行更改算法 37 QByteArray buffer = data.toLatin1(); 38 int size = buffer.size(); 39 for (int i = 0; i < size; i++) { 40 buffer[i] = buffer.at(i) ^ key; 41 } 42 43 return QLatin1String(buffer); 44 } 45 46 void frmMain::on_btnOk_clicked() 47 { 48 bool useDate = ui->ckDate->isChecked(); 49 bool useRun = ui->ckRun->isChecked(); 50 bool useCount = ui->ckCount->isChecked(); 51 52 if (!useDate && !useRun && !useCount) { 53 if (QMessageBox::question(this, "詢問", "確定要生成沒有任何限制的密鑰嗎?") != QMessageBox::Yes) { 54 return; 55 } 56 } 57 58 QString strDate = ui->dateEdit->date().toString("yyyy-MM-dd"); 59 QString strRun = ui->cboxMin->currentText(); 60 QString strCount = ui->cboxCount->currentText(); 61 QString key = QString("%1|%2|%3|%4|%5|%6").arg(useDate).arg(strDate).arg(useRun).arg(strRun).arg(useCount).arg(strCount); 62 63 QFile file(QApplication::applicationDirPath() + "/key.db"); 64 file.open(QFile::WriteOnly | QIODevice::Text); 65 file.write(getXorEncryptDecrypt(key, 110).toLatin1()); 66 file.close(); 67 QMessageBox::information(this, "提示", "生成密鑰成功,將 key.db 文件拷貝到對應目錄即可!"); 68 } 69 70 void frmMain::on_btnClose_clicked() 71 { 72 this->close(); 73 }
使用demo封裝類代碼:
1 #include "appkey.h" 2 #include "qmutex.h" 3 #include "qfile.h" 4 #include "qtimer.h" 5 #include "qdatetime.h" 6 #include "qapplication.h" 7 #include "qmessagebox.h" 8 9 AppKey *AppKey::self = NULL; 10 AppKey *AppKey::Instance() 11 { 12 if (!self) { 13 QMutex mutex; 14 QMutexLocker locker(&mutex); 15 if (!self) { 16 self = new AppKey; 17 } 18 } 19 20 return self; 21 } 22 23 AppKey::AppKey(QObject *parent) : QObject(parent) 24 { 25 keyData = ""; 26 keyUseDate = false; 27 keyDate = "2017-01-01"; 28 keyUseRun = false; 29 keyRun = 1; 30 keyUseCount = false; 31 keyCount = 10; 32 33 timer = new QTimer(this); 34 timer->setInterval(1000); 35 connect(timer, SIGNAL(timeout()), this, SLOT(checkTime())); 36 startTime = QDateTime::currentDateTime(); 37 } 38 39 void AppKey::start() 40 { 41 //判斷密鑰文件是否存在,不存在則從資源文件復制出來,同時需要設置文件寫權限 42 QString keyName = qApp->applicationDirPath() + "/key.db"; 43 QFile keyFile(keyName); 44 if (!keyFile.exists() || keyFile.size() == 0) { 45 QMessageBox::critical(0, "錯誤", "密鑰文件丟失,請聯系供應商!"); 46 exit(0); 47 } 48 49 //讀取密鑰文件 50 keyFile.open(QFile::ReadOnly); 51 keyData = keyFile.readLine(); 52 keyFile.close(); 53 54 //將從注冊碼文件中的密文解密,與當前時間比較是否到期 55 keyData = getXorEncryptDecrypt(keyData, 110); 56 QStringList data = keyData.split("|"); 57 58 if (data.count() != 6) { 59 QMessageBox::critical(0, "錯誤", "注冊碼文件已損壞,程序將自動關閉!"); 60 exit(0); 61 } 62 63 keyUseDate = (data.at(0) == "1" ? true : false); 64 keyDate = data.at(1); 65 keyUseRun = (data.at(2) == "1" ? true : false); 66 keyRun = data.at(3).toInt(); 67 keyUseCount = (data.at(4) == "1" ? true : false); 68 keyCount = data.at(5).toInt(); 69 70 //如果啟用了時間限制 71 if (keyUseDate) { 72 QString nowDate = QDate::currentDate().toString("yyyy-MM-dd"); 73 if (nowDate > keyDate) { 74 QMessageBox::critical(0, "錯誤", "軟件已到期,請聯系供應商更新注冊碼!"); 75 exit(0); 76 } 77 } 78 79 //如果啟用了運行時間顯示 80 if (keyUseRun) { 81 timer->start(); 82 } 83 } 84 85 void AppKey::stop() 86 { 87 timer->stop(); 88 } 89 90 void AppKey::checkTime() 91 { 92 //找出當前時間與首次啟動時間比較 93 QDateTime now = QDateTime::currentDateTime(); 94 if (startTime.secsTo(now) >= (keyRun * 60)) { 95 QMessageBox::critical(0, "錯誤", "試運行時間已到,請聯系供應商更新注冊碼!"); 96 exit(0); 97 } 98 } 99 100 QString AppKey::getXorEncryptDecrypt(const QString &data, char key) 101 { 102 //采用異或加密,也可以自行更改算法 103 QByteArray buffer = data.toLatin1(); 104 int size = buffer.size(); 105 for (int i = 0; i < size; i++) { 106 buffer[i] = buffer.at(i) ^ key; 107 } 108 109 return QLatin1String(buffer); 110 } 111 112 bool AppKey::checkCount(int count) 113 { 114 if (keyUseCount) { 115 if (count >= keyCount) { 116 QMessageBox::critical(0, "錯誤", "設備數量超過限制,請聯系供應商更新注冊碼!"); 117 return false; 118 } 119 } 120 121 return true; 122 }