From a08c93d53a6bbee41b1da0dde043f3c9ef0f60e8 Mon Sep 17 00:00:00 2001 From: Mathew Sutcliffe Date: Wed, 12 Oct 2016 13:33:56 +0100 Subject: [PATCH] refs #756 Added class CProcessInfo to obtain a process name from its PID, and check if a process exists. --- src/blackmisc/processinfo.cpp | 62 +++++++++++++++++++++++++ src/blackmisc/processinfo.h | 67 +++++++++++++++++++++++++++ src/blackmisc/registermetadata.cpp | 2 + tests/blackmisc/testblackmiscmain.cpp | 5 ++ tests/blackmisc/testprocess.cpp | 43 +++++++++++++++++ tests/blackmisc/testprocess.h | 41 ++++++++++++++++ 6 files changed, 220 insertions(+) create mode 100644 src/blackmisc/processinfo.cpp create mode 100644 src/blackmisc/processinfo.h create mode 100644 tests/blackmisc/testprocess.cpp create mode 100644 tests/blackmisc/testprocess.h diff --git a/src/blackmisc/processinfo.cpp b/src/blackmisc/processinfo.cpp new file mode 100644 index 000000000..c9872fb2c --- /dev/null +++ b/src/blackmisc/processinfo.cpp @@ -0,0 +1,62 @@ +/* Copyright (C) 2016 + * swift project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +#include "blackmisc/processinfo.h" +#include +#include +#include + +#if defined(Q_OS_OSX) +#include +#elif defined(Q_OS_WIN) +#include +#include +#endif + +namespace BlackMisc +{ + + QString CProcessInfo::convertToQString(bool) const + { + return QString("{ %1, %2 }").arg(QString::number(m_pid), m_name); + } + +#if defined(Q_OS_LINUX) + QString CProcessInfo::processNameFromId(qint64 pid) + { + QString path = QFileInfo(QString("/proc/%1/exe").arg(pid)).symLinkTarget(); + return QFileInfo(path).fileName(); + } +#elif defined(Q_OS_OSX) + QString CProcessInfo::processNameFromId(qint64 pid) + { + char name[1024]; + proc_name(pid, name, std::extent::value); + return name; + } +#elif defined(Q_OS_WIN) + QString CProcessInfo::processNameFromId(qint64 pid) + { + HANDLE proc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, static_cast(pid)); + if (! proc) { return ""; } + wchar_t path[1024]; + auto len = GetModuleFileNameEx(proc, nullptr, path, std::extent::value); + CloseHandle(proc); + if (len <= 0) { return ""; } + return QFileInfo(QString::fromWCharArray(path)).completeBaseName(); + } +#else + QString CProcessInfo::processNameFromId(qint64) + { + qFatal("Not implemented"); + return ""; + } +#endif + +} diff --git a/src/blackmisc/processinfo.h b/src/blackmisc/processinfo.h new file mode 100644 index 000000000..a4cbdce7f --- /dev/null +++ b/src/blackmisc/processinfo.h @@ -0,0 +1,67 @@ +/* Copyright (C) 2016 + * swift project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +//! \file + +#ifndef BLACKMISC_PROCESSINFO_H +#define BLACKMISC_PROCESSINFO_H + +#include "blackmisc/valueobject.h" +#include +#include + +namespace BlackMisc +{ + /*! + * Value class identifying a process, with a PID and a name. + */ + class BLACKMISC_EXPORT CProcessInfo : public CValueObject + { + public: + //! Construct an object identifying an invalid process. + CProcessInfo() {} + + //! Construct an object identifying the process with the given PID. + explicit CProcessInfo(qint64 pid) : m_pid(pid), m_name(processNameFromId(pid)) {} + + //! Construct an object identifying a process with the given PID and name. + CProcessInfo(qint64 pid, const QString &name) : m_pid(pid), m_name(name) {} + + //! Return an object identifying the current process. + static CProcessInfo currentProcess() { return CProcessInfo(QCoreApplication::applicationPid()); } + + //! True if this object identifies a process that exists. + bool exists() const { return ! m_name.isEmpty() && *this == CProcessInfo(m_pid); } + + //! Get the pid. + qint64 processId() const { return m_pid; } + + //! Get the process name. + const QString &processName() const { return m_name; } + + //! \copydoc BlackMisc::Mixin::String::toQString + QString convertToQString(bool i18n = false) const; + + private: + static QString processNameFromId(qint64 pid); + + qint64 m_pid = 0; + QString m_name; + + BLACK_METACLASS( + CProcessInfo, + BLACK_METAMEMBER(pid), + BLACK_METAMEMBER(name) + ); + }; +} + +Q_DECLARE_METATYPE(BlackMisc::CProcessInfo) + +#endif diff --git a/src/blackmisc/registermetadata.cpp b/src/blackmisc/registermetadata.cpp index ee5eec55a..374f8d0ab 100644 --- a/src/blackmisc/registermetadata.cpp +++ b/src/blackmisc/registermetadata.cpp @@ -28,6 +28,7 @@ #include "blackmisc/network/registermetadatanetwork.h" #include "blackmisc/pixmap.h" #include "blackmisc/pq/registermetadatapq.h" +#include "blackmisc/processinfo.h" #include "blackmisc/propertyindex.h" #include "blackmisc/propertyindexlist.h" #include "blackmisc/propertyindexvariantmap.h" @@ -71,6 +72,7 @@ namespace BlackMisc CNameVariantPair::registerMetadata(); CNameVariantPairList::registerMetadata(); CPixmap::registerMetadata(); + CProcessInfo::registerMetadata(); CPropertyIndex::registerMetadata(); CPropertyIndex::registerMetadata(); CPropertyIndexList::registerMetadata(); diff --git a/tests/blackmisc/testblackmiscmain.cpp b/tests/blackmisc/testblackmiscmain.cpp index 2ce9842cf..314951321 100644 --- a/tests/blackmisc/testblackmiscmain.cpp +++ b/tests/blackmisc/testblackmiscmain.cpp @@ -23,6 +23,7 @@ #include "testlibrarypath.h" #include "testmath.h" #include "testphysicalquantities.h" +#include "testprocess.h" #include "testslot.h" #include "teststringutils.h" #include "testvaluecache.h" @@ -95,6 +96,10 @@ namespace BlackMiscTest CTestLibraryPath libraryPathTests; status |= test.exec(&libraryPathTests, "blackmisc_librarypath"); } + { + CTestProcess processTests; + status |= test.exec(&processTests, "blackmisc_process"); + } return status; } } // namespace diff --git a/tests/blackmisc/testprocess.cpp b/tests/blackmisc/testprocess.cpp new file mode 100644 index 000000000..2658a7121 --- /dev/null +++ b/tests/blackmisc/testprocess.cpp @@ -0,0 +1,43 @@ +/* Copyright (C) 2016 + * swift Project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +//! \cond PRIVATE_TESTS + +/*! +* \file +* \ingroup testblackmisc +*/ + +#include "testprocess.h" +#include "blackmisc/processinfo.h" + +#include +#include + +using namespace BlackMisc; + +namespace BlackMiscTest +{ + + void CTestProcess::processInfo() + { + CProcessInfo invalid; + QVERIFY2(! invalid.exists(), "Invalid process shall not exist"); + + CProcessInfo current1(CProcessInfo::currentProcess()); + CProcessInfo current2(QCoreApplication::applicationPid()); + CProcessInfo current3(QCoreApplication::applicationPid(), QCoreApplication::applicationName()); + QVERIFY2(current1.exists(), "Current process shall exist"); + QVERIFY2(current1 == current2, "Current process equals process with current PID"); + QVERIFY2(current1 == current3, "Current process equals process with current PID and name"); + } + +} + +//! \endcond diff --git a/tests/blackmisc/testprocess.h b/tests/blackmisc/testprocess.h new file mode 100644 index 000000000..e3df08a9e --- /dev/null +++ b/tests/blackmisc/testprocess.h @@ -0,0 +1,41 @@ +/* Copyright (C) 2016 + * swift project community / contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +#ifndef BLACKMISCTEST_TESTPROCESS_H +#define BLACKMISCTEST_TESTPROCESS_H + +//! \cond PRIVATE_TESTS + +/*! +* \file +* \ingroup testblackmisc +*/ + +#include + +namespace BlackMiscTest +{ + //! Testing process tools + class CTestProcess : public QObject + { + Q_OBJECT + + public: + //! Constructor + explicit CTestProcess(QObject *parent = nullptr) : QObject(parent) {} + + private slots: + //! Process info tests + void processInfo(); + }; +} + +//! \endcond + +#endif