mirror of
https://github.com/tnodir/fort
synced 2024-11-15 07:25:18 +00:00
UI: Prepare ServiceInfoMonitor
This commit is contained in:
parent
e372bf8c1c
commit
ef1fcf84b9
@ -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 \
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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<QWidget *> menuWidgets = { m_cbFilterServices };
|
||||
const QList<QWidget *> 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);
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -84,6 +84,7 @@ void FortManager::initialize()
|
||||
setupConfManager();
|
||||
setupQuotaManager();
|
||||
setupTaskManager();
|
||||
setupServiceInfoManager();
|
||||
|
||||
setupDriver();
|
||||
loadConf();
|
||||
@ -258,7 +259,6 @@ void FortManager::setupConfManager()
|
||||
const FirewallConf *conf = IoC<ConfManager>()->conf();
|
||||
|
||||
updateLogger(conf);
|
||||
updateServiceInfoManager(conf);
|
||||
|
||||
if (!onlyFlags || conf->flagsEdited()) {
|
||||
updateDriverConf(onlyFlags);
|
||||
@ -287,12 +287,11 @@ void FortManager::setupTaskManager()
|
||||
IoC<ConfManager>(), &ConfManager::updateDriverZones);
|
||||
}
|
||||
|
||||
void FortManager::updateServiceInfoManager(const FirewallConf *conf)
|
||||
void FortManager::setupServiceInfoManager()
|
||||
{
|
||||
if (!conf->flagsEdited())
|
||||
return;
|
||||
auto serviceInfoManager = IoC<ServiceInfoManager>();
|
||||
|
||||
IoC<ServiceInfoManager>()->setEnabled(conf->filterServices());
|
||||
serviceInfoManager->setMonitorEnabled(IoC<FortSettings>()->isMaster());
|
||||
}
|
||||
|
||||
void FortManager::setupTranslationManager()
|
||||
|
@ -46,8 +46,7 @@ private:
|
||||
void setupConfManager();
|
||||
void setupQuotaManager();
|
||||
void setupTaskManager();
|
||||
|
||||
void updateServiceInfoManager(const FirewallConf *conf);
|
||||
void setupServiceInfoManager();
|
||||
|
||||
void setupTranslationManager();
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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];
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include <QVector>
|
||||
|
||||
#include <serviceinfo/serviceinfo.h>
|
||||
#include <util/model/tableitemmodel.h>
|
||||
|
||||
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<ServiceInfo> &services() const { return m_services; }
|
||||
const ServiceInfo &serviceInfoAt(int index) const;
|
||||
|
||||
private:
|
||||
QVector<ServiceInfo> m_services;
|
||||
|
||||
mutable TableRow m_serviceRow;
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -1,10 +1,16 @@
|
||||
#include "serviceinfomanager.h"
|
||||
|
||||
#include <QLoggingCategory>
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <qt_windows.h>
|
||||
|
||||
#include "serviceinfomonitor.h"
|
||||
|
||||
namespace {
|
||||
|
||||
const QLoggingCategory LC("serviceInfo.serviceInfoManager");
|
||||
|
||||
QVector<ServiceInfo> getServiceInfoList(SC_HANDLE mngr)
|
||||
{
|
||||
QVector<ServiceInfo> infoList;
|
||||
@ -43,54 +49,94 @@ QVector<ServiceInfo> 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<ServiceInfo> ServiceInfoManager::loadServiceInfoList()
|
||||
{
|
||||
QVector<ServiceInfo> 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<ServiceInfoMonitor *>(sender());
|
||||
Q_ASSERT(m);
|
||||
|
||||
if (state == ServiceInfo::StateDeleted) {
|
||||
stopServiceMonitor(m);
|
||||
|
||||
m_serviceMonitors.remove(m->name());
|
||||
}
|
||||
}
|
||||
|
@ -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<QString, int> &serviceGroups() { return m_serviceGroups; }
|
||||
const QHash<QString, int> &serviceGroups() const { return m_serviceGroups; }
|
||||
int groupIndexByName(const QString &name) const;
|
||||
|
||||
QVector<ServiceInfo> &services() { return m_services; }
|
||||
const QVector<ServiceInfo> &services() const { return m_services; }
|
||||
|
||||
const ServiceInfo &serviceInfoAt(int index) const;
|
||||
static QVector<ServiceInfo> 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<QString, int> m_serviceGroups;
|
||||
QVector<ServiceInfo> m_services;
|
||||
QHash<QString, ServiceInfoMonitor *> m_serviceMonitors;
|
||||
};
|
||||
|
||||
#endif // SERVICEINFOMANAGER_H
|
||||
|
155
src/ui/serviceinfo/serviceinfomonitor.cpp
Normal file
155
src/ui/serviceinfo/serviceinfomonitor.cpp
Normal file
@ -0,0 +1,155 @@
|
||||
#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) {
|
||||
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<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_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;
|
||||
}
|
||||
}
|
||||
}
|
52
src/ui/serviceinfo/serviceinfomonitor.h
Normal file
52
src/ui/serviceinfo/serviceinfomonitor.h
Normal file
@ -0,0 +1,52 @@
|
||||
#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;
|
||||
|
||||
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
|
Loading…
Reference in New Issue
Block a user