From ef1fcf84b9125f3208bfa211aa4f808d9e0a659c Mon Sep 17 00:00:00 2001 From: Nodir Temirkhodjaev Date: Sun, 26 Dec 2021 21:08:02 +0300 Subject: [PATCH] UI: Prepare ServiceInfoMonitor --- src/ui/FortFirewallUI.pro | 2 + src/ui/conf/firewallconf.cpp | 12 -- src/ui/conf/firewallconf.h | 5 - src/ui/form/opt/pages/servicespage.cpp | 38 ++---- src/ui/form/opt/pages/servicespage.h | 5 +- src/ui/fortmanager.cpp | 9 +- src/ui/fortmanager.h | 3 +- src/ui/fortsettings.cpp | 1 - src/ui/model/servicelistmodel.cpp | 33 ++++- src/ui/model/servicelistmodel.h | 7 + src/ui/serviceinfo/serviceinfo.h | 8 +- src/ui/serviceinfo/serviceinfomanager.cpp | 120 +++++++++++------ src/ui/serviceinfo/serviceinfomanager.h | 31 +++-- src/ui/serviceinfo/serviceinfomonitor.cpp | 155 ++++++++++++++++++++++ src/ui/serviceinfo/serviceinfomonitor.h | 52 ++++++++ 15 files changed, 363 insertions(+), 118 deletions(-) create mode 100644 src/ui/serviceinfo/serviceinfomonitor.cpp create mode 100644 src/ui/serviceinfo/serviceinfomonitor.h diff --git a/src/ui/FortFirewallUI.pro b/src/ui/FortFirewallUI.pro index 46620ce4..7915ec4a 100644 --- a/src/ui/FortFirewallUI.pro +++ b/src/ui/FortFirewallUI.pro @@ -111,6 +111,7 @@ SOURCES += \ rpc/windowmanagerfake.cpp \ serviceinfo/serviceinfo.cpp \ serviceinfo/serviceinfomanager.cpp \ + serviceinfo/serviceinfomonitor.cpp \ stat/quotamanager.cpp \ stat/statmanager.cpp \ stat/statsql.cpp \ @@ -264,6 +265,7 @@ HEADERS += \ rpc/windowmanagerfake.h \ serviceinfo/serviceinfo.h \ serviceinfo/serviceinfomanager.h \ + serviceinfo/serviceinfomonitor.h \ stat/quotamanager.h \ stat/statmanager.h \ stat/statsql.h \ diff --git a/src/ui/conf/firewallconf.cpp b/src/ui/conf/firewallconf.cpp index aac1eb77..1ade9a29 100644 --- a/src/ui/conf/firewallconf.cpp +++ b/src/ui/conf/firewallconf.cpp @@ -22,7 +22,6 @@ FirewallConf::FirewallConf(Settings *settings, QObject *parent) : m_logBlockedIp(false), m_appBlockAll(true), m_appAllowAll(false), - m_filterServices(false), m_activePeriodEnabled(false), m_ini(settings) { @@ -102,11 +101,6 @@ void FirewallConf::setAppAllowAll(bool appAllowAll) m_appAllowAll = appAllowAll; } -void FirewallConf::setFilterServices(bool filterServices) -{ - m_filterServices = filterServices; -} - void FirewallConf::setActivePeriodEnabled(bool activePeriodEnabled) { m_activePeriodEnabled = activePeriodEnabled; @@ -295,8 +289,6 @@ void FirewallConf::copyFlags(const FirewallConf &o) m_appBlockAll = o.appBlockAll(); m_appAllowAll = o.appAllowAll(); - m_filterServices = o.filterServices(); - m_activePeriodEnabled = o.activePeriodEnabled(); m_activePeriodFrom = o.activePeriodFrom(); m_activePeriodTo = o.activePeriodTo(); @@ -345,8 +337,6 @@ QVariant FirewallConf::flagsToVariant() const map["appBlockAll"] = appBlockAll(); map["appAllowAll"] = appAllowAll(); - map["filterServices"] = filterServices(); - map["activePeriodEnabled"] = activePeriodEnabled(); map["activePeriodFrom"] = activePeriodFrom(); map["activePeriodTo"] = activePeriodTo(); @@ -377,8 +367,6 @@ void FirewallConf::flagsFromVariant(const QVariant &v) m_appBlockAll = map["appBlockAll"].toBool(); m_appAllowAll = map["appAllowAll"].toBool(); - m_filterServices = map["filterServices"].toBool(); - m_activePeriodEnabled = map["activePeriodEnabled"].toBool(); m_activePeriodFrom = map["activePeriodFrom"].toString(); m_activePeriodTo = map["activePeriodTo"].toString(); diff --git a/src/ui/conf/firewallconf.h b/src/ui/conf/firewallconf.h index 02000fbd..a36d3fd9 100644 --- a/src/ui/conf/firewallconf.h +++ b/src/ui/conf/firewallconf.h @@ -85,9 +85,6 @@ public: bool appAllowAll() const { return m_appAllowAll; } void setAppAllowAll(bool appAllowAll); - bool filterServices() const { return m_filterServices; } - void setFilterServices(bool filterServices); - bool activePeriodEnabled() const { return m_activePeriodEnabled; } void setActivePeriodEnabled(bool activePeriodEnabled); @@ -185,8 +182,6 @@ private: uint m_appBlockAll : 1; uint m_appAllowAll : 1; - uint m_filterServices : 1; - uint m_activePeriodEnabled : 1; quint32 m_appGroupBits = 0; diff --git a/src/ui/form/opt/pages/servicespage.cpp b/src/ui/form/opt/pages/servicespage.cpp index 454e4f19..ed461d57 100644 --- a/src/ui/form/opt/pages/servicespage.cpp +++ b/src/ui/form/opt/pages/servicespage.cpp @@ -31,11 +31,11 @@ ServiceInfoManager *ServicesPage::serviceInfoManager() const void ServicesPage::onRetranslateUi() { + m_btRefresh->setText(tr("Refresh")); m_btEdit->setText(tr("Edit")); m_actEditService->setText(tr("Edit Service")); m_btOptions->setText(tr("Options")); - m_cbFilterServices->setText(tr("Filter Services")); serviceListModel()->refresh(); } @@ -61,6 +61,9 @@ QLayout *ServicesPage::setupHeader() { auto layout = new QHBoxLayout(); + m_btRefresh = ControlUtil::createButton( + ":/icons/arrow_refresh_small.png", [&] { serviceListModel()->initialize(); }); + // Edit Menu auto editMenu = new QMenu(this); @@ -80,6 +83,7 @@ QLayout *ServicesPage::setupHeader() // Options setupOptions(); + layout->addWidget(m_btRefresh); layout->addWidget(m_btEdit); layout->addStretch(); layout->addWidget(m_btOptions); @@ -89,10 +93,8 @@ QLayout *ServicesPage::setupHeader() void ServicesPage::setupOptions() { - setupFilterServices(); - // Menu - const QList menuWidgets = { m_cbFilterServices }; + const QList menuWidgets = {}; auto layout = ControlUtil::createLayoutByWidgets(menuWidgets); auto menu = ControlUtil::createMenuByLayout(layout, this); @@ -101,19 +103,6 @@ void ServicesPage::setupOptions() m_btOptions->setMenu(menu); } -void ServicesPage::setupFilterServices() -{ - m_cbFilterServices = ControlUtil::createCheckBox(conf()->filterServices(), [&](bool checked) { - if (conf()->filterServices() == checked) - return; - - conf()->setFilterServices(checked); - ctrl()->setFlagsEdited(); - - updateFilterServices(); - }); -} - void ServicesPage::setupTableServiceList() { m_serviceListView = new TableView(); @@ -133,15 +122,10 @@ void ServicesPage::setupTableServiceListHeader() header->setSectionResizeMode(0, QHeaderView::Interactive); header->setSectionResizeMode(1, QHeaderView::Stretch); header->setSectionResizeMode(2, QHeaderView::Interactive); + header->setSectionResizeMode(3, QHeaderView::Interactive); - header->resizeSection(0, 250); - header->resizeSection(1, 350); - header->resizeSection(2, 90); -} - -void ServicesPage::updateFilterServices() -{ - if (conf()->filterServices()) { - serviceInfoManager()->setEnabled(true); - } + header->resizeSection(0, 240); + header->resizeSection(1, 290); + header->resizeSection(2, 80); + header->resizeSection(3, 90); } diff --git a/src/ui/form/opt/pages/servicespage.h b/src/ui/form/opt/pages/servicespage.h index 2dee51e5..b211c323 100644 --- a/src/ui/form/opt/pages/servicespage.h +++ b/src/ui/form/opt/pages/servicespage.h @@ -24,19 +24,16 @@ private: void setupUi(); QLayout *setupHeader(); void setupOptions(); - void setupFilterServices(); void setupTableServiceList(); void setupTableServiceListHeader(); - void updateFilterServices(); - private: ServiceListModel *m_serviceListModel; + QPushButton *m_btRefresh = nullptr; QPushButton *m_btEdit = nullptr; QAction *m_actEditService = nullptr; QPushButton *m_btOptions = nullptr; - QCheckBox *m_cbFilterServices = nullptr; TableView *m_serviceListView = nullptr; }; diff --git a/src/ui/fortmanager.cpp b/src/ui/fortmanager.cpp index 36506dab..8a9af232 100644 --- a/src/ui/fortmanager.cpp +++ b/src/ui/fortmanager.cpp @@ -84,6 +84,7 @@ void FortManager::initialize() setupConfManager(); setupQuotaManager(); setupTaskManager(); + setupServiceInfoManager(); setupDriver(); loadConf(); @@ -258,7 +259,6 @@ void FortManager::setupConfManager() const FirewallConf *conf = IoC()->conf(); updateLogger(conf); - updateServiceInfoManager(conf); if (!onlyFlags || conf->flagsEdited()) { updateDriverConf(onlyFlags); @@ -287,12 +287,11 @@ void FortManager::setupTaskManager() IoC(), &ConfManager::updateDriverZones); } -void FortManager::updateServiceInfoManager(const FirewallConf *conf) +void FortManager::setupServiceInfoManager() { - if (!conf->flagsEdited()) - return; + auto serviceInfoManager = IoC(); - IoC()->setEnabled(conf->filterServices()); + serviceInfoManager->setMonitorEnabled(IoC()->isMaster()); } void FortManager::setupTranslationManager() diff --git a/src/ui/fortmanager.h b/src/ui/fortmanager.h index 7a0a863d..e4349b8f 100644 --- a/src/ui/fortmanager.h +++ b/src/ui/fortmanager.h @@ -46,8 +46,7 @@ private: void setupConfManager(); void setupQuotaManager(); void setupTaskManager(); - - void updateServiceInfoManager(const FirewallConf *conf); + void setupServiceInfoManager(); void setupTranslationManager(); diff --git a/src/ui/fortsettings.cpp b/src/ui/fortsettings.cpp index b165f26c..2f62145a 100644 --- a/src/ui/fortsettings.cpp +++ b/src/ui/fortsettings.cpp @@ -347,7 +347,6 @@ void FortSettings::writeConfIni(const FirewallConf &conf) setIniValue("logBlockedIp", conf.logBlockedIp()); setIniValue("appBlockAll", conf.appBlockAll()); setIniValue("appAllowAll", conf.appAllowAll()); - setIniValue("filterServices", conf.filterServices()); setIniValue("appGroupBits", conf.appGroupBits(), DEFAULT_APP_GROUP_BITS); ini()->endGroup(); diff --git a/src/ui/model/servicelistmodel.cpp b/src/ui/model/servicelistmodel.cpp index 87f23320..3c0ed887 100644 --- a/src/ui/model/servicelistmodel.cpp +++ b/src/ui/model/servicelistmodel.cpp @@ -25,20 +25,21 @@ FirewallConf *ServiceListModel::conf() const void ServiceListModel::initialize() { - connect(serviceInfoManager(), &ServiceInfoManager::servicesChanged, this, - &ServiceListModel::reset); + m_services = serviceInfoManager()->loadServiceInfoList(); + + reset(); } int ServiceListModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent); - return serviceInfoManager()->services().size(); + return services().size(); } int ServiceListModel::columnCount(const QModelIndex &parent) const { - return parent.isValid() ? 0 : 3; + return parent.isValid() ? 0 : 4; } QVariant ServiceListModel::headerData(int section, Qt::Orientation orientation, int role) const @@ -50,6 +51,8 @@ QVariant ServiceListModel::headerData(int section, Qt::Orientation orientation, case 1: return tr("Display Name"); case 2: + return tr("Process ID"); + case 3: return tr("Group"); } } @@ -76,7 +79,7 @@ QVariant ServiceListModel::dataDisplay(const QModelIndex &index) const const int row = index.row(); const int column = index.column(); - const auto info = serviceInfoManager()->serviceInfoAt(row); + const auto info = serviceInfoAt(row); switch (column) { case 0: @@ -84,18 +87,36 @@ QVariant ServiceListModel::dataDisplay(const QModelIndex &index) const case 1: return info.displayName; case 2: + return dataDisplayProcessId(info); + case 3: return dataDisplayAppGroup(info); } return QVariant(); } +QVariant ServiceListModel::dataDisplayProcessId(const ServiceInfo &info) const +{ + return (info.processId == 0) ? QVariant() : QVariant(info.processId); +} + QVariant ServiceListModel::dataDisplayAppGroup(const ServiceInfo &info) const { - return (info.groupIndex < 0) ? QVariant() : conf()->appGroupAt(info.groupIndex)->name(); + const int groupIndex = serviceInfoManager()->groupIndexByName(info.serviceName); + + return (groupIndex < 0) ? QVariant() : conf()->appGroupAt(groupIndex)->name(); } bool ServiceListModel::updateTableRow(int /*row*/) const { return true; } + +const ServiceInfo &ServiceListModel::serviceInfoAt(int index) const +{ + if (index < 0 || index >= services().size()) { + static const ServiceInfo g_nullServiceInfo; + return g_nullServiceInfo; + } + return services()[index]; +} diff --git a/src/ui/model/servicelistmodel.h b/src/ui/model/servicelistmodel.h index a52b4feb..ce133b69 100644 --- a/src/ui/model/servicelistmodel.h +++ b/src/ui/model/servicelistmodel.h @@ -3,6 +3,7 @@ #include +#include #include class ConfManager; @@ -36,9 +37,15 @@ protected: private: QVariant dataDisplay(const QModelIndex &index) const; + QVariant dataDisplayProcessId(const ServiceInfo &info) const; QVariant dataDisplayAppGroup(const ServiceInfo &info) const; + const QVector &services() const { return m_services; } + const ServiceInfo &serviceInfoAt(int index) const; + private: + QVector m_services; + mutable TableRow m_serviceRow; }; diff --git a/src/ui/serviceinfo/serviceinfo.h b/src/ui/serviceinfo/serviceinfo.h index e4abd429..e9daaf22 100644 --- a/src/ui/serviceinfo/serviceinfo.h +++ b/src/ui/serviceinfo/serviceinfo.h @@ -6,11 +6,13 @@ class ServiceInfo { public: - int groupIndex = -1; + enum State { + StateActive = 0x01, + StateInactive = 0x02, + StateDeleted = 0x04, + }; quint32 processId = 0; - quint64 id = 0; - QString serviceName; QString displayName; }; diff --git a/src/ui/serviceinfo/serviceinfomanager.cpp b/src/ui/serviceinfo/serviceinfomanager.cpp index 5129fa71..afdd36d0 100644 --- a/src/ui/serviceinfo/serviceinfomanager.cpp +++ b/src/ui/serviceinfo/serviceinfomanager.cpp @@ -1,10 +1,16 @@ #include "serviceinfomanager.h" +#include + #define WIN32_LEAN_AND_MEAN #include +#include "serviceinfomonitor.h" + namespace { +const QLoggingCategory LC("serviceInfo.serviceInfoManager"); + QVector getServiceInfoList(SC_HANDLE mngr) { QVector infoList; @@ -43,54 +49,94 @@ QVector getServiceInfoList(SC_HANDLE mngr) ServiceInfoManager::ServiceInfoManager(QObject *parent) : QObject(parent) { } -void ServiceInfoManager::setEnabled(bool v) +ServiceInfoManager::~ServiceInfoManager() { - if (m_enabled != v) { - m_enabled = v; - updateWorker(); - updateServices(); + clearServiceMonitors(); +} + +void ServiceInfoManager::setMonitorEnabled(bool v) +{ + if (m_monitorEnabled != v) { + m_monitorEnabled = v; + + setupServiceMonitors(); } } -const ServiceInfo &ServiceInfoManager::serviceInfoAt(int index) const +int ServiceInfoManager::groupIndexByName(const QString &name) const { - if (index < 0 || index >= services().size()) { - static const ServiceInfo g_nullServiceInfo; - return g_nullServiceInfo; - } - return services()[index]; + return m_serviceGroups.value(name, -1); } -void ServiceInfoManager::updateWorker() -{ - if (enabled()) { - startWorker(); - } else { - stopWorker(); - } -} - -void ServiceInfoManager::startWorker() { } - -void ServiceInfoManager::stopWorker() { } - -void ServiceInfoManager::updateServices() -{ - services().clear(); - - if (enabled()) { - loadServices(); - } - - emit servicesChanged(); -} - -void ServiceInfoManager::loadServices() +QVector ServiceInfoManager::loadServiceInfoList() { + QVector list; const SC_HANDLE mngr = OpenSCManagerW(nullptr, nullptr, SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE); if (mngr) { - m_services = getServiceInfoList(mngr); + list = getServiceInfoList(mngr); CloseServiceHandle(mngr); } + 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; + } + + const auto services = loadServiceInfoList(); + for (const auto &info : services) { + const auto m = startServiceMonitor(info, mngr); + + m_serviceMonitors.insert(info.serviceName, m); + } + + CloseServiceHandle(mngr); +} + +void ServiceInfoManager::clearServiceMonitors() +{ + const auto moniros = m_serviceMonitors.values(); + for (ServiceInfoMonitor *m : moniros) { + stopServiceMonitor(m); + } + m_serviceMonitors.clear(); +} + +ServiceInfoMonitor *ServiceInfoManager::startServiceMonitor( + const ServiceInfo &info, void *managerHandle) +{ + const auto m = new ServiceInfoMonitor(info.processId, info.serviceName, managerHandle); + + connect(m, &ServiceInfoMonitor::stateChanged, this, &ServiceInfoManager::onServiceStateChanged); + + return m; +} + +void ServiceInfoManager::stopServiceMonitor(ServiceInfoMonitor *m) +{ + m->terminate(); + m->deleteLater(); +} + +void ServiceInfoManager::onServiceStateChanged(ServiceInfo::State state) +{ + const auto m = qobject_cast(sender()); + Q_ASSERT(m); + + if (state == ServiceInfo::StateDeleted) { + stopServiceMonitor(m); + + m_serviceMonitors.remove(m->name()); + } } diff --git a/src/ui/serviceinfo/serviceinfomanager.h b/src/ui/serviceinfo/serviceinfomanager.h index bd082be2..6eca0ce1 100644 --- a/src/ui/serviceinfo/serviceinfomanager.h +++ b/src/ui/serviceinfo/serviceinfomanager.h @@ -8,41 +8,40 @@ #include "serviceinfo.h" +class ServiceInfoMonitor; + class ServiceInfoManager : public QObject, public IocService { Q_OBJECT public: explicit ServiceInfoManager(QObject *parent = nullptr); + ~ServiceInfoManager() override; - bool enabled() const { return m_enabled; } - void setEnabled(bool v); + bool monitorEnabled() const { return m_monitorEnabled; } + void setMonitorEnabled(bool v); - QHash &serviceGroups() { return m_serviceGroups; } - const QHash &serviceGroups() const { return m_serviceGroups; } + int groupIndexByName(const QString &name) const; - QVector &services() { return m_services; } - const QVector &services() const { return m_services; } - - const ServiceInfo &serviceInfoAt(int index) const; + static QVector loadServiceInfoList(); signals: void servicesChanged(); private: - void updateWorker(); - void startWorker(); - void stopWorker(); + void setupServiceMonitors(); + void clearServiceMonitors(); - void updateServices(); - void loadServices(); - void loadServiceInfos(); + ServiceInfoMonitor *startServiceMonitor(const ServiceInfo &info, void *managerHandle); + void stopServiceMonitor(ServiceInfoMonitor *m); + + void onServiceStateChanged(ServiceInfo::State state); private: - bool m_enabled = false; + bool m_monitorEnabled = false; QHash m_serviceGroups; - QVector m_services; + QHash m_serviceMonitors; }; #endif // SERVICEINFOMANAGER_H diff --git a/src/ui/serviceinfo/serviceinfomonitor.cpp b/src/ui/serviceinfo/serviceinfomonitor.cpp new file mode 100644 index 00000000..47d960ee --- /dev/null +++ b/src/ui/serviceinfo/serviceinfomonitor.cpp @@ -0,0 +1,155 @@ +#include "serviceinfomonitor.h" + +#include + +#define WIN32_LEAN_AND_MEAN +#include + +#define asServiceHandle(h) static_cast((h)) +#define serviceHandle() asServiceHandle(m_serviceHandle) + +namespace { + +const QLoggingCategory LC("serviceInfo.serviceInfoMonitor"); + +static void CALLBACK notifyCallback(PVOID parameter) +{ + PSERVICE_NOTIFYW notify = static_cast(parameter); + ServiceInfoMonitor *m = static_cast(notify->pContext); + + if (notify->dwNotificationStatus != ERROR_SUCCESS) { + if (notify->dwNotificationStatus == ERROR_SERVICE_MARKED_FOR_DELETE) { + emit m->stateChanged(ServiceInfo::StateDeleted); + } + return; + } + + m->setProcessId(notify->ServiceStatus.dwProcessId); + + const ServiceInfo::State state = (notify->ServiceStatus.dwCurrentState == SERVICE_STOPPED) + ? ServiceInfo::StateInactive + : ServiceInfo::StateActive; + + emit m->stateChanged(state); + + // NotifyServiceStatusChange() must not be called from the callback + m->requestStartNotifier(); +} + +PSERVICE_NOTIFYW getNotifyBuffer(ServiceInfoMonitor *m) +{ + QByteArray &buffer = m->notifyBuffer(); + if (buffer.isNull()) { + buffer = QByteArray(sizeof(SERVICE_NOTIFYW), '\0'); + } + + PSERVICE_NOTIFYW notify = reinterpret_cast(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_startNotifierRequested(false), + m_processId(processId), + m_name(name) +{ + openService(managerHandle); +} + +ServiceInfoMonitor::~ServiceInfoMonitor() +{ + closeService(); +} + +void ServiceInfoMonitor::terminate() +{ + m_terminated = true; + + closeService(); +} + +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) { + qCCritical(LC) << "Open service error:" << name() << GetLastError(); + 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(); + return; + } + + m_isReopening = true; + + closeService(); + openService(); + + m_isReopening = false; +} + +void ServiceInfoMonitor::startNotifier() +{ + if (m_terminated) + return; + + m_startNotifierRequested = false; + + constexpr DWORD mask = SERVICE_NOTIFY_STOPPED | SERVICE_NOTIFY_RUNNING; + + PSERVICE_NOTIFYW notify = getNotifyBuffer(this); + + const DWORD res = NotifyServiceStatusChangeW(serviceHandle(), mask, notify); + + if (res != ERROR_SUCCESS) { + if (res == ERROR_SERVICE_NOTIFY_CLIENT_LAGGING) { + qCDebug(LC) << "Notifier is lagging:" << name(); + reopenService(); + } else { + qCCritical(LC) << "Start notifier error:" << name() << res; + } + } +} diff --git a/src/ui/serviceinfo/serviceinfomonitor.h b/src/ui/serviceinfo/serviceinfomonitor.h new file mode 100644 index 00000000..e34f7a38 --- /dev/null +++ b/src/ui/serviceinfo/serviceinfomonitor.h @@ -0,0 +1,52 @@ +#ifndef SERVICEINFOMONITOR_H +#define SERVICEINFOMONITOR_H + +#include + +#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; + + quint32 processId() const { return m_processId; } + void setProcessId(quint32 v) { m_processId = v; } + + QString name() const { return m_name; } + + QByteArray ¬ifyBuffer() { return m_notifyBuffer; } + +signals: + void stateChanged(ServiceInfo::State state); + +public slots: + void terminate(); + + void requestStartNotifier(); + +private: + void openService(void *managerHandle = nullptr); + void closeService(); + void reopenService(); + + void startNotifier(); + +private: + bool m_terminated : 1; + bool m_isReopening : 1; + bool m_startNotifierRequested : 1; + + quint32 m_processId = 0; + + void *m_serviceHandle = nullptr; + QByteArray m_notifyBuffer; + + const QString m_name; +}; + +#endif // SERVICEINFOMONITOR_H