diff --git a/src/thread_ipc.cpp b/src/thread_ipc.cpp new file mode 100644 index 0000000..7a2b8ca --- /dev/null +++ b/src/thread_ipc.cpp @@ -0,0 +1,136 @@ +/////////////////////////////////////////////////////////////////////////////// +// Simple x264 Launcher +// Copyright (C) 2004-2012 LoRd_MuldeR +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// http://www.gnu.org/licenses/gpl-2.0.txt +/////////////////////////////////////////////////////////////////////////////// + +#include "thread_ipc.h" +#include "global.h" + +#include +#include + +static const char* s_key[3] = +{ + "{53F0CAC8-75BC-449A-91DF-2417B2867087}", + "{20BD6A5F-B510-4764-937D-EE6598271801}", + "{F09C3D10-EC27-4F4D-BF9C-9957A23B8A70}" +}; + +IPCThread::IPCThread(void) +{ + m_ipcReady = m_firstInstance = m_abort = false; + + m_semaphore_r = new QSystemSemaphore(QString::fromLatin1(s_key[0]), 0); + m_semaphore_w = new QSystemSemaphore(QString::fromLatin1(s_key[1]), 1); + m_sharedMem = new QSharedMemory(QString::fromLatin1(s_key[2])); +} + +IPCThread::~IPCThread(void) +{ + X264_DELETE(m_semaphore_r); + X264_DELETE(m_semaphore_w); + X264_DELETE(m_sharedMem); +} + +bool IPCThread::initialize(bool *firstInstance) +{ + if(!m_ipcReady) + { + if((m_semaphore_r->error() == 0) && (m_semaphore_w->error() == 0) && (m_sharedMem->error() == 0)) + { + if(m_sharedMem->create(sizeof(DWORD), QSharedMemory::ReadWrite)) + { + m_firstInstance = m_ipcReady = true; + } + else + { + if(m_sharedMem->attach(QSharedMemory::ReadWrite)) + { + m_ipcReady = true; + } + } + } + } + + if(firstInstance) + { + *firstInstance = m_firstInstance; + } + + return m_ipcReady; +} + +void IPCThread::notifyOtherInstance(void) +{ + if(!m_firstInstance) + { + m_semaphore_w->acquire(); + DWORD *pidPtr = reinterpret_cast(m_sharedMem->data()); + *pidPtr = GetCurrentProcessId(); + m_semaphore_r->release(); + } +} + +void IPCThread::start(Priority priority) +{ + m_abort = false; + + if(!m_ipcReady) + { + throw "IPC not initialized yet !!!"; + return; + } + + if(!m_firstInstance) + { + qWarning("This is NOT the first instance!"); + return; + } + + QThread::start(priority); +} + +void IPCThread::setAbort(void) +{ + m_abort = true; + if(m_semaphore_r) + { + m_semaphore_r->release(); + } +} + +void IPCThread::run(void) +{ + forever + { + if(!m_semaphore_r->acquire()) + { + qWarning("IPCThread: System error !!!"); + qWarning("IPCThread: %s\n", m_semaphore_r->errorString().toLatin1().constData()); + break; + } + if(m_abort) + { + break; + } + const DWORD procId = *reinterpret_cast(m_sharedMem->constData()); + m_semaphore_w->release(); + emit instanceCreated(procId); + } +} diff --git a/src/thread_ipc.h b/src/thread_ipc.h new file mode 100644 index 0000000..25f4d10 --- /dev/null +++ b/src/thread_ipc.h @@ -0,0 +1,59 @@ +/////////////////////////////////////////////////////////////////////////////// +// Simple x264 Launcher +// Copyright (C) 2004-2012 LoRd_MuldeR +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// http://www.gnu.org/licenses/gpl-2.0.txt +/////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "global.h" +#include + +class QSystemSemaphore; +class QSharedMemory; + +class IPCThread : public QThread +{ + Q_OBJECT + +public: + IPCThread(void); + ~IPCThread(void); + + void setAbort(void); + bool initialize(bool *firstInstance = NULL); + void notifyOtherInstance(void); + +signals: + void instanceCreated(DWORD pid); + +public slots: + void start(Priority priority = InheritPriority); + +protected: + volatile bool m_abort; + + QSystemSemaphore *m_semaphore_r; + QSystemSemaphore *m_semaphore_w; + QSharedMemory *m_sharedMem; + + bool m_ipcReady; + bool m_firstInstance; + + virtual void run(void); +}; diff --git a/src/version.h b/src/version.h index ef718a6..bdc738b 100644 --- a/src/version.h +++ b/src/version.h @@ -22,7 +22,7 @@ #define VER_X264_MAJOR 2 #define VER_X264_MINOR 0 #define VER_X264_PATCH 2 -#define VER_X264_BUILD 222 +#define VER_X264_BUILD 238 #define VER_X264_MINIMUM_REV 2146 #define VER_X264_CURRENT_API 120 diff --git a/src/win_main.cpp b/src/win_main.cpp index f29ab02..fcb3b0f 100644 --- a/src/win_main.cpp +++ b/src/win_main.cpp @@ -72,6 +72,7 @@ MainWindow::MainWindow(const x264_cpu_t *const cpuFeatures) //Register meta types qRegisterMetaType("QUuid"); + qRegisterMetaType("DWORD"); qRegisterMetaType("EncodeThread::JobStatus"); //Load preferences @@ -82,6 +83,10 @@ MainWindow::MainWindow(const x264_cpu_t *const cpuFeatures) m_options = new OptionsModel(); OptionsModel::loadTemplate(m_options, QString::fromLatin1(tpl_last)); + //Create IPC thread object + m_ipcThread = new IPCThread(); + connect(m_ipcThread, SIGNAL(instanceCreated(DWORD)), this, SLOT(instanceCreated(DWORD)), Qt::QueuedConnection); + //Freeze minimum size setMinimumSize(size()); splitter->setSizes(QList() << 16 << 196); @@ -177,6 +182,18 @@ MainWindow::~MainWindow(void) QFile *temp = m_toolsList.takeFirst(); X264_DELETE(temp); } + + if(m_ipcThread->isRunning()) + { + m_ipcThread->setAbort(); + if(!m_ipcThread->wait(5000)) + { + m_ipcThread->terminate(); + m_ipcThread->wait(); + } + } + + X264_DELETE(m_ipcThread); } /////////////////////////////////////////////////////////////////////////////// @@ -617,6 +634,18 @@ void MainWindow::init(void) updateLabelPos(); + //Check for a running instance + bool firstInstance = false; + if(m_ipcThread->initialize(&firstInstance)) + { + if(!firstInstance) + { + m_ipcThread->notifyOtherInstance(); + close(); qApp->exit(-1); return; + } + m_ipcThread->start(); + } + //Check all binaries while(!binaries.isEmpty()) { @@ -800,6 +829,24 @@ void MainWindow::handleDroppedFiles(void) qDebug("Leave from MainWindow::handleDroppedFiles!"); } +void MainWindow::instanceCreated(DWORD pid) +{ + qDebug("Notification from other instance received!"); + + FLASHWINFO flashWinInfo; + memset(&flashWinInfo, 0, sizeof(FLASHWINFO)); + flashWinInfo.cbSize = sizeof(FLASHWINFO); + flashWinInfo.hwnd = this->winId(); + flashWinInfo.dwFlags = FLASHW_ALL; + flashWinInfo.dwTimeout = 125; + flashWinInfo.uCount = 5; + + SwitchToThisWindow(this->winId(), TRUE); + SetForegroundWindow(this->winId()); + qApp->processEvents(); + FlashWindowEx(&flashWinInfo); +} + /////////////////////////////////////////////////////////////////////////////// // Event functions /////////////////////////////////////////////////////////////////////////////// diff --git a/src/win_main.h b/src/win_main.h index e6a85bb..97223e3 100644 --- a/src/win_main.h +++ b/src/win_main.h @@ -22,6 +22,7 @@ #pragma once #include "uic_win_main.h" +#include "thread_ipc.h" #include "thread_encode.h" #include "win_preferences.h" #include "global.h" @@ -51,6 +52,7 @@ protected: private: bool m_firstShow; QLabel *m_label; + IPCThread *m_ipcThread; JobListModel *m_jobList; OptionsModel *m_options; @@ -76,6 +78,7 @@ private slots: void copyLogToClipboard(bool checked); void handleDroppedFiles(void); void init(void); + void instanceCreated(DWORD pid); void jobSelected(const QModelIndex & current, const QModelIndex & previous); void jobChangedData(const QModelIndex &top, const QModelIndex &bottom); void jobLogExtended(const QModelIndex & parent, int start, int end); diff --git a/x264_launcher.vcxproj b/x264_launcher.vcxproj index 299f221..335fcfd 100644 --- a/x264_launcher.vcxproj +++ b/x264_launcher.vcxproj @@ -248,6 +248,14 @@ copy "$(SolutionDir)res\toolset\*.exe" "$(SolutionDir)bin\$(Configuration)\tools + + "$(QTDIR)\bin\moc.exe" -o "$(SolutionDir)tmp\moc\moc_%(Filename).cpp" "%(FullPath)" + "$(QTDIR)\bin\moc.exe" -o "$(SolutionDir)tmp\moc\moc_%(Filename).cpp" "%(FullPath)" + MOC "$(SolutionDir)tmp\moc\moc_%(Filename).cpp" + MOC "$(SolutionDir)tmp\moc\moc_%(Filename).cpp" + $(SolutionDir)tmp\moc\moc_%(Filename).cpp;%(Outputs) + $(SolutionDir)tmp\moc\moc_%(Filename).cpp;%(Outputs) + "$(QTDIR)\bin\moc.exe" -o "$(SolutionDir)tmp\moc\moc_%(Filename).cpp" "%(FullPath)" @@ -266,6 +274,7 @@ copy "$(SolutionDir)res\toolset\*.exe" "$(SolutionDir)bin\$(Configuration)\tools + @@ -274,6 +283,7 @@ copy "$(SolutionDir)res\toolset\*.exe" "$(SolutionDir)bin\$(Configuration)\tools + diff --git a/x264_launcher.vcxproj.filters b/x264_launcher.vcxproj.filters index 74ebb9e..5a2fe0a 100644 --- a/x264_launcher.vcxproj.filters +++ b/x264_launcher.vcxproj.filters @@ -113,6 +113,12 @@ Generated Files + + Source Files + + + Generated Files + @@ -157,6 +163,9 @@ Header Files + + Header Files +