diff --git a/0snap/key.png b/0snap/key.png new file mode 100644 index 0000000..90be902 Binary files /dev/null and b/0snap/key.png differ diff --git a/0snap/live.png b/0snap/live.png new file mode 100644 index 0000000..b09a677 Binary files /dev/null and b/0snap/live.png differ diff --git a/README.md b/README.md index 4df967b..3999b64 100644 --- a/README.md +++ b/README.md @@ -40,8 +40,10 @@ | 33 | echartgauge | echart仪表盘含交互支持webkit及webengine | | 34 | ffmpegdemo | 视频流播放ffmpeg内核 | | 35 | vlcdemo | 视频流播放vlc内核 | -| 36 | designer | QtDesigner4源码 | -| 37 | netserver | 网络中转服务器 | +| 36 | key | 秘钥生成器 | +| 37 | live | 程序守护进程 | +| 38 | designer | QtDesigner4源码 | +| 39 | netserver | 网络中转服务器 | ### 二、学习群 1. **Qt交流大会群 853086607(雨田哥)** @@ -86,5 +88,7 @@ ![avatar](https://github.com/feiyangqingyun/QWidgetDemo/raw/master/0snap/imageswitch.gif) ![avatar](https://github.com/feiyangqingyun/QWidgetDemo/raw/master/0snap/ffmpegdemo.png) ![avatar](https://github.com/feiyangqingyun/QWidgetDemo/raw/master/0snap/vlcdemo.png) +![avatar](https://github.com/feiyangqingyun/QWidgetDemo/raw/master/0snap/key.png) +![avatar](https://github.com/feiyangqingyun/QWidgetDemo/raw/master/0snap/live.png) ![avatar](https://github.com/feiyangqingyun/QWidgetDemo/raw/master/0snap/netserver.jpg) ![avatar](https://github.com/feiyangqingyun/QWidgetDemo/raw/master/0snap/designer.png) \ No newline at end of file diff --git a/key/key.pro b/key/key.pro new file mode 100644 index 0000000..a5e8a85 --- /dev/null +++ b/key/key.pro @@ -0,0 +1,4 @@ +TEMPLATE = subdirs +CONFIG += ordered +SUBDIRS += keytool +SUBDIRS += keydemo diff --git a/key/keydemo/appkey.cpp b/key/keydemo/appkey.cpp new file mode 100644 index 0000000..064be08 --- /dev/null +++ b/key/keydemo/appkey.cpp @@ -0,0 +1,122 @@ +#include "appkey.h" +#include "qmutex.h" +#include "qfile.h" +#include "qtimer.h" +#include "qdatetime.h" +#include "qapplication.h" +#include "qmessagebox.h" + +AppKey *AppKey::self = NULL; +AppKey *AppKey::Instance() +{ + if (!self) { + QMutex mutex; + QMutexLocker locker(&mutex); + if (!self) { + self = new AppKey; + } + } + + return self; +} + +AppKey::AppKey(QObject *parent) : QObject(parent) +{ + keyData = ""; + keyUseDate = false; + keyDate = "2017-01-01"; + keyUseRun = false; + keyRun = 1; + keyUseCount = false; + keyCount = 10; + + timer = new QTimer(this); + timer->setInterval(1000); + connect(timer, SIGNAL(timeout()), this, SLOT(checkTime())); + startTime = QDateTime::currentDateTime(); +} + +void AppKey::start() +{ + //判断密钥文件是否存在,不存在则从资源文件复制出来,同时需要设置文件写权限 + QString keyName = qApp->applicationDirPath() + "/key.db"; + QFile keyFile(keyName); + if (!keyFile.exists() || keyFile.size() == 0) { + QMessageBox::critical(0, "错误", "密钥文件丢失,请联系供应商!"); + exit(0); + } + + //读取密钥文件 + keyFile.open(QFile::ReadOnly); + keyData = keyFile.readLine(); + keyFile.close(); + + //将从注册码文件中的密文解密,与当前时间比较是否到期 + keyData = getXorEncryptDecrypt(keyData, 110); + QStringList data = keyData.split("|"); + + if (data.count() != 6) { + QMessageBox::critical(0, "错误", "注册码文件已损坏,程序将自动关闭!"); + exit(0); + } + + keyUseDate = (data.at(0) == "1"); + keyDate = data.at(1); + keyUseRun = (data.at(2) == "1"); + keyRun = data.at(3).toInt(); + keyUseCount = (data.at(4) == "1"); + keyCount = data.at(5).toInt(); + + //如果启用了时间限制 + if (keyUseDate) { + QString nowDate = QDate::currentDate().toString("yyyy-MM-dd"); + if (nowDate > keyDate) { + QMessageBox::critical(0, "错误", "软件已到期,请联系供应商更新注册码!"); + exit(0); + } + } + + //如果启用了运行时间显示 + if (keyUseRun) { + timer->start(); + } +} + +void AppKey::stop() +{ + timer->stop(); +} + +void AppKey::checkTime() +{ + //找出当前时间与首次启动时间比较 + QDateTime now = QDateTime::currentDateTime(); + if (startTime.secsTo(now) >= (keyRun * 60)) { + QMessageBox::critical(0, "错误", "试运行时间已到,请联系供应商更新注册码!"); + exit(0); + } +} + +QString AppKey::getXorEncryptDecrypt(const QString &data, char key) +{ + //采用异或加密,也可以自行更改算法 + QByteArray buffer = data.toLatin1(); + int size = buffer.size(); + for (int i = 0; i < size; i++) { + buffer[i] = buffer.at(i) ^ key; + } + + return QLatin1String(buffer); +} + +bool AppKey::checkCount(int count) +{ + if (keyUseCount) { + if (count >= keyCount) { + QMessageBox::critical(0, "错误", "设备数量超过限制,请联系供应商更新注册码!"); + return false; + } + } + + return true; +} diff --git a/key/keydemo/appkey.h b/key/keydemo/appkey.h new file mode 100644 index 0000000..0f1d300 --- /dev/null +++ b/key/keydemo/appkey.h @@ -0,0 +1,40 @@ +#ifndef APPKEY_H +#define APPKEY_H + +#include +#include + +class QTimer; + +class AppKey : public QObject +{ + Q_OBJECT +public: + static AppKey *Instance(); + explicit AppKey(QObject *parent = 0); + +private: + static AppKey *self; + + QString keyData; //注册码密文 + bool keyUseDate; //是否启用运行日期时间限制 + QString keyDate; //到期时间字符串 + bool keyUseRun; //是否启用可运行时间限制 + int keyRun; //可运行时间 + bool keyUseCount; //是否启用设备数量限制 + int keyCount; //设备限制数量 + + QTimer *timer; //定时器判断是否运行超时 + QDateTime startTime; //程序启动时间 + +private slots: + void checkTime(); + QString getXorEncryptDecrypt(const QString &data, char key); + +public slots: + void start(); + void stop(); + bool checkCount(int count); +}; + +#endif // APPKEY_H diff --git a/key/keydemo/frmmain.cpp b/key/keydemo/frmmain.cpp new file mode 100644 index 0000000..f3893e7 --- /dev/null +++ b/key/keydemo/frmmain.cpp @@ -0,0 +1,22 @@ +#include "frmmain.h" +#include "ui_frmmain.h" +#include "appkey.h" + +frmMain::frmMain(QWidget *parent) : QWidget(parent), ui(new Ui::frmMain) +{ + ui->setupUi(this); +} + +frmMain::~frmMain() +{ + delete ui; +} + +void frmMain::on_btnAdd_clicked() +{ + QString name = ui->lineEdit->text().trimmed(); + ui->listWidget->addItem(name); + + //计算当前设备数量多少 + AppKey::Instance()->checkCount(ui->listWidget->count()); +} diff --git a/key/keydemo/frmmain.h b/key/keydemo/frmmain.h new file mode 100644 index 0000000..f190b7d --- /dev/null +++ b/key/keydemo/frmmain.h @@ -0,0 +1,25 @@ +#ifndef FRMMAIN_H +#define FRMMAIN_H + +#include + +namespace Ui { +class frmMain; +} + +class frmMain : public QWidget +{ + Q_OBJECT + +public: + explicit frmMain(QWidget *parent = 0); + ~frmMain(); + +private: + Ui::frmMain *ui; + +private slots: + void on_btnAdd_clicked(); +}; + +#endif // FRMMAIN_H diff --git a/key/keydemo/frmmain.ui b/key/keydemo/frmmain.ui new file mode 100644 index 0000000..b3cb5e6 --- /dev/null +++ b/key/keydemo/frmmain.ui @@ -0,0 +1,39 @@ + + + frmMain + + + + 0 + 0 + 400 + 300 + + + + frmMain + + + + + + + + + 测试设备 + + + + + + + 添加 + + + + + + + + + diff --git a/key/keydemo/keydemo.pro b/key/keydemo/keydemo.pro new file mode 100644 index 0000000..5c28892 --- /dev/null +++ b/key/keydemo/keydemo.pro @@ -0,0 +1,24 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2019-02-17T20:23:58 +# +#------------------------------------------------- + +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +TARGET = keydemo +TEMPLATE = app +MOC_DIR = temp/moc +RCC_DIR = temp/rcc +UI_DIR = temp/ui +OBJECTS_DIR = temp/obj +DESTDIR = $$PWD/../bin +CONFIG += warn_off + +SOURCES += main.cpp +SOURCES += frmmain.cpp appkey.cpp +HEADERS += frmmain.h appkey.h +FORMS += frmmain.ui + diff --git a/key/keydemo/main.cpp b/key/keydemo/main.cpp new file mode 100644 index 0000000..497ac30 --- /dev/null +++ b/key/keydemo/main.cpp @@ -0,0 +1,34 @@ +#pragma execution_character_set("utf-8") +#include "frmmain.h" +#include "appkey.h" +#include +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + a.setFont(QFont("Microsoft Yahei", 9)); + +#if (QT_VERSION <= QT_VERSION_CHECK(5,0,0)) +#if _MSC_VER + QTextCodec *codec = QTextCodec::codecForName("gbk"); +#else + QTextCodec *codec = QTextCodec::codecForName("utf-8"); +#endif + QTextCodec::setCodecForLocale(codec); + QTextCodec::setCodecForCStrings(codec); + QTextCodec::setCodecForTr(codec); +#else + QTextCodec *codec = QTextCodec::codecForName("utf-8"); + QTextCodec::setCodecForLocale(codec); +#endif + + //启动密钥服务类 + AppKey::Instance()->start(); + + frmMain w; + w.setWindowTitle("密钥使用示例"); + w.show(); + + return a.exec(); +} diff --git a/key/keytool/frmmain.cpp b/key/keytool/frmmain.cpp new file mode 100644 index 0000000..38f2278 --- /dev/null +++ b/key/keytool/frmmain.cpp @@ -0,0 +1,112 @@ +#include "frmmain.h" +#include "ui_frmmain.h" +#include "qmessagebox.h" +#include "qfile.h" +#include "qprocess.h" +#include "qdebug.h" + +frmMain::frmMain(QWidget *parent) : QWidget(parent), ui(new Ui::frmMain) +{ + ui->setupUi(this); + this->initForm(); + qDebug() << this->getCpuName() << this->getCpuId() << this->getDiskNum(); +} + +frmMain::~frmMain() +{ + delete ui; +} + +void frmMain::initForm() +{ + QStringList min; + min << "1" << "5" << "10" << "20" << "30"; + for (int i = 1; i <= 24; i++) { + min << QString::number(i * 60); + } + + ui->cboxMin->addItems(min); + ui->cboxMin->setCurrentIndex(1); + ui->dateEdit->setDate(QDate::currentDate()); + + for (int i = 5; i <= 150; i = i + 5) { + ui->cboxCount->addItem(QString("%1").arg(i)); + } +} + +QString frmMain::getWMIC(const QString &cmd) +{ + //获取cpu名称:wmic cpu get Name + //获取cpu核心数:wmic cpu get NumberOfCores + //获取cpu线程数:wmic cpu get NumberOfLogicalProcessors + //查询cpu序列号:wmic cpu get processorid + //查询主板序列号:wmic baseboard get serialnumber + //查询BIOS序列号:wmic bios get serialnumber + //查看硬盘:wmic diskdrive get serialnumber + QProcess p; + p.start(cmd); + p.waitForFinished(); + QString result = QString::fromLocal8Bit(p.readAllStandardOutput()); + QStringList list = cmd.split(" "); + result = result.remove(list.last(), Qt::CaseInsensitive); + result = result.replace("\r", ""); + result = result.replace("\n", ""); + result = result.simplified(); + return result; +} + +QString frmMain::getCpuName() +{ + return getWMIC("wmic cpu get name"); +} + +QString frmMain::getCpuId() +{ + return getWMIC("wmic cpu get processorid"); +} + +QString frmMain::getDiskNum() +{ + return getWMIC("wmic diskdrive where index=0 get serialnumber"); +} + +QString frmMain::getXorEncryptDecrypt(const QString &data, char key) +{ + //采用异或加密,也可以自行更改算法 + QByteArray buffer = data.toLatin1(); + int size = buffer.size(); + for (int i = 0; i < size; i++) { + buffer[i] = buffer.at(i) ^ key; + } + + return QLatin1String(buffer); +} + +void frmMain::on_btnOk_clicked() +{ + bool useDate = ui->ckDate->isChecked(); + bool useRun = ui->ckRun->isChecked(); + bool useCount = ui->ckCount->isChecked(); + + if (!useDate && !useRun && !useCount) { + if (QMessageBox::question(this, "询问", "确定要生成没有任何限制的密钥吗?") != QMessageBox::Yes) { + return; + } + } + + QString strDate = ui->dateEdit->date().toString("yyyy-MM-dd"); + QString strRun = ui->cboxMin->currentText(); + QString strCount = ui->cboxCount->currentText(); + QString key = QString("%1|%2|%3|%4|%5|%6").arg(useDate).arg(strDate).arg(useRun).arg(strRun).arg(useCount).arg(strCount); + + QFile file(QApplication::applicationDirPath() + "/key.db"); + file.open(QFile::WriteOnly | QIODevice::Text); + file.write(getXorEncryptDecrypt(key, 110).toLatin1()); + file.close(); + QMessageBox::information(this, "提示", "生成密钥成功,将 key.db 文件拷贝到对应目录即可!"); +} + +void frmMain::on_btnClose_clicked() +{ + this->close(); +} diff --git a/key/keytool/frmmain.h b/key/keytool/frmmain.h new file mode 100644 index 0000000..21c44f2 --- /dev/null +++ b/key/keytool/frmmain.h @@ -0,0 +1,34 @@ +#ifndef FRMMAIN_H +#define FRMMAIN_H + +#include + +namespace Ui { +class frmMain; +} + +class frmMain : public QWidget +{ + Q_OBJECT + +public: + explicit frmMain(QWidget *parent = 0); + ~frmMain(); + +private: + Ui::frmMain *ui; + +private slots: + void initForm(); + QString getWMIC(const QString &cmd); + QString getCpuName(); + QString getCpuId(); + QString getDiskNum(); + QString getXorEncryptDecrypt(const QString &data, char key); + +private slots: + void on_btnOk_clicked(); + void on_btnClose_clicked(); +}; + +#endif // FRMMAIN_H diff --git a/key/keytool/frmmain.ui b/key/keytool/frmmain.ui new file mode 100644 index 0000000..622a854 --- /dev/null +++ b/key/keytool/frmmain.ui @@ -0,0 +1,156 @@ + + + frmMain + + + + 0 + 0 + 334 + 129 + + + + frmMain + + + + + + Qt::NoFocus + + + yyyy年MM月dd日 + + + true + + + + + + + + 80 + 0 + + + + Qt::NoFocus + + + 生成 + + + + 20 + 20 + + + + + + + + Qt::NoFocus + + + 时间限制 + + + + + + + Qt::NoFocus + + + 数量限制 + + + + + + + true + + + + + + + + 80 + 0 + + + + Qt::NoFocus + + + 关闭 + + + + 20 + 20 + + + + + + + + Qt::NoFocus + + + 运行限制 + + + + + + + true + + + + + + + 分钟自动关闭 + + + + + + + Qt::Vertical + + + + 20 + 24 + + + + + + + + Qt::Horizontal + + + + 1 + 108 + + + + + + + + + + diff --git a/key/keytool/keytool.pro b/key/keytool/keytool.pro new file mode 100644 index 0000000..16c64ae --- /dev/null +++ b/key/keytool/keytool.pro @@ -0,0 +1,24 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2019-02-17T20:23:58 +# +#------------------------------------------------- + +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +TARGET = keytool +TEMPLATE = app +MOC_DIR = temp/moc +RCC_DIR = temp/rcc +UI_DIR = temp/ui +OBJECTS_DIR = temp/obj +DESTDIR = $$PWD/../bin +CONFIG += warn_off + +SOURCES += main.cpp +SOURCES += frmmain.cpp +HEADERS += frmmain.h +FORMS += frmmain.ui + diff --git a/key/keytool/main.cpp b/key/keytool/main.cpp new file mode 100644 index 0000000..265cb8d --- /dev/null +++ b/key/keytool/main.cpp @@ -0,0 +1,30 @@ +#pragma execution_character_set("utf-8") +#include "frmmain.h" +#include +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + a.setFont(QFont("Microsoft Yahei", 9)); + +#if (QT_VERSION <= QT_VERSION_CHECK(5,0,0)) +#if _MSC_VER + QTextCodec *codec = QTextCodec::codecForName("gbk"); +#else + QTextCodec *codec = QTextCodec::codecForName("utf-8"); +#endif + QTextCodec::setCodecForLocale(codec); + QTextCodec::setCodecForCStrings(codec); + QTextCodec::setCodecForTr(codec); +#else + QTextCodec *codec = QTextCodec::codecForName("utf-8"); + QTextCodec::setCodecForLocale(codec); +#endif + + frmMain w; + w.setWindowTitle("密钥生成工具"); + w.show(); + + return a.exec(); +} diff --git a/key/snap/QQ截图20190226090503.png b/key/snap/QQ截图20190226090503.png new file mode 100644 index 0000000..90be902 Binary files /dev/null and b/key/snap/QQ截图20190226090503.png differ diff --git a/key/snap/QQ截图20190226090532.png b/key/snap/QQ截图20190226090532.png new file mode 100644 index 0000000..6234099 Binary files /dev/null and b/key/snap/QQ截图20190226090532.png differ diff --git a/key/snap/QQ截图20190226090557.png b/key/snap/QQ截图20190226090557.png new file mode 100644 index 0000000..c2ddaaf Binary files /dev/null and b/key/snap/QQ截图20190226090557.png differ diff --git a/key/snap/QQ截图20190226090720.png b/key/snap/QQ截图20190226090720.png new file mode 100644 index 0000000..771a97d Binary files /dev/null and b/key/snap/QQ截图20190226090720.png differ diff --git a/live/live.pro b/live/live.pro new file mode 100644 index 0000000..89a3774 --- /dev/null +++ b/live/live.pro @@ -0,0 +1,4 @@ +TEMPLATE = subdirs +CONFIG += ordered +SUBDIRS += livetool +SUBDIRS += livedemo diff --git a/live/livedemo/applive.cpp b/live/livedemo/applive.cpp new file mode 100644 index 0000000..7171233 --- /dev/null +++ b/live/livedemo/applive.cpp @@ -0,0 +1,66 @@ +#include "applive.h" +#include "qmutex.h" +#include "qudpsocket.h" +#include "qstringlist.h" +#include "qapplication.h" +#include "qdatetime.h" +#include "qdebug.h" + +#define TIMEMS qPrintable(QTime::currentTime().toString("HH:mm:ss zzz")) + +QScopedPointer AppLive::self; +AppLive *AppLive::Instance() +{ + if (self.isNull()) { + QMutex mutex; + QMutexLocker locker(&mutex); + if (self.isNull()) { + self.reset(new AppLive); + } + } + + return self.data(); +} + +AppLive::AppLive(QObject *parent) : QObject(parent) +{ + udpServer = new QUdpSocket(this); + + QString name = qApp->applicationFilePath(); + QStringList list = name.split("/"); + appName = list.at(list.count() - 1).split(".").at(0); +} + +void AppLive::readData() +{ + QByteArray tempData; + + do { + tempData.resize(udpServer->pendingDatagramSize()); + QHostAddress sender; + quint16 senderPort; + udpServer->readDatagram(tempData.data(), tempData.size(), &sender, &senderPort); + QString data = QLatin1String(tempData); + + if (data == "hello") { + udpServer->writeDatagram(QString("%1OK").arg(appName).toLatin1(), sender, senderPort); + } + } while (udpServer->hasPendingDatagrams()); +} + +bool AppLive::start(int port) +{ + bool ok = udpServer->bind(port); + if (ok) { + connect(udpServer, SIGNAL(readyRead()), this, SLOT(readData())); + qDebug() << TIMEMS << "Start AppLive Ok"; + } + + return ok; +} + +void AppLive::stop() +{ + udpServer->abort(); + disconnect(udpServer, SIGNAL(readyRead()), this, SLOT(readData())); +} diff --git a/live/livedemo/applive.h b/live/livedemo/applive.h new file mode 100644 index 0000000..304c746 --- /dev/null +++ b/live/livedemo/applive.h @@ -0,0 +1,28 @@ +#ifndef APPLIVE_H +#define APPLIVE_H + +#include + +class QUdpSocket; + +class AppLive : public QObject +{ + Q_OBJECT +public: + static AppLive *Instance(); + explicit AppLive(QObject *parent = 0); + +private: + static QScopedPointer self; + QUdpSocket *udpServer; + QString appName; + +private slots: + void readData(); + +public slots: + bool start(int port); + void stop(); +}; + +#endif // APPLIVE_H diff --git a/live/livedemo/frmmain.cpp b/live/livedemo/frmmain.cpp new file mode 100644 index 0000000..4115d9d --- /dev/null +++ b/live/livedemo/frmmain.cpp @@ -0,0 +1,12 @@ +#include "frmmain.h" +#include "ui_frmmain.h" + +frmMain::frmMain(QWidget *parent) : QWidget(parent), ui(new Ui::frmMain) +{ + ui->setupUi(this); +} + +frmMain::~frmMain() +{ + delete ui; +} diff --git a/live/livedemo/frmmain.h b/live/livedemo/frmmain.h new file mode 100644 index 0000000..ad1efe1 --- /dev/null +++ b/live/livedemo/frmmain.h @@ -0,0 +1,22 @@ +#ifndef FRMMAIN_H +#define FRMMAIN_H + +#include + +namespace Ui { +class frmMain; +} + +class frmMain : public QWidget +{ + Q_OBJECT + +public: + explicit frmMain(QWidget *parent = 0); + ~frmMain(); + +private: + Ui::frmMain *ui; +}; + +#endif // FRMMAIN_H diff --git a/live/livedemo/frmmain.ui b/live/livedemo/frmmain.ui new file mode 100644 index 0000000..9317247 --- /dev/null +++ b/live/livedemo/frmmain.ui @@ -0,0 +1,21 @@ + + + frmMain + + + + 0 + 0 + 400 + 300 + + + + frmMain + + + + + + + diff --git a/live/livedemo/livedemo.pro b/live/livedemo/livedemo.pro new file mode 100644 index 0000000..bb0cf6a --- /dev/null +++ b/live/livedemo/livedemo.pro @@ -0,0 +1,24 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2019-02-17T20:23:58 +# +#------------------------------------------------- + +QT += core gui network + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +TARGET = livedemo +TEMPLATE = app +MOC_DIR = temp/moc +RCC_DIR = temp/rcc +UI_DIR = temp/ui +OBJECTS_DIR = temp/obj +DESTDIR = $$PWD/../bin +CONFIG += warn_off + +SOURCES += main.cpp +SOURCES += frmmain.cpp applive.cpp +HEADERS += frmmain.h applive.h +FORMS += frmmain.ui + diff --git a/live/livedemo/main.cpp b/live/livedemo/main.cpp new file mode 100644 index 0000000..52bee1d --- /dev/null +++ b/live/livedemo/main.cpp @@ -0,0 +1,34 @@ +#pragma execution_character_set("utf-8") +#include "frmmain.h" +#include "applive.h" +#include +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + a.setFont(QFont("Microsoft Yahei", 9)); + +#if (QT_VERSION <= QT_VERSION_CHECK(5,0,0)) +#if _MSC_VER + QTextCodec *codec = QTextCodec::codecForName("gbk"); +#else + QTextCodec *codec = QTextCodec::codecForName("utf-8"); +#endif + QTextCodec::setCodecForLocale(codec); + QTextCodec::setCodecForCStrings(codec); + QTextCodec::setCodecForTr(codec); +#else + QTextCodec *codec = QTextCodec::codecForName("utf-8"); + QTextCodec::setCodecForLocale(codec); +#endif + + //启动守护程序服务类 + AppLive::Instance()->start(6666); + + frmMain w; + w.setWindowTitle("守护程序使用示例"); + w.show(); + + return a.exec(); +} diff --git a/live/livetool/app.cpp b/live/livetool/app.cpp new file mode 100644 index 0000000..80ebdc7 --- /dev/null +++ b/live/livetool/app.cpp @@ -0,0 +1,79 @@ +#include "app.h" +#include "qsettings.h" +#include "qfile.h" + +QString App::ConfigFile = "config.ini"; +QString App::TargetAppName = "livedemo"; +int App::TargetAppPort = 6666; +bool App::ReStartExplorer = false; +int App::TimeoutCount = 3; +int App::ReStartCount = 0; +QString App::ReStartLastTime = "2019-01-01 00:00:00"; + +void App::readConfig() +{ + if (!checkConfig()) { + return; + } + + QSettings set(App::ConfigFile, QSettings::IniFormat); + set.beginGroup("BaseConfig"); + App::TargetAppName = set.value("TargetAppName", App::TargetAppName).toString(); + App::TargetAppPort = set.value("TargetAppPort", App::TargetAppPort).toInt(); + App::ReStartExplorer = set.value("ReStartExplorer", App::ReStartExplorer).toBool(); + App::TimeoutCount = set.value("TimeoutCount", App::TimeoutCount).toInt(); + App::ReStartCount = set.value("ReStartCount", App::ReStartCount).toInt(); + App::ReStartLastTime = set.value("ReStartLastTime", App::ReStartLastTime).toString(); + set.endGroup(); +} + +void App::writeConfig() +{ + QSettings set(App::ConfigFile, QSettings::IniFormat); + set.beginGroup("BaseConfig"); + set.setValue("TargetAppName", App::TargetAppName); + set.setValue("TargetAppPort", App::TargetAppPort); + set.setValue("ReStartExplorer", App::ReStartExplorer); + set.setValue("TimeoutCount", App::TimeoutCount); + set.setValue("ReStartCount", App::ReStartCount); + set.setValue("ReStartLastTime", App::ReStartLastTime); + set.endGroup(); +} + +bool App::checkConfig() +{ + //如果配置文件大小为0,则以初始值继续运行,并生成配置文件 + QFile file(App::ConfigFile); + if (file.size() == 0) { + writeConfig(); + return false; + } + + //如果配置文件不完整,则以初始值继续运行,并生成配置文件 + if (file.open(QFile::ReadOnly)) { + bool ok = true; + while (!file.atEnd()) { + QString line = file.readLine(); + line = line.replace("\r", ""); + line = line.replace("\n", ""); + QStringList list = line.split("="); + + if (list.count() == 2) { + if (list.at(1) == "") { + ok = false; + break; + } + } + } + + if (!ok) { + writeConfig(); + return false; + } + } else { + writeConfig(); + return false; + } + + return true; +} diff --git a/live/livetool/app.h b/live/livetool/app.h new file mode 100644 index 0000000..1ce5daa --- /dev/null +++ b/live/livetool/app.h @@ -0,0 +1,23 @@ +#ifndef APP_H +#define APP_H + +#include + +class App +{ +public: + static QString ConfigFile; //配置文件文件路径及名称 + static QString TargetAppName; //目标软件程序名称 + static int TargetAppPort; //目标软件通信端口 + static bool ReStartExplorer; //是否需要重启桌面 + static int TimeoutCount; //超时次数 + static int ReStartCount; //已重启次数 + static QString ReStartLastTime; //最后一次重启时间 + + static void readConfig(); //读取配置文件,在main函数最开始加载程序载入 + static void writeConfig(); //写入配置文件,在更改配置文件程序关闭时调用 + static bool checkConfig(); //校验配置文件 + +}; + +#endif // APP_H diff --git a/live/livetool/frmmain.cpp b/live/livetool/frmmain.cpp new file mode 100644 index 0000000..af16983 --- /dev/null +++ b/live/livetool/frmmain.cpp @@ -0,0 +1,206 @@ +#pragma execution_character_set("utf-8") +#include "frmmain.h" +#include "ui_frmmain.h" +#include "qtimer.h" +#include "qudpsocket.h" +#include "qsharedmemory.h" +#include "qprocess.h" +#include "qdatetime.h" +#include "qapplication.h" +#include "qdesktopservices.h" +#include "qmessagebox.h" +#if (QT_VERSION > QT_VERSION_CHECK(5,0,0)) +#include "qstandardpaths.h" +#endif + +#include "app.h" + +frmMain::frmMain(QWidget *parent) : QWidget(parent), ui(new Ui::frmMain) +{ + ui->setupUi(this); + this->initForm(); +} + +frmMain::~frmMain() +{ + delete ui; +} + +void frmMain::changeEvent(QEvent *event) +{ + //隐藏当前界面,最小化到托盘 + if(event->type() == QEvent::WindowStateChange) { + if(windowState() & Qt::WindowMinimized) { + hide(); + } + } + + QWidget::changeEvent(event); +} + +void frmMain::initForm() +{ + count = 0; + ok = false; + + //每秒钟定时询问心跳 + timerHeart = new QTimer(this); + timerHeart->setInterval(2000); + connect(timerHeart, SIGNAL(timeout()), this, SLOT(sendHearData())); + + //从6050端口开始,如果绑定失败则将端口加1,直到绑定成功 + udp = new QUdpSocket(this); + int port = 6050; + while(!udp->bind(port)) { + port++; + } + + connect(udp, SIGNAL(readyRead()), this, SLOT(readData())); + + if (App::TargetAppName.isEmpty()) { + ui->btnStart->setText("启动"); + ui->btnStart->setEnabled(false); + timerHeart->stop(); + } else { + ui->btnStart->setText("暂停"); + ui->btnStart->setEnabled(true); + timerHeart->start(); + } + + ui->txtAppName->setText(App::TargetAppName); + ui->txtAppName->setFocus(); +} + +void frmMain::sendHearData() +{ + udp->writeDatagram("hello", QHostAddress::LocalHost, App::TargetAppPort); + + //判断当前是否没有回复 + if (!ok) { + count++; + } else { + count = 0; + ok = false; + } + + //如果超过规定次数没有收到心跳回复,则超时重启 + if (count >= App::TimeoutCount) { + timerHeart->stop(); + + QSharedMemory mem(App::TargetAppName); + if (!mem.create(1)) { + killApp(); + } + + QTimer::singleShot(1000 , this, SLOT(killOther())); + QTimer::singleShot(3000 , this, SLOT(startApp())); + QTimer::singleShot(4000 , this, SLOT(startExplorer())); + } +} + +void frmMain::killApp() +{ + QProcess *p = new QProcess; + p->start(QString("taskkill /im %1.exe /f").arg(App::TargetAppName)); +} + +void frmMain::killOther() +{ + QProcess *p = new QProcess; + p->start(QString("taskkill /im %1.exe /f").arg("WerFault")); + + //重建缓存,彻底清除托盘图标 + if (App::ReStartExplorer) { + QProcess *p1 = new QProcess; + p1->start("taskkill /f /im explorer.exe"); + } +} + +void frmMain::startApp() +{ + if (ui->btnStart->text() == "开始" || ui->btnStart->text() == "启动") { + count = 0; + return; + } + + QProcess *p = new QProcess; + p->start(QString("\"%1/%2.exe\"").arg(qApp->applicationDirPath()).arg(App::TargetAppName)); + + count = 0; + ok = true; + timerHeart->start(); + + App::ReStartCount++; + App::ReStartLastTime = QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss"); + App::writeConfig(); + + ui->labCount->setText(QString("已重启 %1 次").arg(App::ReStartCount)); + ui->labInfo->setText(QString("最后一次重启在 %1").arg(App::ReStartLastTime)); +} + +void frmMain::startExplorer() +{ + //取得操作系统目录路径,指定操作系统目录下的explorer程序,采用绝对路径,否则在64位操作系统下无效 +#if (QT_VERSION > QT_VERSION_CHECK(5,0,0)) + QString str = QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation); +#else + QString str = QDesktopServices::storageLocation(QDesktopServices::ApplicationsLocation); +#endif + + if (App::ReStartExplorer) { + str = QString("%1\\Windows\\explorer.exe").arg(str.mid(0, 2)); + QProcess *p = new QProcess(this); + p->start(str); + } +} + +void frmMain::readData() +{ + QByteArray tempData; + do { + tempData.resize(udp->pendingDatagramSize()); + udp->readDatagram(tempData.data(), tempData.size()); + QString data = QLatin1String(tempData); + if (data.right(2) == "OK") { + count = 0; + ok = true; + } + } while (udp->hasPendingDatagrams()); +} + +void frmMain::on_btnOk_clicked() +{ + App::TargetAppName = ui->txtAppName->text(); + if (App::TargetAppName == "") { + QMessageBox::critical(this, "提示", "应用程序名称不能为空!"); + ui->txtAppName->setFocus(); + return; + } + + App::writeConfig(); + ui->btnStart->setEnabled(true); +} + +void frmMain::on_btnStart_clicked() +{ + count = 0; + if (ui->btnStart->text() == "暂停") { + timerHeart->stop(); + ui->btnStart->setText("开始"); + } else { + timerHeart->start(); + ui->btnStart->setText("暂停"); + } +} + +void frmMain::on_btnReset_clicked() +{ + App::ReStartCount = 0; + App::ReStartLastTime = "2019-01-01 12:00:00"; + App::writeConfig(); + + ui->txtAppName->setText(App::TargetAppName); + ui->labCount->setText(QString("已重启 %1 次").arg(App::ReStartCount)); + ui->labInfo->setText(QString("最后一次重启在 %1").arg(App::ReStartLastTime)); + QMessageBox::information(this, "提示", "重置配置文件成功!"); +} diff --git a/live/livetool/frmmain.h b/live/livetool/frmmain.h new file mode 100644 index 0000000..f7a306d --- /dev/null +++ b/live/livetool/frmmain.h @@ -0,0 +1,46 @@ +#ifndef FRMMAIN_H +#define FRMMAIN_H + +#include + +class QUdpSocket; + +namespace Ui +{ + class frmMain; +} + +class frmMain : public QWidget +{ + Q_OBJECT + +public: + explicit frmMain(QWidget *parent = 0); + ~frmMain(); + +protected: + void changeEvent(QEvent *event); + +private: + Ui::frmMain *ui; + QTimer *timerHeart; //心跳定时器 + QUdpSocket *udp; //UDP通信对象 + int count; //计数 + bool ok; //是否正常 + +private slots: + void initForm(); + void sendHearData(); + void readData(); + void killApp(); + void killOther(); + void startApp(); + void startExplorer(); + +private slots: + void on_btnOk_clicked(); + void on_btnStart_clicked(); + void on_btnReset_clicked(); +}; + +#endif // FRMMAIN_H diff --git a/live/livetool/frmmain.ui b/live/livetool/frmmain.ui new file mode 100644 index 0000000..39df60c --- /dev/null +++ b/live/livetool/frmmain.ui @@ -0,0 +1,102 @@ + + + frmMain + + + + 0 + 0 + 288 + 125 + + + + false + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + QFrame::Box + + + QFrame::Sunken + + + + + + + 70 + 0 + + + + 应用 + + + + + + + + 70 + 0 + + + + 暂停 + + + + + + + 重置 + + + + + + + + + + 最后一次重启在 + + + + + + + 已重启 0 次 + + + + + + + + + + + txtAppName + btnOk + btnStart + btnReset + + + + diff --git a/live/livetool/livetool.pro b/live/livetool/livetool.pro new file mode 100644 index 0000000..f11590b --- /dev/null +++ b/live/livetool/livetool.pro @@ -0,0 +1,24 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2019-02-15T14:34:50 +# +#------------------------------------------------- + +QT += core gui network + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +TARGET = livetool +TEMPLATE = app +MOC_DIR = temp/moc +RCC_DIR = temp/rcc +UI_DIR = temp/ui +OBJECTS_DIR = temp/obj +DESTDIR = $$PWD/../bin +CONFIG += warn_off + +SOURCES += main.cpp frmmain.cpp trayicon.cpp app.cpp +HEADERS += frmmain.h trayicon.h app.h +FORMS += frmmain.ui +RESOURCES += main.qrc + diff --git a/live/livetool/main.cpp b/live/livetool/main.cpp new file mode 100644 index 0000000..8f258ff --- /dev/null +++ b/live/livetool/main.cpp @@ -0,0 +1,43 @@ +#pragma execution_character_set("utf-8") +#include "frmmain.h" +#include "trayicon.h" +#include "app.h" +#include +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + a.setWindowIcon(QIcon(":/main.ico")); + +#if (QT_VERSION <= QT_VERSION_CHECK(5,0,0)) +#if _MSC_VER + QTextCodec *codec = QTextCodec::codecForName("gbk"); +#else + QTextCodec *codec = QTextCodec::codecForName("utf-8"); +#endif + QTextCodec::setCodecForLocale(codec); + QTextCodec::setCodecForCStrings(codec); + QTextCodec::setCodecForTr(codec); +#else + QTextCodec *codec = QTextCodec::codecForName("utf-8"); + QTextCodec::setCodecForLocale(codec); +#endif + + frmMain w; + w.setWindowTitle("程序启动器"); + w.setFixedSize(w.sizeHint()); + + //启动托盘类 + TrayIcon::Instance()->setMainWidget(&w); + TrayIcon::Instance()->setIcon(":/main.ico"); + TrayIcon::Instance()->setToolTip(w.windowTitle()); + TrayIcon::Instance()->setVisible(true); + QObject::connect(&w, SIGNAL(destroyed(QObject *)), TrayIcon::Instance(), SLOT(closeAll())); + + App::ConfigFile = qApp->applicationDirPath() + "/config.ini"; + App::readConfig(); + App::TargetAppName.isEmpty() ? w.show() : w.hide(); + + return a.exec(); +} diff --git a/live/livetool/main.ico b/live/livetool/main.ico new file mode 100644 index 0000000..100e0dc Binary files /dev/null and b/live/livetool/main.ico differ diff --git a/live/livetool/main.qrc b/live/livetool/main.qrc new file mode 100644 index 0000000..91c2747 --- /dev/null +++ b/live/livetool/main.qrc @@ -0,0 +1,5 @@ + + + main.ico + + diff --git a/live/livetool/trayicon.cpp b/live/livetool/trayicon.cpp new file mode 100644 index 0000000..133f973 --- /dev/null +++ b/live/livetool/trayicon.cpp @@ -0,0 +1,99 @@ +#pragma execution_character_set("utf-8") + +#include "trayicon.h" +#include "qmutex.h" +#include "qmenu.h" +#include "qapplication.h" +#include "qdesktopwidget.h" +#include "qdebug.h" + +QScopedPointer TrayIcon::self; +TrayIcon *TrayIcon::Instance() +{ + if (self.isNull()) { + QMutex mutex; + QMutexLocker locker(&mutex); + if (self.isNull()) { + self.reset(new TrayIcon); + } + } + + return self.data(); +} + +TrayIcon::TrayIcon(QObject *parent) : QObject(parent) +{ + mainWidget = 0; + trayIcon = new QSystemTrayIcon(this); + connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), + this, SLOT(iconIsActived(QSystemTrayIcon::ActivationReason))); + menu = new QMenu(QApplication::desktop()); + exitDirect = true; +} + +void TrayIcon::iconIsActived(QSystemTrayIcon::ActivationReason reason) +{ + switch (reason) { + case QSystemTrayIcon::Trigger: + case QSystemTrayIcon::DoubleClick: { + mainWidget->showNormal(); + break; + } + + default: + break; + } +} + +bool TrayIcon::getVisible() const +{ + return trayIcon->isVisible(); +} + +void TrayIcon::setExitDirect(bool exitDirect) +{ + if (this->exitDirect != exitDirect) { + this->exitDirect = exitDirect; + } +} + +void TrayIcon::setMainWidget(QWidget *mainWidget) +{ + this->mainWidget = mainWidget; + menu->addAction("主界面", mainWidget, SLOT(showNormal())); + + if (exitDirect) { + menu->addAction("退出", this, SLOT(closeAll())); + } else { + menu->addAction("退出", this, SIGNAL(trayIconExit())); + } + + trayIcon->setContextMenu(menu); +} + +void TrayIcon::showMessage(const QString &title, const QString &msg, QSystemTrayIcon::MessageIcon icon, int msecs) +{ + trayIcon->showMessage(title, msg, icon, msecs); +} + +void TrayIcon::setIcon(const QString &strIcon) +{ + trayIcon->setIcon(QIcon(strIcon)); +} + +void TrayIcon::setToolTip(const QString &tip) +{ + trayIcon->setToolTip(tip); +} + +void TrayIcon::setVisible(bool visible) +{ + trayIcon->setVisible(visible); +} + +void TrayIcon::closeAll() +{ + trayIcon->hide(); + trayIcon->deleteLater(); + qApp->exit(); +} diff --git a/live/livetool/trayicon.h b/live/livetool/trayicon.h new file mode 100644 index 0000000..8487d81 --- /dev/null +++ b/live/livetool/trayicon.h @@ -0,0 +1,72 @@ +#ifndef TRAYICON_H +#define TRAYICON_H + +/** + * 托盘图标控件 作者:feiyangqingyun(QQ:517216493) 2017-1-8 + * 1:可设置托盘图标对应所属主窗体 + * 2:可设置托盘图标 + * 3:可设置提示信息 + * 4:自带右键菜单 + */ + +#include +#include + +class QMenu; + +#ifdef quc +#if (QT_VERSION < QT_VERSION_CHECK(5,7,0)) +#include +#else +#include +#endif + +class QDESIGNER_WIDGET_EXPORT TrayIcon : public QObject +#else +class TrayIcon : public QObject +#endif + +{ + Q_OBJECT +public: + static TrayIcon *Instance(); + explicit TrayIcon(QObject *parent = 0); + +private: + static QScopedPointer self; + QWidget *mainWidget; //对应所属主窗体 + QSystemTrayIcon *trayIcon; //托盘对象 + QMenu *menu; //右键菜单 + bool exitDirect; //是否直接退出 + +private slots: + void iconIsActived(QSystemTrayIcon::ActivationReason reason); + +public: + bool getVisible() const; + +public Q_SLOTS: + //设置是否直接退出,如果不是直接退出则发送信号给主界面 + void setExitDirect(bool exitDirect); + + //设置所属主窗体 + void setMainWidget(QWidget *mainWidget); + + //显示消息 + void showMessage(const QString &title, const QString &msg, + QSystemTrayIcon::MessageIcon icon = QSystemTrayIcon::Information, int msecs = 5000); + + //设置图标 + void setIcon(const QString &strIcon); + //设置提示信息 + void setToolTip(const QString &tip); + //设置是否可见 + void setVisible(bool visible); + //退出所有 + void closeAll(); + +Q_SIGNALS: + void trayIconExit(); +}; + +#endif // TRAYICON_H diff --git a/live/snap/QQ截图20190302141124.png b/live/snap/QQ截图20190302141124.png new file mode 100644 index 0000000..b09a677 Binary files /dev/null and b/live/snap/QQ截图20190302141124.png differ diff --git a/live/snap/QQ截图20190302141129.png b/live/snap/QQ截图20190302141129.png new file mode 100644 index 0000000..29e2f25 Binary files /dev/null and b/live/snap/QQ截图20190302141129.png differ diff --git a/live/snap/QQ截图20190302141147.png b/live/snap/QQ截图20190302141147.png new file mode 100644 index 0000000..901349e Binary files /dev/null and b/live/snap/QQ截图20190302141147.png differ