diff --git a/MUtilities_VS2013.vcxproj b/MUtilities_VS2013.vcxproj
index a1f9d34..a0fab79 100644
--- a/MUtilities_VS2013.vcxproj
+++ b/MUtilities_VS2013.vcxproj
@@ -24,6 +24,7 @@
+
@@ -39,6 +40,7 @@
+
diff --git a/MUtilities_VS2013.vcxproj.filters b/MUtilities_VS2013.vcxproj.filters
index 272fdb4..657655d 100644
--- a/MUtilities_VS2013.vcxproj.filters
+++ b/MUtilities_VS2013.vcxproj.filters
@@ -78,6 +78,9 @@
Source Files
+
+ Source Files
+
@@ -131,6 +134,9 @@
Public Headers
+
+ Public Headers
+
diff --git a/include/MUtils/IPCChannel.h b/include/MUtils/IPCChannel.h
new file mode 100644
index 0000000..a175bca
--- /dev/null
+++ b/include/MUtils/IPCChannel.h
@@ -0,0 +1,58 @@
+///////////////////////////////////////////////////////////////////////////////
+// MuldeR's Utilities for Qt
+// Copyright (C) 2004-2014 LoRd_MuldeR
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library 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
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+//
+// http://www.gnu.org/licenses/lgpl-2.1.txt
+//////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#include
+
+namespace MUtils
+{
+ typedef enum
+ {
+ IPC_RET_SUCCESS_MASTER = 0,
+ IPC_RET_SUCCESS_SLAVE = 1,
+ IPC_RET_ALREADY_INITIALIZED = 2,
+ IPC_RET_FAILURE = 3
+ }
+ ipc_result_t;
+
+ class MUTILS_API IPCChannel_Private;
+
+ class MUTILS_API IPCChannel
+ {
+ public:
+ IPCChannel(const QString &applicationId, const QString &channelId);
+ ~IPCChannel(void);
+
+ int initialize(void);
+
+ bool send(const unsigned int &command, const char *const message);
+ bool read(unsigned int &command, char *const message, const size_t &buffSize);
+
+ private:
+ IPCChannel(const IPCChannel&) : p(NULL) {}
+ IPCChannel &operator=(const IPCChannel&) { return *this; }
+
+ IPCChannel_Private *const p;
+ const QString m_applicationId;
+ const QString m_channelId;
+ };
+}
diff --git a/include/MUtils/JobObject.h b/include/MUtils/JobObject.h
index 62fb4be..b6b47ad 100644
--- a/include/MUtils/JobObject.h
+++ b/include/MUtils/JobObject.h
@@ -22,7 +22,6 @@
#pragma once
#include
-#include
class QProcess;
@@ -40,6 +39,6 @@ namespace MUtils
bool terminateJob(unsigned int exitCode);
private:
- QScopedPointer p;
+ JobObject_Private *const p;
};
}
diff --git a/src/IPCChannel.cpp b/src/IPCChannel.cpp
new file mode 100644
index 0000000..9aab938
--- /dev/null
+++ b/src/IPCChannel.cpp
@@ -0,0 +1,337 @@
+///////////////////////////////////////////////////////////////////////////////
+// MuldeR's Utilities for Qt
+// Copyright (C) 2004-2014 LoRd_MuldeR
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library 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
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+//
+// http://www.gnu.org/licenses/lgpl-2.1.txt
+//////////////////////////////////////////////////////////////////////////////////
+
+//MUtils
+#include
+#include
+
+//Qt includes
+#include
+#include
+#include
+#include
+
+///////////////////////////////////////////////////////////////////////////////
+// TYPES
+///////////////////////////////////////////////////////////////////////////////
+
+namespace MUtils
+{
+ static const size_t IPC_SLOTS = 128;
+ static const size_t MAX_MESSAGE_LEN = 4096;
+
+ typedef struct
+ {
+ unsigned int command;
+ unsigned int reserved_1;
+ unsigned int reserved_2;
+ char parameter[MAX_MESSAGE_LEN];
+ }
+ ipc_data_t;
+
+ typedef struct
+ {
+ unsigned int pos_wr;
+ unsigned int pos_rd;
+ ipc_data_t data[IPC_SLOTS];
+ }
+ ipc_t;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// UTILITIES
+///////////////////////////////////////////////////////////////////////////////
+
+static inline QString ESCAPE(QString str)
+{
+ return str.replace(QRegExp("[^A-Za-z0-9_]"), "_").toLower();
+}
+
+static QString MAKE_ID(const QString &applicationId, const QString &channelId, const QString &itemId)
+{
+ return QString("ipc://mutilities.muldersoft.com:37402/%1/%2/%3").arg(ESCAPE(applicationId), ESCAPE(channelId), ESCAPE(itemId));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// PRIVATE DATA
+///////////////////////////////////////////////////////////////////////////////
+
+namespace MUtils
+{
+ class IPCChannel_Private
+ {
+ friend class IPCChannel;
+
+ protected:
+ volatile bool initialized;
+ QScopedPointer sharedmem;
+ QScopedPointer semaphore_rd;
+ QScopedPointer semaphore_wr;
+ QReadWriteLock lock;
+ };
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CONSTRUCTOR & DESTRUCTOR
+///////////////////////////////////////////////////////////////////////////////
+
+MUtils::IPCChannel::IPCChannel(const QString &applicationId, const QString &channelId)
+:
+ p(new IPCChannel_Private()),
+ m_applicationId(applicationId),
+ m_channelId(channelId)
+{
+ p->initialized = false;
+}
+
+MUtils::IPCChannel::~IPCChannel(void)
+{
+ if(p->initialized)
+ {
+ if(p->sharedmem->isAttached())
+ {
+ p->sharedmem->detach();
+ }
+ }
+
+ delete p;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// INITIALIZATION
+///////////////////////////////////////////////////////////////////////////////
+
+int MUtils::IPCChannel::initialize(void)
+{
+ QWriteLocker writeLock(&p->lock);
+
+ if(p->initialized)
+ {
+ return IPC_RET_ALREADY_INITIALIZED;
+ }
+
+ p->sharedmem.reset(new QSharedMemory(MAKE_ID(m_applicationId, m_channelId, "sharedmem"), NULL));
+ p->semaphore_rd.reset(new QSystemSemaphore(MAKE_ID(m_applicationId, m_channelId, "semaphore_rd"), 0));
+ p->semaphore_wr.reset(new QSystemSemaphore(MAKE_ID(m_applicationId, m_channelId, "semaphore_wr"), 0));
+
+ if(p->semaphore_rd->error() != QSystemSemaphore::NoError)
+ {
+ const QString errorMessage = p->semaphore_rd->errorString();
+ qWarning("Failed to create system smaphore: %s", MUTILS_UTF8(errorMessage));
+ return IPC_RET_FAILURE;
+ }
+
+ if(p->semaphore_wr->error() != QSystemSemaphore::NoError)
+ {
+ const QString errorMessage = p->semaphore_wr->errorString();
+ qWarning("Failed to create system smaphore: %s", MUTILS_UTF8(errorMessage));
+ return IPC_RET_FAILURE;
+ }
+
+ if(!p->sharedmem->create(sizeof(ipc_t)))
+ {
+ if(p->sharedmem->error() == QSharedMemory::AlreadyExists)
+ {
+ if(!p->sharedmem->attach())
+ {
+ const QString errorMessage = p->sharedmem->errorString();
+ qWarning("Failed to attach to shared memory: %s", MUTILS_UTF8(errorMessage));
+ return IPC_RET_FAILURE;
+ }
+ if(p->sharedmem->error() != QSharedMemory::NoError)
+ {
+ const QString errorMessage = p->sharedmem->errorString();
+ qWarning("Failed to attach to shared memory: %s", MUTILS_UTF8(errorMessage));
+ return IPC_RET_FAILURE;
+ }
+ p->initialized = true;
+ return IPC_RET_SUCCESS_SLAVE;
+ }
+ else
+ {
+ const QString errorMessage = p->sharedmem->errorString();
+ qWarning("Failed to create shared memory: %s", MUTILS_UTF8(errorMessage));
+ return IPC_RET_FAILURE;
+ }
+ }
+
+ if(p->sharedmem->error() != QSharedMemory::NoError)
+ {
+ const QString errorMessage = p->sharedmem->errorString();
+ qWarning("Failed to create shared memory: %s", MUTILS_UTF8(errorMessage));
+ return IPC_RET_FAILURE;
+ }
+
+ if(void *const data = p->sharedmem->data())
+ {
+ memset(data, 0, sizeof(ipc_t));
+ }
+
+ if(!p->semaphore_wr->release(IPC_SLOTS))
+ {
+ const QString errorMessage = p->semaphore_wr->errorString();
+ qWarning("Failed to release system semaphore: %s", MUTILS_UTF8(errorMessage));
+ return IPC_RET_FAILURE;
+ }
+
+ p->initialized = true;
+ return IPC_RET_SUCCESS_MASTER;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// SEND MESSAGE
+///////////////////////////////////////////////////////////////////////////////
+
+bool MUtils::IPCChannel::send(const unsigned int &command, const char *const message)
+{
+ bool success = false;
+ QReadLocker readLock(&p->lock);
+
+ if(!p->initialized)
+ {
+ MUTILS_THROW("Shared memory for IPC not initialized yet.");
+ }
+
+ ipc_data_t ipc_data;
+ memset(&ipc_data, 0, sizeof(ipc_data_t));
+ ipc_data.command = command;
+
+ if(message)
+ {
+ strncpy_s(ipc_data.parameter, MAX_MESSAGE_LEN, message, _TRUNCATE);
+ }
+
+ if(!p->semaphore_wr->acquire())
+ {
+ const QString errorMessage = p->semaphore_wr->errorString();
+ qWarning("Failed to acquire system semaphore: %s", MUTILS_UTF8(errorMessage));
+ return false;
+ }
+
+ if(!p->sharedmem->lock())
+ {
+ const QString errorMessage = p->sharedmem->errorString();
+ qWarning("Failed to lock shared memory: %s", MUTILS_UTF8(errorMessage));
+ return false;
+ }
+
+ if(ipc_t *const ptr = reinterpret_cast(p->sharedmem->data()))
+ {
+ success = true;
+ memcpy(&ptr->data[ptr->pos_wr], &ipc_data, sizeof(ipc_data_t));
+ ptr->pos_wr = (ptr->pos_wr + 1) % IPC_SLOTS;
+ }
+ else
+ {
+ qWarning("Shared memory pointer is NULL -> unable to write data!");
+ }
+
+ if(!p->sharedmem->unlock())
+ {
+ const QString errorMessage = p->sharedmem->errorString();
+ qWarning("Failed to unlock shared memory: %s", MUTILS_UTF8(errorMessage));
+ return false;
+ }
+
+ if(!p->semaphore_rd->release())
+ {
+ const QString errorMessage = p->semaphore_rd->errorString();
+ qWarning("Failed to acquire release semaphore: %s", MUTILS_UTF8(errorMessage));
+ return false;
+ }
+
+ return success;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// READ MESSAGE
+///////////////////////////////////////////////////////////////////////////////
+
+bool MUtils::IPCChannel::read(unsigned int &command, char *const message, const size_t &buffSize)
+{
+ bool success = false;
+ QReadLocker readLock(&p->lock);
+
+ command = 0;
+ if(message && (buffSize > 0))
+ {
+ message[0] = '\0';
+ }
+
+ if(!p->initialized)
+ {
+ MUTILS_THROW("Shared memory for IPC not initialized yet.");
+ }
+
+ ipc_data_t ipc_data;
+ memset(&ipc_data, 0, sizeof(ipc_data_t));
+
+ if(!p->semaphore_rd->acquire())
+ {
+ const QString errorMessage = p->semaphore_rd->errorString();
+ qWarning("Failed to acquire system semaphore: %s", MUTILS_UTF8(errorMessage));
+ return false;
+ }
+
+ if(!p->sharedmem->lock())
+ {
+ const QString errorMessage = p->sharedmem->errorString();
+ qWarning("Failed to lock shared memory: %s", MUTILS_UTF8(errorMessage));
+ return false;
+ }
+
+ if(ipc_t *const ptr = reinterpret_cast(p->sharedmem->data()))
+ {
+ success = true;
+ memcpy(&ipc_data, &ptr->data[ptr->pos_rd], sizeof(ipc_data_t));
+ ptr->pos_rd = (ptr->pos_rd + 1) % IPC_SLOTS;
+
+ if(!(ipc_data.reserved_1 || ipc_data.reserved_2))
+ {
+ command = ipc_data.command;
+ strncpy_s(message, buffSize, ipc_data.parameter, _TRUNCATE);
+ }
+ else
+ {
+ qWarning("Malformed IPC message, will be ignored");
+ }
+ }
+ else
+ {
+ qWarning("Shared memory pointer is NULL -> unable to write data!");
+ }
+
+ if(!p->sharedmem->unlock())
+ {
+ const QString errorMessage = p->sharedmem->errorString();
+ qWarning("Failed to unlock shared memory: %s", MUTILS_UTF8(errorMessage));
+ return false;
+ }
+
+ if(!p->semaphore_wr->release())
+ {
+ const QString errorMessage = p->semaphore_wr->errorString();
+ qWarning("Failed to acquire release semaphore: %s", MUTILS_UTF8(errorMessage));
+ return false;
+ }
+
+ return success;
+}
diff --git a/src/JobObject_Win32.cpp b/src/JobObject_Win32.cpp
index 51c1295..b39a54a 100644
--- a/src/JobObject_Win32.cpp
+++ b/src/JobObject_Win32.cpp
@@ -84,6 +84,8 @@ MUtils::JobObject::~JobObject(void)
CloseHandle(p->m_hJobObject);
p->m_hJobObject = NULL;
}
+
+ delete p;
}
bool MUtils::JobObject::addProcessToJob(const QProcess *proc)