Added support for handling multiple instances.

This commit is contained in:
LoRd_MuldeR 2012-02-21 00:37:31 +01:00
parent 9a7ddf16c4
commit ff3f5516d8
7 changed files with 265 additions and 1 deletions

136
src/thread_ipc.cpp Normal file
View File

@ -0,0 +1,136 @@
///////////////////////////////////////////////////////////////////////////////
// Simple x264 Launcher
// Copyright (C) 2004-2012 LoRd_MuldeR <MuldeR2@GMX.de>
//
// 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 <QSystemSemaphore>
#include <QSharedMemory>
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<DWORD*>(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<const DWORD*>(m_sharedMem->constData());
m_semaphore_w->release();
emit instanceCreated(procId);
}
}

59
src/thread_ipc.h Normal file
View File

@ -0,0 +1,59 @@
///////////////////////////////////////////////////////////////////////////////
// Simple x264 Launcher
// Copyright (C) 2004-2012 LoRd_MuldeR <MuldeR2@GMX.de>
//
// 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 <QThread>
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);
};

View File

@ -22,7 +22,7 @@
#define VER_X264_MAJOR 2 #define VER_X264_MAJOR 2
#define VER_X264_MINOR 0 #define VER_X264_MINOR 0
#define VER_X264_PATCH 2 #define VER_X264_PATCH 2
#define VER_X264_BUILD 222 #define VER_X264_BUILD 238
#define VER_X264_MINIMUM_REV 2146 #define VER_X264_MINIMUM_REV 2146
#define VER_X264_CURRENT_API 120 #define VER_X264_CURRENT_API 120

View File

