# HG changeset patch # User Matti Hamalainen # Date 1521546321 -7200 # Node ID 37d5f432944967814b0d8478b024b630e1b1293b # Parent 07e7f254ef16ddd4bbac1c6c56ab58c7f511347f Implement single running instance check to prevent problems with the SQLite database. diff -r 07e7f254ef16 -r 37d5f4329449 Makefile.gen --- a/Makefile.gen Mon Mar 12 10:52:21 2018 +0200 +++ b/Makefile.gen Tue Mar 20 13:45:21 2018 +0200 @@ -25,7 +25,7 @@ APP_SRC=src/ APP_IMG=img/ APP_BIN=$(BINPATH)Syntilista$(EXEEXT) -APP_OBJS=main.o sqlmodels.o printing.o resources.o moc_main.o +APP_OBJS=main.o sqlmodels.o printing.o resources.o moc_main.o runguard.o APP_VERSION := $(shell cat VERSION) comma:= , APP_VERSION_COM := $(subst .,$(comma),$(APP_VERSION)) diff -r 07e7f254ef16 -r 37d5f4329449 src/main.cpp --- a/src/main.cpp Mon Mar 12 10:52:21 2018 +0200 +++ b/src/main.cpp Tue Mar 20 13:45:21 2018 +0200 @@ -15,6 +15,7 @@ #include "ui_editperson.h" #include "ui_aboutwindow.h" #include "ui_viewtransactions.h" +#include "runguard.h" // @@ -262,6 +263,20 @@ QApplication sapp(argc, argv); QSettings tmpst(APP_VENDOR, APP_ID); + // Check for multiple instances + RunGuard guard(QStringLiteral(APP_VENDOR) + QStringLiteral(APP_ID)); + if (!guard.tryToRun()) + { + slErrorMsg( + QObject::tr("Virhe!"), + QObject::tr( + "Syntilista-sovellus on jo käynnissä. Sulje tämä ikkuna ja " + "etsi ajossa oleva Syntilista-sovellus tehtäväpalkista." + ) + ); + return 1; + } + // Read configuration settings settings.uiPos = tmpst.value("pos", QPoint(100, 100)).toPoint(); settings.uiSize = tmpst.value("size", QSize(1000, 600)).toSize(); diff -r 07e7f254ef16 -r 37d5f4329449 src/runguard.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/runguard.cpp Tue Mar 20 13:45:21 2018 +0200 @@ -0,0 +1,88 @@ +// +// Taken and modified from https://stackoverflow.com/questions/5006547/qt-best-practice-for-a-single-instance-app-protection +// +#include "runguard.h" +#include + + +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()) + return false; + + memLock.acquire(); + const bool result = sharedMem.create(sizeof(quint64)); + memLock.release(); + + if (!result) + release(); + + return result; +} + + +void RunGuard::release() +{ + memLock.acquire(); + + if (sharedMem.isAttached()) + sharedMem.detach(); + + memLock.release(); +} diff -r 07e7f254ef16 -r 37d5f4329449 src/runguard.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/runguard.h Tue Mar 20 13:45:21 2018 +0200 @@ -0,0 +1,35 @@ +// +// Taken and modified from https://stackoverflow.com/questions/5006547/qt-best-practice-for-a-single-instance-app-protection +// +#ifndef RUNGUARD_H +#define RUNGUARD_H + +#include +#include +#include + + +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