mirror of
https://github.com/tnodir/fort
synced 2024-11-15 07:57:24 +00:00
UI: Remove service monitors
Driver will monitor the `svchost.exe`
This commit is contained in:
parent
01d0e2b8d3
commit
43aeab0b9b
@ -111,8 +111,6 @@ SOURCES += \
|
|||||||
rpc/windowmanagerfake.cpp \
|
rpc/windowmanagerfake.cpp \
|
||||||
serviceinfo/serviceinfo.cpp \
|
serviceinfo/serviceinfo.cpp \
|
||||||
serviceinfo/serviceinfomanager.cpp \
|
serviceinfo/serviceinfomanager.cpp \
|
||||||
serviceinfo/serviceinfomonitor.cpp \
|
|
||||||
serviceinfo/servicelistmonitor.cpp \
|
|
||||||
stat/quotamanager.cpp \
|
stat/quotamanager.cpp \
|
||||||
stat/statmanager.cpp \
|
stat/statmanager.cpp \
|
||||||
stat/statsql.cpp \
|
stat/statsql.cpp \
|
||||||
@ -266,8 +264,6 @@ HEADERS += \
|
|||||||
rpc/windowmanagerfake.h \
|
rpc/windowmanagerfake.h \
|
||||||
serviceinfo/serviceinfo.h \
|
serviceinfo/serviceinfo.h \
|
||||||
serviceinfo/serviceinfomanager.h \
|
serviceinfo/serviceinfomanager.h \
|
||||||
serviceinfo/serviceinfomonitor.h \
|
|
||||||
serviceinfo/servicelistmonitor.h \
|
|
||||||
stat/quotamanager.h \
|
stat/quotamanager.h \
|
||||||
stat/statmanager.h \
|
stat/statmanager.h \
|
||||||
stat/statsql.h \
|
stat/statsql.h \
|
||||||
|
@ -84,7 +84,6 @@ void FortManager::initialize()
|
|||||||
setupConfManager();
|
setupConfManager();
|
||||||
setupQuotaManager();
|
setupQuotaManager();
|
||||||
setupTaskManager();
|
setupTaskManager();
|
||||||
setupServiceInfoManager();
|
|
||||||
|
|
||||||
setupDriver();
|
setupDriver();
|
||||||
loadConf();
|
loadConf();
|
||||||
@ -287,13 +286,6 @@ void FortManager::setupTaskManager()
|
|||||||
IoC<ConfManager>(), &ConfManager::updateDriverZones);
|
IoC<ConfManager>(), &ConfManager::updateDriverZones);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FortManager::setupServiceInfoManager()
|
|
||||||
{
|
|
||||||
auto serviceInfoManager = IoC<ServiceInfoManager>();
|
|
||||||
|
|
||||||
serviceInfoManager->setMonitorEnabled(IoC<FortSettings>()->isMaster());
|
|
||||||
}
|
|
||||||
|
|
||||||
void FortManager::setupTranslationManager()
|
void FortManager::setupTranslationManager()
|
||||||
{
|
{
|
||||||
IoC<TranslationManager>()->switchLanguageByName(IoC<UserSettings>()->iniUser().language());
|
IoC<TranslationManager>()->switchLanguageByName(IoC<UserSettings>()->iniUser().language());
|
||||||
|
@ -46,7 +46,6 @@ private:
|
|||||||
void setupConfManager();
|
void setupConfManager();
|
||||||
void setupQuotaManager();
|
void setupQuotaManager();
|
||||||
void setupTaskManager();
|
void setupTaskManager();
|
||||||
void setupServiceInfoManager();
|
|
||||||
|
|
||||||
void setupTranslationManager();
|
void setupTranslationManager();
|
||||||
|
|
||||||
|
@ -5,9 +5,6 @@
|
|||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#include <qt_windows.h>
|
#include <qt_windows.h>
|
||||||
|
|
||||||
#include "serviceinfomonitor.h"
|
|
||||||
#include "servicelistmonitor.h"
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
const QLoggingCategory LC("serviceInfo.serviceInfoManager");
|
const QLoggingCategory LC("serviceInfo.serviceInfoManager");
|
||||||
@ -49,21 +46,6 @@ QVector<ServiceInfo> getServiceInfoList(SC_HANDLE mngr, DWORD state = SERVICE_ST
|
|||||||
|
|
||||||
ServiceInfoManager::ServiceInfoManager(QObject *parent) : QObject(parent) { }
|
ServiceInfoManager::ServiceInfoManager(QObject *parent) : QObject(parent) { }
|
||||||
|
|
||||||
ServiceInfoManager::~ServiceInfoManager()
|
|
||||||
{
|
|
||||||
clearServiceMonitors();
|
|
||||||
stopServiceListMonitor();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServiceInfoManager::setMonitorEnabled(bool v)
|
|
||||||
{
|
|
||||||
if (m_monitorEnabled != v) {
|
|
||||||
m_monitorEnabled = v;
|
|
||||||
|
|
||||||
setupServiceMonitors();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int ServiceInfoManager::groupIndexByName(const QString &name) const
|
int ServiceInfoManager::groupIndexByName(const QString &name) const
|
||||||
{
|
{
|
||||||
return m_serviceGroups.value(name, -1);
|
return m_serviceGroups.value(name, -1);
|
||||||
@ -80,114 +62,3 @@ QVector<ServiceInfo> ServiceInfoManager::loadServiceInfoList()
|
|||||||
}
|
}
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServiceInfoManager::setupServiceMonitors()
|
|
||||||
{
|
|
||||||
clearServiceMonitors();
|
|
||||||
|
|
||||||
if (!monitorEnabled())
|
|
||||||
return;
|
|
||||||
|
|
||||||
const SC_HANDLE mngr =
|
|
||||||
OpenSCManagerW(nullptr, nullptr, SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE);
|
|
||||||
if (!mngr) {
|
|
||||||
qCCritical(LC) << "Open manager error:" << GetLastError();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!m_serviceGroups.isEmpty()) {
|
|
||||||
const auto services = getServiceInfoList(mngr);
|
|
||||||
for (const auto &info : services) {
|
|
||||||
startServiceMonitor(info.serviceName, info.processId, mngr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
startServiceListMonitor(mngr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServiceInfoManager::clearServiceMonitors()
|
|
||||||
{
|
|
||||||
const auto monitors = m_serviceMonitors.values();
|
|
||||||
m_serviceMonitors.clear();
|
|
||||||
|
|
||||||
for (ServiceInfoMonitor *m : monitors) {
|
|
||||||
stopServiceMonitor(m);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServiceInfoManager::startServiceMonitor(
|
|
||||||
const QString &name, quint32 processId, void *managerHandle)
|
|
||||||
{
|
|
||||||
if (!m_serviceGroups.contains(name))
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto m = new ServiceInfoMonitor(processId, name, managerHandle);
|
|
||||||
|
|
||||||
connect(m, &ServiceInfoMonitor::stateChanged, this, &ServiceInfoManager::onServiceStateChanged,
|
|
||||||
Qt::QueuedConnection);
|
|
||||||
|
|
||||||
m_serviceMonitors.insert(name, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServiceInfoManager::stopServiceMonitor(ServiceInfoMonitor *m)
|
|
||||||
{
|
|
||||||
m_serviceMonitors.remove(m->name());
|
|
||||||
|
|
||||||
m->terminate();
|
|
||||||
m->deleteLater();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServiceInfoManager::startServiceListMonitor(void *managerHandle)
|
|
||||||
{
|
|
||||||
auto m = new ServiceListMonitor(managerHandle);
|
|
||||||
|
|
||||||
connect(m, &ServiceListMonitor::serviceCreated, this, &ServiceInfoManager::onServiceCreated,
|
|
||||||
Qt::QueuedConnection);
|
|
||||||
connect(m, &ServiceListMonitor::errorOccurred, this,
|
|
||||||
&ServiceInfoManager::stopServiceListMonitor, Qt::QueuedConnection);
|
|
||||||
|
|
||||||
m_serviceListMonitor = m;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServiceInfoManager::stopServiceListMonitor()
|
|
||||||
{
|
|
||||||
auto m = m_serviceListMonitor;
|
|
||||||
if (!m)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_serviceListMonitor = nullptr;
|
|
||||||
|
|
||||||
m->terminate();
|
|
||||||
m->deleteLater();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServiceInfoManager::onServiceStateChanged(ServiceInfo::State state, quint32 processId)
|
|
||||||
{
|
|
||||||
const auto m = qobject_cast<ServiceInfoMonitor *>(sender());
|
|
||||||
Q_ASSERT(m);
|
|
||||||
|
|
||||||
if (state == ServiceInfo::StateDeleted) {
|
|
||||||
Q_ASSERT(processId == 0);
|
|
||||||
processId = m->processId();
|
|
||||||
if (processId != 0) {
|
|
||||||
state = ServiceInfo::StateInactive;
|
|
||||||
}
|
|
||||||
|
|
||||||
stopServiceMonitor(m);
|
|
||||||
}
|
|
||||||
|
|
||||||
const int groupIndex = groupIndexByName(m->name());
|
|
||||||
if (groupIndex == -1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
Q_ASSERT(processId != 0);
|
|
||||||
|
|
||||||
emit serviceChanged(processId, (state == ServiceInfo::StateActive ? groupIndex : -1));
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServiceInfoManager::onServiceCreated(const QStringList &nameList)
|
|
||||||
{
|
|
||||||
for (const auto &name : nameList) {
|
|
||||||
startServiceMonitor(name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -8,19 +8,12 @@
|
|||||||
|
|
||||||
#include "serviceinfo.h"
|
#include "serviceinfo.h"
|
||||||
|
|
||||||
class ServiceInfoMonitor;
|
|
||||||
class ServiceListMonitor;
|
|
||||||
|
|
||||||
class ServiceInfoManager : public QObject, public IocService
|
class ServiceInfoManager : public QObject, public IocService
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit ServiceInfoManager(QObject *parent = nullptr);
|
explicit ServiceInfoManager(QObject *parent = nullptr);
|
||||||
~ServiceInfoManager() override;
|
|
||||||
|
|
||||||
bool monitorEnabled() const { return m_monitorEnabled; }
|
|
||||||
void setMonitorEnabled(bool v);
|
|
||||||
|
|
||||||
int groupIndexByName(const QString &name) const;
|
int groupIndexByName(const QString &name) const;
|
||||||
|
|
||||||
@ -30,25 +23,7 @@ signals:
|
|||||||
void serviceChanged(quint32 processId, int groupIndex = -1);
|
void serviceChanged(quint32 processId, int groupIndex = -1);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setupServiceMonitors();
|
|
||||||
void clearServiceMonitors();
|
|
||||||
|
|
||||||
void startServiceMonitor(
|
|
||||||
const QString &name, quint32 processId = 0, void *managerHandle = nullptr);
|
|
||||||
void stopServiceMonitor(ServiceInfoMonitor *m);
|
|
||||||
|
|
||||||
void startServiceListMonitor(void *managerHandle = nullptr);
|
|
||||||
void stopServiceListMonitor();
|
|
||||||
|
|
||||||
void onServiceStateChanged(ServiceInfo::State state, quint32 processId = 0);
|
|
||||||
void onServiceCreated(const QStringList &nameList);
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool m_monitorEnabled = false;
|
|
||||||
|
|
||||||
QHash<QString, int> m_serviceGroups;
|
QHash<QString, int> m_serviceGroups;
|
||||||
QHash<QString, ServiceInfoMonitor *> m_serviceMonitors;
|
|
||||||
ServiceListMonitor *m_serviceListMonitor = nullptr;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SERVICEINFOMANAGER_H
|
#endif // SERVICEINFOMANAGER_H
|
||||||
|
@ -1,199 +0,0 @@
|
|||||||
#include "serviceinfomonitor.h"
|
|
||||||
|
|
||||||
#include <QLoggingCategory>
|
|
||||||
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
|
||||||
#include <qt_windows.h>
|
|
||||||
|
|
||||||
#define asServiceHandle(h) static_cast<SC_HANDLE>((h))
|
|
||||||
#define serviceHandle() asServiceHandle(m_serviceHandle)
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
const QLoggingCategory LC("serviceInfo.serviceInfoMonitor");
|
|
||||||
|
|
||||||
static void CALLBACK notifyCallback(PVOID parameter)
|
|
||||||
{
|
|
||||||
PSERVICE_NOTIFYW notify = static_cast<PSERVICE_NOTIFYW>(parameter);
|
|
||||||
ServiceInfoMonitor *m = static_cast<ServiceInfoMonitor *>(notify->pContext);
|
|
||||||
|
|
||||||
if (notify->dwNotificationStatus != ERROR_SUCCESS) {
|
|
||||||
qCDebug(LC) << "Callback error:" << m->name() << notify->dwNotificationStatus;
|
|
||||||
m->requestReopenService();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (notify->dwNotificationTriggered & SERVICE_NOTIFY_DELETE_PENDING) {
|
|
||||||
emit m->stateChanged(ServiceInfo::StateDeleted);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const bool running = (notify->ServiceStatus.dwCurrentState == SERVICE_RUNNING);
|
|
||||||
m->setRunning(running);
|
|
||||||
|
|
||||||
const quint32 processId = notify->ServiceStatus.dwProcessId;
|
|
||||||
const quint32 oldProcessId = m->processId();
|
|
||||||
m->setProcessId(processId);
|
|
||||||
|
|
||||||
const ServiceInfo::State state =
|
|
||||||
running ? ServiceInfo::StateActive : ServiceInfo::StateInactive;
|
|
||||||
|
|
||||||
emit m->stateChanged(state, (running ? processId : oldProcessId));
|
|
||||||
|
|
||||||
// NotifyServiceStatusChange() must not be called from the callback
|
|
||||||
m->requestStartNotifier();
|
|
||||||
}
|
|
||||||
|
|
||||||
PSERVICE_NOTIFYW getNotifyBuffer(ServiceInfoMonitor *m)
|
|
||||||
{
|
|
||||||
auto &buffer = m->notifyBuffer();
|
|
||||||
|
|
||||||
PSERVICE_NOTIFYW notify = reinterpret_cast<PSERVICE_NOTIFYW>(buffer.data());
|
|
||||||
|
|
||||||
notify->dwVersion = SERVICE_NOTIFY_STATUS_CHANGE;
|
|
||||||
notify->pfnNotifyCallback = notifyCallback;
|
|
||||||
notify->pContext = m;
|
|
||||||
|
|
||||||
return notify;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
ServiceInfoMonitor::ServiceInfoMonitor(
|
|
||||||
quint32 processId, const QString &name, void *managerHandle, QObject *parent) :
|
|
||||||
QObject(parent),
|
|
||||||
m_terminated(false),
|
|
||||||
m_isReopening(false),
|
|
||||||
m_reopenServiceRequested(false),
|
|
||||||
m_startNotifierRequested(false),
|
|
||||||
m_running(processId != 0),
|
|
||||||
m_processId(processId),
|
|
||||||
m_name(name),
|
|
||||||
m_notifyBuffer(sizeof(SERVICE_NOTIFYW))
|
|
||||||
{
|
|
||||||
openService(managerHandle);
|
|
||||||
}
|
|
||||||
|
|
||||||
ServiceInfoMonitor::~ServiceInfoMonitor()
|
|
||||||
{
|
|
||||||
terminate();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServiceInfoMonitor::terminate()
|
|
||||||
{
|
|
||||||
if (m_terminated)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_terminated = true;
|
|
||||||
|
|
||||||
closeService();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServiceInfoMonitor::requestReopenService()
|
|
||||||
{
|
|
||||||
if (m_reopenServiceRequested)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_reopenServiceRequested = true;
|
|
||||||
|
|
||||||
QMetaObject::invokeMethod(this, &ServiceInfoMonitor::reopenService, Qt::QueuedConnection);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServiceInfoMonitor::requestStartNotifier()
|
|
||||||
{
|
|
||||||
if (m_startNotifierRequested)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_startNotifierRequested = true;
|
|
||||||
|
|
||||||
QMetaObject::invokeMethod(this, &ServiceInfoMonitor::startNotifier, Qt::QueuedConnection);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServiceInfoMonitor::openService(void *managerHandle)
|
|
||||||
{
|
|
||||||
const SC_HANDLE mngr = managerHandle ? asServiceHandle(managerHandle)
|
|
||||||
: OpenSCManagerW(nullptr, nullptr, SC_MANAGER_CONNECT);
|
|
||||||
if (mngr) {
|
|
||||||
m_serviceHandle = OpenServiceW(mngr, (LPCWSTR) name().utf16(), SERVICE_QUERY_STATUS);
|
|
||||||
|
|
||||||
if (!managerHandle) {
|
|
||||||
CloseServiceHandle(mngr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!m_serviceHandle) {
|
|
||||||
const DWORD res = GetLastError();
|
|
||||||
switch (res) {
|
|
||||||
case ERROR_SERVICE_MARKED_FOR_DELETE: {
|
|
||||||
emit stateChanged(ServiceInfo::StateDeleted);
|
|
||||||
} break;
|
|
||||||
default:
|
|
||||||
qCCritical(LC) << "Open service error:" << name() << res;
|
|
||||||
errorOccurred();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
startNotifier();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServiceInfoMonitor::closeService()
|
|
||||||
{
|
|
||||||
if (m_serviceHandle) {
|
|
||||||
CloseServiceHandle(serviceHandle());
|
|
||||||
m_serviceHandle = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServiceInfoMonitor::reopenService()
|
|
||||||
{
|
|
||||||
if (m_isReopening) {
|
|
||||||
qCCritical(LC) << "Reopen service error:" << name();
|
|
||||||
errorOccurred();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_isReopening = true;
|
|
||||||
|
|
||||||
m_reopenServiceRequested = false;
|
|
||||||
|
|
||||||
closeService();
|
|
||||||
openService();
|
|
||||||
|
|
||||||
m_isReopening = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServiceInfoMonitor::startNotifier()
|
|
||||||
{
|
|
||||||
if (m_terminated)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_startNotifierRequested = false;
|
|
||||||
|
|
||||||
constexpr DWORD mask =
|
|
||||||
SERVICE_NOTIFY_STOPPED | SERVICE_NOTIFY_RUNNING | SERVICE_NOTIFY_DELETE_PENDING;
|
|
||||||
|
|
||||||
PSERVICE_NOTIFYW notify = getNotifyBuffer(this);
|
|
||||||
|
|
||||||
const DWORD res = NotifyServiceStatusChangeW(serviceHandle(), mask, notify);
|
|
||||||
|
|
||||||
if (res != ERROR_SUCCESS) {
|
|
||||||
switch (res) {
|
|
||||||
case ERROR_SERVICE_MARKED_FOR_DELETE: {
|
|
||||||
emit stateChanged(ServiceInfo::StateDeleted);
|
|
||||||
} break;
|
|
||||||
case ERROR_SERVICE_NOTIFY_CLIENT_LAGGING: {
|
|
||||||
qCDebug(LC) << "Notifier is lagging:" << name();
|
|
||||||
reopenService();
|
|
||||||
} break;
|
|
||||||
default:
|
|
||||||
qCCritical(LC) << "Start notifier error:" << name() << res;
|
|
||||||
errorOccurred();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServiceInfoMonitor::errorOccurred()
|
|
||||||
{
|
|
||||||
emit stateChanged(ServiceInfo::StateDeleted);
|
|
||||||
}
|
|
@ -1,60 +0,0 @@
|
|||||||
#ifndef SERVICEINFOMONITOR_H
|
|
||||||
#define SERVICEINFOMONITOR_H
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
|
|
||||||
#include "serviceinfo.h"
|
|
||||||
|
|
||||||
class ServiceInfoMonitor : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit ServiceInfoMonitor(quint32 processId, const QString &name,
|
|
||||||
void *managerHandle = nullptr, QObject *parent = nullptr);
|
|
||||||
~ServiceInfoMonitor() override;
|
|
||||||
|
|
||||||
bool running() const { return m_running; }
|
|
||||||
void setRunning(bool v) { m_running = v; }
|
|
||||||
|
|
||||||
quint32 processId() const { return m_processId; }
|
|
||||||
void setProcessId(quint32 v) { m_processId = v; }
|
|
||||||
|
|
||||||
QString name() const { return m_name; }
|
|
||||||
|
|
||||||
QVector<char> ¬ifyBuffer() { return m_notifyBuffer; }
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void stateChanged(ServiceInfo::State state, quint32 processId = 0);
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void terminate();
|
|
||||||
|
|
||||||
void requestReopenService();
|
|
||||||
void requestStartNotifier();
|
|
||||||
|
|
||||||
private:
|
|
||||||
void openService(void *managerHandle = nullptr);
|
|
||||||
void closeService();
|
|
||||||
void reopenService();
|
|
||||||
|
|
||||||
void startNotifier();
|
|
||||||
|
|
||||||
void errorOccurred();
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool m_terminated : 1;
|
|
||||||
bool m_isReopening : 1;
|
|
||||||
bool m_reopenServiceRequested : 1;
|
|
||||||
bool m_startNotifierRequested : 1;
|
|
||||||
bool m_running : 1;
|
|
||||||
|
|
||||||
quint32 m_processId = 0;
|
|
||||||
|
|
||||||
const QString m_name;
|
|
||||||
|
|
||||||
void *m_serviceHandle = nullptr;
|
|
||||||
QVector<char> m_notifyBuffer;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // SERVICEINFOMONITOR_H
|
|
@ -1,181 +0,0 @@
|
|||||||
#include "servicelistmonitor.h"
|
|
||||||
|
|
||||||
#include <QLoggingCategory>
|
|
||||||
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
|
||||||
#include <qt_windows.h>
|
|
||||||
|
|
||||||
#define asManagerHandle(h) static_cast<SC_HANDLE>((h))
|
|
||||||
#define managerHandle() asManagerHandle(m_managerHandle)
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
const QLoggingCategory LC("serviceInfo.serviceListMonitor");
|
|
||||||
|
|
||||||
static QStringList parseServiceNames(LPWSTR pszServiceNames)
|
|
||||||
{
|
|
||||||
QStringList list;
|
|
||||||
PWSTR name = pszServiceNames;
|
|
||||||
for (;;) {
|
|
||||||
if (name[0] == '\0')
|
|
||||||
break;
|
|
||||||
Q_ASSERT(name[0] == '/');
|
|
||||||
++name; // Skip the leading '/' for created services
|
|
||||||
const QString nameStr = QString::fromWCharArray(name);
|
|
||||||
name += nameStr.length() + 1;
|
|
||||||
list.append(nameStr);
|
|
||||||
}
|
|
||||||
LocalFree(pszServiceNames);
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void CALLBACK notifyCallback(PVOID parameter)
|
|
||||||
{
|
|
||||||
PSERVICE_NOTIFYW notify = static_cast<PSERVICE_NOTIFYW>(parameter);
|
|
||||||
ServiceListMonitor *m = static_cast<ServiceListMonitor *>(notify->pContext);
|
|
||||||
|
|
||||||
if (notify->dwNotificationStatus != ERROR_SUCCESS) {
|
|
||||||
qCDebug(LC) << "Callback error:" << notify->dwNotificationStatus;
|
|
||||||
m->requestReopenManager();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QStringList nameList =
|
|
||||||
notify->pszServiceNames ? parseServiceNames(notify->pszServiceNames) : QStringList();
|
|
||||||
|
|
||||||
if (!nameList.isEmpty()) {
|
|
||||||
emit m->serviceCreated(nameList);
|
|
||||||
}
|
|
||||||
|
|
||||||
// NotifyServiceStatusChange() must not be called from the callback
|
|
||||||
m->requestStartNotifier();
|
|
||||||
}
|
|
||||||
|
|
||||||
PSERVICE_NOTIFYW getNotifyBuffer(ServiceListMonitor *m)
|
|
||||||
{
|
|
||||||
auto &buffer = m->notifyBuffer();
|
|
||||||
|
|
||||||
PSERVICE_NOTIFYW notify = reinterpret_cast<PSERVICE_NOTIFYW>(buffer.data());
|
|
||||||
|
|
||||||
notify->dwVersion = SERVICE_NOTIFY_STATUS_CHANGE;
|
|
||||||
notify->pfnNotifyCallback = notifyCallback;
|
|
||||||
notify->pContext = m;
|
|
||||||
|
|
||||||
return notify;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
ServiceListMonitor::ServiceListMonitor(void *managerHandle, QObject *parent) :
|
|
||||||
QObject(parent),
|
|
||||||
m_terminated(false),
|
|
||||||
m_isReopening(false),
|
|
||||||
m_reopenManagerRequested(false),
|
|
||||||
m_startNotifierRequested(false),
|
|
||||||
m_managerHandle(managerHandle),
|
|
||||||
m_notifyBuffer(sizeof(SERVICE_NOTIFYW))
|
|
||||||
{
|
|
||||||
openManager();
|
|
||||||
}
|
|
||||||
|
|
||||||
ServiceListMonitor::~ServiceListMonitor()
|
|
||||||
{
|
|
||||||
terminate();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServiceListMonitor::terminate()
|
|
||||||
{
|
|
||||||
if (m_terminated)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_terminated = true;
|
|
||||||
|
|
||||||
closeManager();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServiceListMonitor::requestReopenManager()
|
|
||||||
{
|
|
||||||
if (m_reopenManagerRequested)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_reopenManagerRequested = true;
|
|
||||||
|
|
||||||
QMetaObject::invokeMethod(this, &ServiceListMonitor::reopenManager, Qt::QueuedConnection);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServiceListMonitor::requestStartNotifier()
|
|
||||||
{
|
|
||||||
if (m_startNotifierRequested)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_startNotifierRequested = true;
|
|
||||||
|
|
||||||
QMetaObject::invokeMethod(this, &ServiceListMonitor::startNotifier, Qt::QueuedConnection);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServiceListMonitor::openManager()
|
|
||||||
{
|
|
||||||
if (!m_managerHandle) {
|
|
||||||
m_managerHandle = OpenSCManagerW(nullptr, nullptr, SC_MANAGER_ENUMERATE_SERVICE);
|
|
||||||
|
|
||||||
if (!m_managerHandle) {
|
|
||||||
qCCritical(LC) << "Open manager error:" << GetLastError();
|
|
||||||
emit errorOccurred();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
startNotifier();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServiceListMonitor::closeManager()
|
|
||||||
{
|
|
||||||
if (m_managerHandle) {
|
|
||||||
CloseServiceHandle(managerHandle());
|
|
||||||
m_managerHandle = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServiceListMonitor::reopenManager()
|
|
||||||
{
|
|
||||||
if (m_isReopening) {
|
|
||||||
qCCritical(LC) << "Reopen manager error";
|
|
||||||
emit errorOccurred();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_isReopening = true;
|
|
||||||
|
|
||||||
m_reopenManagerRequested = false;
|
|
||||||
|
|
||||||
closeManager();
|
|
||||||
openManager();
|
|
||||||
|
|
||||||
m_isReopening = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServiceListMonitor::startNotifier()
|
|
||||||
{
|
|
||||||
if (m_terminated)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_startNotifierRequested = false;
|
|
||||||
|
|
||||||
constexpr DWORD mask = SERVICE_NOTIFY_CREATED;
|
|
||||||
|
|
||||||
PSERVICE_NOTIFYW notify = getNotifyBuffer(this);
|
|
||||||
|
|
||||||
const DWORD res = NotifyServiceStatusChangeW(managerHandle(), mask, notify);
|
|
||||||
|
|
||||||
if (res != ERROR_SUCCESS) {
|
|
||||||
switch (res) {
|
|
||||||
case ERROR_SERVICE_NOTIFY_CLIENT_LAGGING: {
|
|
||||||
qCDebug(LC) << "Notifier is lagging";
|
|
||||||
reopenManager();
|
|
||||||
} break;
|
|
||||||
default:
|
|
||||||
qCCritical(LC) << "Start notifier error:" << res;
|
|
||||||
emit errorOccurred();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,43 +0,0 @@
|
|||||||
#ifndef SERVICELISTMONITOR_H
|
|
||||||
#define SERVICELISTMONITOR_H
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
|
|
||||||
class ServiceListMonitor : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit ServiceListMonitor(void *managerHandle = nullptr, QObject *parent = nullptr);
|
|
||||||
~ServiceListMonitor() override;
|
|
||||||
|
|
||||||
QVector<char> ¬ifyBuffer() { return m_notifyBuffer; }
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void serviceCreated(const QStringList &nameList);
|
|
||||||
void errorOccurred();
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void terminate();
|
|
||||||
|
|
||||||
void requestReopenManager();
|
|
||||||
void requestStartNotifier();
|
|
||||||
|
|
||||||
private:
|
|
||||||
void openManager();
|
|
||||||
void closeManager();
|
|
||||||
void reopenManager();
|
|
||||||
|
|
||||||
void startNotifier();
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool m_terminated : 1;
|
|
||||||
bool m_isReopening : 1;
|
|
||||||
bool m_reopenManagerRequested : 1;
|
|
||||||
bool m_startNotifierRequested : 1;
|
|
||||||
|
|
||||||
void *m_managerHandle = nullptr;
|
|
||||||
QVector<char> m_notifyBuffer;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // SERVICELISTMONITOR_H
|
|
Loading…
Reference in New Issue
Block a user