diff --git a/Hv2ray.pro b/Hv2ray.pro index 48af9e0d..8afcaefa 100644 --- a/Hv2ray.pro +++ b/Hv2ray.pro @@ -34,7 +34,8 @@ SOURCES += \ vinteract.cpp \ db.cpp \ vmess.cpp \ - utils.cpp + utils.cpp \ + src/runguard.cpp HEADERS += \ mainwindow.h \ @@ -43,7 +44,8 @@ HEADERS += \ vinteract.h \ db.h \ vmess.h \ - utils.h + utils.h \ + src/runguard.h FORMS += \ mainwindow.ui \ diff --git a/src/main.cpp b/src/main.cpp index 84f7add5..b9c68a5d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,7 +8,8 @@ #include #include #include - +#include +#include "runguard.h" void init() { @@ -40,6 +41,11 @@ void init() int main(int argc, char *argv[]) { QApplication a(argc, argv); + RunGuard guard("Hv2ray"); + if(!guard.tryToRun()) { + QMessageBox::critical(0, "Already running", "Another instance of Hv2ray is already running!", QMessageBox::Ok | QMessageBox::Default); + return 0; + } init(); MainWindow w; w.show(); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 9bbe52dc..c1df4c12 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -17,6 +17,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { + this->setWindowIcon(QIcon("Himeki.ico")); ui->setupUi(this); updateConfTable(); ui->configTable->setContextMenuPolicy(Qt::CustomContextMenu); diff --git a/src/runguard.cpp b/src/runguard.cpp new file mode 100644 index 00000000..a7c007df --- /dev/null +++ b/src/runguard.cpp @@ -0,0 +1,76 @@ +#include "runguard.h" +#include + +//from https://stackoverflow.com/a/28172162 +namespace +{ + + QString generateKeyHash( const QString& key, const QString& salt ) + { + QByteArray data; + data.append( key.toUtf8() ); + data.append( salt.toUtf8() ); + data = QCryptographicHash::hash( data, QCryptographicHash::Sha1 ).toHex(); + return data; + } + +} + + +RunGuard::RunGuard( const QString& key ) + : key( key ) + , memLockKey( generateKeyHash( key, "_memLockKey" ) ) + , sharedmemKey( generateKeyHash( key, "_sharedmemKey" ) ) + , sharedMem( sharedmemKey ) + , memLock( memLockKey, 1 ) +{ + memLock.acquire(); + { + QSharedMemory fix( sharedmemKey ); // Fix for *nix: http://habrahabr.ru/post/173281/ + fix.attach(); + } + memLock.release(); +} + +RunGuard::~RunGuard() +{ + release(); +} + +bool RunGuard::isAnotherRunning() +{ + if ( sharedMem.isAttached() ) { + return false; + } + memLock.acquire(); + const bool isRunning = sharedMem.attach(); + if ( isRunning ) { + sharedMem.detach(); + } + memLock.release(); + return isRunning; +} + +bool RunGuard::tryToRun() +{ + if ( isAnotherRunning() ) { // Extra check + return false; + } + memLock.acquire(); + const bool result = sharedMem.create( sizeof( quint64 ) ); + memLock.release(); + if ( !result ) { + release(); + return false; + } + return true; +} + +void RunGuard::release() +{ + memLock.acquire(); + if ( sharedMem.isAttached() ) { + sharedMem.detach(); + } + memLock.release(); +} diff --git a/src/runguard.h b/src/runguard.h new file mode 100644 index 00000000..555318b5 --- /dev/null +++ b/src/runguard.h @@ -0,0 +1,31 @@ +#ifndef RUNGUARD_H +#define RUNGUARD_H + +#include +#include +#include + +//from https://stackoverflow.com/a/28172162 +class RunGuard +{ + +public: + RunGuard( const QString& key ); + ~RunGuard(); + + bool isAnotherRunning(); + bool tryToRun(); + void release(); + +private: + const QString key; + const QString memLockKey; + const QString sharedmemKey; + + QSharedMemory sharedMem; + QSystemSemaphore memLock; + + Q_DISABLE_COPY( RunGuard ) +}; + +#endif // RUNGUARD_H