@ -72,6 +72,7 @@ MainWindow::MainWindow(const x264_cpu_t *const cpuFeatures)
//Register meta types //Register meta types
qRegisterMetaType<QUuid>("QUuid"); qRegisterMetaType<QUuid>("QUuid");
qRegisterMetaType<QUuid>("DWORD");
qRegisterMetaType<EncodeThread::JobStatus>("EncodeThread::JobStatus"); qRegisterMetaType<EncodeThread::JobStatus>("EncodeThread::JobStatus");
//Load preferences //Load preferences
@ -82,6 +83,10 @@ MainWindow::MainWindow(const x264_cpu_t *const cpuFeatures)
m_options = new OptionsModel(); m_options = new OptionsModel();
OptionsModel::loadTemplate(m_options, QString::fromLatin1(tpl_last)); 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 //Freeze minimum size
setMinimumSize(size()); setMinimumSize(size());
splitter->setSizes(QList<int>() << 16 << 196); splitter->setSizes(QList<int>() << 16 << 196);
@ -177,6 +182,18 @@ MainWindow::~MainWindow(void)
QFile *temp = m_toolsList.takeFirst(); QFile *temp = m_toolsList.takeFirst();
X264_DELETE(temp); 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(); 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 //Check all binaries
while(!binaries.isEmpty()) while(!binaries.isEmpty())
{ {
@ -800,6 +829,24 @@ void MainWindow::handleDroppedFiles(void)
qDebug("Leave from MainWindow::handleDroppedFiles!"); 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 // Event functions
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////

View File

@ -22,6 +22,7 @@
#pragma once #pragma once
#include "uic_win_main.h" #include "uic_win_main.h"
#include "thread_ipc.h"
#include "thread_encode.h" #include "thread_encode.h"
#include "win_preferences.h" #include "win_preferences.h"
#include "global.h" #include "global.h"
@ -51,6 +52,7 @@ protected:
private: private:
bool m_firstShow; bool m_firstShow;
QLabel *m_label; QLabel *m_label;
IPCThread *m_ipcThread;
JobListModel *m_jobList; JobListModel *m_jobList;
OptionsModel *m_options; OptionsModel *m_options;
@ -76,6 +78,7 @@ private slots:
void copyLogToClipboard(bool checked); void copyLogToClipboard(bool checked);
void handleDroppedFiles(void); void handleDroppedFiles(void);
void init(void); void init(void);
void instanceCreated(DWORD pid);
void jobSelected(const QModelIndex & current, const QModelIndex & previous); void jobSelected(const QModelIndex & current, const QModelIndex & previous);
void jobChangedData(const QModelIndex &top, const QModelIndex &bottom); void jobChangedData(const QModelIndex &top, const QModelIndex &bottom);
void jobLogExtended(const QModelIndex & parent, int start, int end); void jobLogExtended(const QModelIndex & parent, int start, int end);

View File

@ -248,6 +248,14 @@ copy "$(SolutionDir)res\toolset\*.exe" "$(SolutionDir)bin\$(Configuration)\tools
<ClInclude Include="src\model_options.h" /> <ClInclude Include="src\model_options.h" />
<ClInclude Include="src\targetver.h" /> <ClInclude Include="src\targetver.h" />
<ClInclude Include="src\taskbar7.h" /> <ClInclude Include="src\taskbar7.h" />
<CustomBuild Include="src\thread_ipc.h">
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\moc.exe" -o "$(SolutionDir)tmp\moc\moc_%(Filename).cpp" "%(FullPath)"</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(QTDIR)\bin\moc.exe" -o "$(SolutionDir)tmp\moc\moc_%(Filename).cpp" "%(FullPath)"</Command>
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">MOC "$(SolutionDir)tmp\moc\moc_%(Filename).cpp"</Message>
<Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MOC "$(SolutionDir)tmp\moc\moc_%(Filename).cpp"</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)tmp\moc\moc_%(Filename).cpp;%(Outputs)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)tmp\moc\moc_%(Filename).cpp;%(Outputs)</Outputs>
</CustomBuild>
<ClInclude Include="src\version.h" /> <ClInclude Include="src\version.h" />
<CustomBuild Include="src\win_main.h"> <CustomBuild Include="src\win_main.h">
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\moc.exe" -o "$(SolutionDir)tmp\moc\moc_%(Filename).cpp" "%(FullPath)"</Command> <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\moc.exe" -o "$(SolutionDir)tmp\moc\moc_%(Filename).cpp" "%(FullPath)"</Command>
@ -266,6 +274,7 @@ copy "$(SolutionDir)res\toolset\*.exe" "$(SolutionDir)bin\$(Configuration)\tools
<ClCompile Include="src\thread_encode.cpp" /> <ClCompile Include="src\thread_encode.cpp" />
<ClCompile Include="src\global.cpp" /> <ClCompile Include="src\global.cpp" />
<ClCompile Include="src\main.cpp" /> <ClCompile Include="src\main.cpp" />
<ClCompile Include="src\thread_ipc.cpp" />
<ClCompile Include="src\win_addJob.cpp" /> <ClCompile Include="src\win_addJob.cpp" />
<ClCompile Include="src\win_editor.cpp" /> <ClCompile Include="src\win_editor.cpp" />
<ClCompile Include="src\win_help.cpp" /> <ClCompile Include="src\win_help.cpp" />
@ -274,6 +283,7 @@ copy "$(SolutionDir)res\toolset\*.exe" "$(SolutionDir)bin\$(Configuration)\tools
<ClCompile Include="tmp\moc\moc_model_jobList.cpp" /> <ClCompile Include="tmp\moc\moc_model_jobList.cpp" />
<ClCompile Include="tmp\moc\moc_model_logFile.cpp" /> <ClCompile Include="tmp\moc\moc_model_logFile.cpp" />
<ClCompile Include="tmp\moc\moc_thread_encode.cpp" /> <ClCompile Include="tmp\moc\moc_thread_encode.cpp" />
<ClCompile Include="tmp\moc\moc_thread_ipc.cpp" />
<ClCompile Include="tmp\moc\moc_win_addJob.cpp" /> <ClCompile Include="tmp\moc\moc_win_addJob.cpp" />
<ClCompile Include="tmp\moc\moc_win_editor.cpp" /> <ClCompile Include="tmp\moc\moc_win_editor.cpp" />
<ClCompile Include="tmp\moc\moc_win_help.cpp" /> <ClCompile Include="tmp\moc\moc_win_help.cpp" />

View File

@ -113,6 +113,12 @@
<ClCompile Include="tmp\moc\moc_win_editor.cpp"> <ClCompile Include="tmp\moc\moc_win_editor.cpp">
<Filter>Generated Files</Filter> <Filter>Generated Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="src\thread_ipc.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="tmp\moc\moc_thread_ipc.cpp">
<Filter>Generated Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<CustomBuild Include="src\win_main.h"> <CustomBuild Include="src\win_main.h">
@ -157,6 +163,9 @@
<CustomBuild Include="src\win_editor.h"> <CustomBuild Include="src\win_editor.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</CustomBuild> </CustomBuild>
<CustomBuild Include="src\thread_ipc.h">
<Filter>Header Files</Filter>
</CustomBuild>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ResourceCompile Include="x264_launcher.rc"> <ResourceCompile Include="x264_launcher.rc">