diff --git a/main.cpp b/main.cpp index 0da08b4716e2300e6c6f5600b03101223dee4f1c..0acdeface14225f8ba8931ccaa19e0ca7c31d461 100644 --- a/main.cpp +++ b/main.cpp @@ -28,8 +28,6 @@ #include "media/text.h" #include "media/file.h" #include "globalinstances.h" -#include "pixbufmanipulator.h" -#include "lrcinstance.h" #include <QTranslator> #include <QLibraryInfo> @@ -37,7 +35,10 @@ #include <ciso646> +#include "lrcinstance.h" #include "utils.h" +#include "runguard.h" +#include "pixbufmanipulator.h" #ifdef Q_OS_WIN #include <windows.h> @@ -103,6 +104,10 @@ fileDebug(QFile& debugFile) int main(int argc, char *argv[]) { + RunGuard guard("680b3e5eaf"); + if (!guard.tryToRun()) + return 0; + #ifdef Q_OS_WIN SetProcessDPIAware(); #endif // Q_OS_WIN diff --git a/ring-client-windows.vcxproj b/ring-client-windows.vcxproj index d350393b31e2eaa33e08104b181ae090a96d346d..16aefc1f7f248c9ad712adc0db650930a6e3f0b2 100644 --- a/ring-client-windows.vcxproj +++ b/ring-client-windows.vcxproj @@ -259,6 +259,7 @@ <ClCompile Include="regnamedialog.cpp" /> <ClCompile Include="ringbutton.cpp" /> <ClCompile Include="ringcontactlineedit.cpp" /> + <ClCompile Include="runguard.cpp" /> <ClCompile Include="selectareadialog.cpp" /> <ClCompile Include="conversationsfilterwidget.cpp"> <OutputFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.\GeneratedFiles\$(ConfigurationName)\%(Filename).moc</OutputFile> @@ -399,6 +400,7 @@ <IncludePath Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.\GeneratedFiles\$(ConfigurationName)\.;.\GeneratedFiles;.;$(ProjectDir)..\daemon\contrib\msvc\include;$(ProjectDir)..\lrc\src;$(ProjectDir)..\client-windows\winsparkle\include;$(ProjectDir)..\client-windows\qrencode-win32\qrencode-win32;$(QTDIR)\include;$(QTDIR)\include\QtSvg;$(QTDIR)\include\QtWidgets;$(QTDIR)\include\QtWinExtras;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtXml;$(QTDIR)\include\QtNetwork;$(QTDIR)\include\QtCore;$(QTDIR)\mkspecs\win32-msvc;.\release</IncludePath> <Define Condition="'$(Configuration)|$(Platform)'=='Release|x64'">_WINDOWS;UNICODE;_UNICODE;WIN32;WIN64;NIGHTLY_VERSION=20180706;ENABLE_AUTOUPDATE;QT_NO_DEBUG;NDEBUG</Define> </QtMoc> + <ClInclude Include="runguard.h" /> <ClInclude Include="settingsitemwidget.h"> <IncludePath Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.\GeneratedFiles\$(ConfigurationName)\.;.\GeneratedFiles;.;$(ProjectDir)..\daemon\contrib\msvc\include;$(ProjectDir)..\lrc\src;$(ProjectDir)..\client-windows\winsparkle\include;$(ProjectDir)..\client-windows\qrencode-win32\qrencode-win32;$(QTDIR)\include;$(QTDIR)\include\QtSvg;$(QTDIR)\include\QtWidgets;$(QTDIR)\include\QtWinExtras;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtXml;$(QTDIR)\include\QtNetwork;$(QTDIR)\include\QtCore;$(QTDIR)\mkspecs\win32-msvc;.\release;$(QTDIR)\include\QtMultimedia;$(QTDIR)\include\QtMultimediaWidgets</IncludePath> <Define Condition="'$(Configuration)|$(Platform)'=='Release|x64'">_WINDOWS;UNICODE;_UNICODE;WIN32;WIN64;NIGHTLY_VERSION=20180706;ENABLE_AUTOUPDATE;QT_NO_DEBUG;NDEBUG;QT_MULTIMEDIA_LIB;QT_MULTIMEDIAWIDGETS_LIB</Define> diff --git a/ring-client-windows.vcxproj.filters b/ring-client-windows.vcxproj.filters index 71dc5d4cd57aae01c035040536398b42b7546896..2c61ba0b42cb048ab33c55bff4e2022762c007ef 100644 --- a/ring-client-windows.vcxproj.filters +++ b/ring-client-windows.vcxproj.filters @@ -198,6 +198,9 @@ <ClCompile Include="newwizardwidget.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="runguard.cpp"> + <Filter>Source Files</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <QtMoc Include="aboutdialog.h"> @@ -774,5 +777,8 @@ <ClInclude Include="version.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="runguard.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> </Project> \ No newline at end of file diff --git a/runguard.cpp b/runguard.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c79dfff89940c9dd9452e5f821f47803c54f665e --- /dev/null +++ b/runguard.cpp @@ -0,0 +1,79 @@ +// From: https://stackoverflow.com/a/28172162 + +#include "runguard.h" + +#include <QCryptographicHash> + +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(); +} \ No newline at end of file diff --git a/runguard.h b/runguard.h new file mode 100644 index 0000000000000000000000000000000000000000..c8878fec7bfb4d5a69501e87a7fad17e34a450d8 --- /dev/null +++ b/runguard.h @@ -0,0 +1,29 @@ +// From: https://stackoverflow.com/a/28172162 + +#pragma once + +#include <QObject> +#include <QSharedMemory> +#include <QSystemSemaphore> + +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) +}; \ No newline at end of file