mirror of
https://github.com/tnodir/fort
synced 2024-11-15 06:06:30 +00:00
UI: Prepare ServiceListMonitor
This commit is contained in:
parent
ef1fcf84b9
commit
706694bec9
@ -112,6 +112,7 @@ SOURCES += \
|
||||
serviceinfo/serviceinfo.cpp \
|
||||
serviceinfo/serviceinfomanager.cpp \
|
||||
serviceinfo/serviceinfomonitor.cpp \
|
||||
serviceinfo/servicelistmonitor.cpp \
|
||||
stat/quotamanager.cpp \
|
||||
stat/statmanager.cpp \
|
||||
stat/statsql.cpp \
|
||||
@ -266,6 +267,7 @@ HEADERS += \
|
||||
serviceinfo/serviceinfo.h \
|
||||
serviceinfo/serviceinfomanager.h \
|
||||
serviceinfo/serviceinfomonitor.h \
|
||||
serviceinfo/servicelistmonitor.h \
|
||||
stat/quotamanager.h \
|
||||
stat/statmanager.h \
|
||||
stat/statsql.h \
|
||||
|
@ -6,12 +6,13 @@
|
||||
#include <qt_windows.h>
|
||||
|
||||
#include "serviceinfomonitor.h"
|
||||
#include "servicelistmonitor.h"
|
||||
|
||||
namespace {
|
||||
|
||||
const QLoggingCategory LC("serviceInfo.serviceInfoManager");
|
||||
|
||||
QVector<ServiceInfo> getServiceInfoList(SC_HANDLE mngr)
|
||||
QVector<ServiceInfo> getServiceInfoList(SC_HANDLE mngr, DWORD state = SERVICE_STATE_ALL)
|
||||
{
|
||||
QVector<ServiceInfo> infoList;
|
||||
|
||||
@ -21,9 +22,8 @@ QVector<ServiceInfo> getServiceInfoList(SC_HANDLE mngr)
|
||||
DWORD serviceCount = 0;
|
||||
DWORD resumePoint = 0;
|
||||
|
||||
while (EnumServicesStatusExW(mngr, SC_ENUM_PROCESS_INFO, SERVICE_WIN32, SERVICE_STATE_ALL,
|
||||
(LPBYTE) buffer, sizeof(buffer), &bytesRemaining, &serviceCount, &resumePoint,
|
||||
nullptr)
|
||||
while (EnumServicesStatusExW(mngr, SC_ENUM_PROCESS_INFO, SERVICE_WIN32, state, (LPBYTE) buffer,
|
||||
sizeof(buffer), &bytesRemaining, &serviceCount, &resumePoint, nullptr)
|
||||
|| GetLastError() == ERROR_MORE_DATA) {
|
||||
|
||||
int infoIndex = infoList.size();
|
||||
@ -52,6 +52,7 @@ ServiceInfoManager::ServiceInfoManager(QObject *parent) : QObject(parent) { }
|
||||
ServiceInfoManager::~ServiceInfoManager()
|
||||
{
|
||||
clearServiceMonitors();
|
||||
stopServiceListMonitor();
|
||||
}
|
||||
|
||||
void ServiceInfoManager::setMonitorEnabled(bool v)
|
||||
@ -94,37 +95,61 @@ void ServiceInfoManager::setupServiceMonitors()
|
||||
return;
|
||||
}
|
||||
|
||||
const auto services = loadServiceInfoList();
|
||||
const auto services = getServiceInfoList(mngr);
|
||||
for (const auto &info : services) {
|
||||
const auto m = startServiceMonitor(info, mngr);
|
||||
|
||||
m_serviceMonitors.insert(info.serviceName, m);
|
||||
startServiceMonitor(info.serviceName, info.processId, mngr);
|
||||
}
|
||||
|
||||
CloseServiceHandle(mngr);
|
||||
startServiceListMonitor(mngr);
|
||||
}
|
||||
|
||||
void ServiceInfoManager::clearServiceMonitors()
|
||||
{
|
||||
const auto moniros = m_serviceMonitors.values();
|
||||
for (ServiceInfoMonitor *m : moniros) {
|
||||
const auto monitors = m_serviceMonitors.values();
|
||||
m_serviceMonitors.clear();
|
||||
|
||||
for (ServiceInfoMonitor *m : monitors) {
|
||||
stopServiceMonitor(m);
|
||||
}
|
||||
m_serviceMonitors.clear();
|
||||
}
|
||||
|
||||
ServiceInfoMonitor *ServiceInfoManager::startServiceMonitor(
|
||||
const ServiceInfo &info, void *managerHandle)
|
||||
void ServiceInfoManager::startServiceMonitor(
|
||||
const QString &name, quint32 processId, void *managerHandle)
|
||||
{
|
||||
const auto m = new ServiceInfoMonitor(info.processId, info.serviceName, managerHandle);
|
||||
auto m = new ServiceInfoMonitor(processId, name, managerHandle);
|
||||
|
||||
connect(m, &ServiceInfoMonitor::stateChanged, this, &ServiceInfoManager::onServiceStateChanged);
|
||||
connect(m, &ServiceInfoMonitor::stateChanged, this, &ServiceInfoManager::onServiceStateChanged,
|
||||
Qt::QueuedConnection);
|
||||
|
||||
return m;
|
||||
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);
|
||||
|
||||
m_serviceListMonitor = m;
|
||||
}
|
||||
|
||||
void ServiceInfoManager::stopServiceListMonitor()
|
||||
{
|
||||
auto m = m_serviceListMonitor;
|
||||
if (!m)
|
||||
return;
|
||||
|
||||
m_serviceListMonitor = nullptr;
|
||||
|
||||
m->terminate();
|
||||
m->deleteLater();
|
||||
}
|
||||
@ -136,7 +161,12 @@ void ServiceInfoManager::onServiceStateChanged(ServiceInfo::State state)
|
||||
|
||||
if (state == ServiceInfo::StateDeleted) {
|
||||
stopServiceMonitor(m);
|
||||
|
||||
m_serviceMonitors.remove(m->name());
|
||||
}
|
||||
}
|
||||
|
||||
void ServiceInfoManager::onServiceCreated(const QStringList &nameList)
|
||||
{
|
||||
for (const auto &name : nameList) {
|
||||
startServiceMonitor(name);
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "serviceinfo.h"
|
||||
|
||||
class ServiceInfoMonitor;
|
||||
class ServiceListMonitor;
|
||||
|
||||
class ServiceInfoManager : public QObject, public IocService
|
||||
{
|
||||
@ -32,16 +33,22 @@ private:
|
||||
void setupServiceMonitors();
|
||||
void clearServiceMonitors();
|
||||
|
||||
ServiceInfoMonitor *startServiceMonitor(const ServiceInfo &info, void *managerHandle);
|
||||
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);
|
||||
void onServiceCreated(const QStringList &nameList);
|
||||
|
||||
private:
|
||||
bool m_monitorEnabled = false;
|
||||
|
||||
QHash<QString, int> m_serviceGroups;
|
||||
QHash<QString, ServiceInfoMonitor *> m_serviceMonitors;
|
||||
ServiceListMonitor *m_serviceListMonitor = nullptr;
|
||||
};
|
||||
|
||||
#endif // SERVICEINFOMANAGER_H
|
||||
|
@ -38,10 +38,7 @@ static void CALLBACK notifyCallback(PVOID parameter)
|
||||
|
||||
PSERVICE_NOTIFYW getNotifyBuffer(ServiceInfoMonitor *m)
|
||||
{
|
||||
QByteArray &buffer = m->notifyBuffer();
|
||||
if (buffer.isNull()) {
|
||||
buffer = QByteArray(sizeof(SERVICE_NOTIFYW), '\0');
|
||||
}
|
||||
auto &buffer = m->notifyBuffer();
|
||||
|
||||
PSERVICE_NOTIFYW notify = reinterpret_cast<PSERVICE_NOTIFYW>(buffer.data());
|
||||
|
||||
@ -61,14 +58,15 @@ ServiceInfoMonitor::ServiceInfoMonitor(
|
||||
m_isReopening(false),
|
||||
m_startNotifierRequested(false),
|
||||
m_processId(processId),
|
||||
m_name(name)
|
||||
m_name(name),
|
||||
m_notifyBuffer(sizeof(SERVICE_NOTIFYW))
|
||||
{
|
||||
openService(managerHandle);
|
||||
}
|
||||
|
||||
ServiceInfoMonitor::~ServiceInfoMonitor()
|
||||
{
|
||||
closeService();
|
||||
terminate();
|
||||
}
|
||||
|
||||
void ServiceInfoMonitor::terminate()
|
||||
|
@ -19,7 +19,7 @@ public:
|
||||
|
||||
QString name() const { return m_name; }
|
||||
|
||||
QByteArray ¬ifyBuffer() { return m_notifyBuffer; }
|
||||
QVector<char> ¬ifyBuffer() { return m_notifyBuffer; }
|
||||
|
||||
signals:
|
||||
void stateChanged(ServiceInfo::State state);
|
||||
@ -43,10 +43,10 @@ private:
|
||||
|
||||
quint32 m_processId = 0;
|
||||
|
||||
void *m_serviceHandle = nullptr;
|
||||
QByteArray m_notifyBuffer;
|
||||
|
||||
const QString m_name;
|
||||
|
||||
void *m_serviceHandle = nullptr;
|
||||
QVector<char> m_notifyBuffer;
|
||||
};
|
||||
|
||||
#endif // SERVICEINFOMONITOR_H
|
||||
|
156
src/ui/serviceinfo/servicelistmonitor.cpp
Normal file
156
src/ui/serviceinfo/servicelistmonitor.cpp
Normal file
@ -0,0 +1,156 @@
|
||||
#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] == '/');
|
||||
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)
|
||||
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_startNotifierRequested(false),
|
||||
m_managerHandle(managerHandle),
|
||||
m_notifyBuffer(sizeof(SERVICE_NOTIFYW))
|
||||
{
|
||||
openManager();
|
||||
}
|
||||
|
||||
ServiceListMonitor::~ServiceListMonitor()
|
||||
{
|
||||
terminate();
|
||||
}
|
||||
|
||||
void ServiceListMonitor::terminate()
|
||||
{
|
||||
m_terminated = true;
|
||||
|
||||
closeManager();
|
||||
}
|
||||
|
||||
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();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
startNotifier();
|
||||
}
|
||||
|
||||
void ServiceListMonitor::closeManager()
|
||||
{
|
||||
if (m_managerHandle) {
|
||||
CloseServiceHandle(managerHandle());
|
||||
m_managerHandle = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void ServiceListMonitor::reopenManager()
|
||||
{
|
||||
if (m_isReopening) {
|
||||
qCCritical(LC) << "Reopen manager error";
|
||||
return;
|
||||
}
|
||||
|
||||
m_isReopening = true;
|
||||
|
||||
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) {
|
||||
if (res == ERROR_SERVICE_NOTIFY_CLIENT_LAGGING) {
|
||||
qCDebug(LC) << "Notifier is lagging";
|
||||
reopenManager();
|
||||
} else {
|
||||
qCCritical(LC) << "Start notifier error:" << res;
|
||||
}
|
||||
}
|
||||
}
|
40
src/ui/serviceinfo/servicelistmonitor.h
Normal file
40
src/ui/serviceinfo/servicelistmonitor.h
Normal file
@ -0,0 +1,40 @@
|
||||
#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);
|
||||
|
||||
public slots:
|
||||
void terminate();
|
||||
|
||||
void requestStartNotifier();
|
||||
|
||||
private:
|
||||
void openManager();
|
||||
void closeManager();
|
||||
void reopenManager();
|
||||
|
||||
void startNotifier();
|
||||
|
||||
private:
|
||||
bool m_terminated : 1;
|
||||
bool m_isReopening : 1;
|
||||
bool m_startNotifierRequested : 1;
|
||||
|
||||
void *m_managerHandle = nullptr;
|
||||
QVector<char> m_notifyBuffer;
|
||||
};
|
||||
|
||||
#endif // SERVICELISTMONITOR_H
|
Loading…
Reference in New Issue
Block a user