mirror of
https://github.com/tnodir/fort
synced 2024-11-14 22:25:40 +00:00
UI: Option to try to start a Service on startup
This commit is contained in:
parent
25f4b41de6
commit
4536d858c4
@ -43,3 +43,6 @@
|
||||
|
||||
;Try to install a driver on opening error.
|
||||
;canInstallDriver=false
|
||||
|
||||
;Try to start a Service on startup.
|
||||
;canStartService=false
|
||||
|
@ -198,6 +198,7 @@ SOURCES += \
|
||||
util/osutil.cpp \
|
||||
util/processinfo.cpp \
|
||||
util/regkey.cpp \
|
||||
util/service/servicehandle.cpp \
|
||||
util/service/serviceinfo.cpp \
|
||||
util/service/servicelistmonitor.cpp \
|
||||
util/service/servicemanageriface.cpp \
|
||||
@ -412,6 +413,7 @@ HEADERS += \
|
||||
util/osutil.h \
|
||||
util/processinfo.h \
|
||||
util/regkey.h \
|
||||
util/service/servicehandle.h \
|
||||
util/service/serviceinfo.h \
|
||||
util/service/servicelistmonitor.h \
|
||||
util/service/servicemanageriface.h \
|
||||
|
@ -179,6 +179,7 @@ void FortManager::initialize()
|
||||
loadConf();
|
||||
|
||||
checkInstallDriver();
|
||||
checkStartService();
|
||||
}
|
||||
|
||||
void FortManager::setupThreadPool()
|
||||
@ -329,14 +330,29 @@ void FortManager::checkInstallDriver()
|
||||
|
||||
const auto settings = IoC<FortSettings>();
|
||||
|
||||
const bool canInstallDriver = (settings->canInstallDriver() || settings->isPortable())
|
||||
&& settings->isMaster() && settings->isUserAdmin();
|
||||
const bool canInstallDriver = (settings->canInstallDriver() || settings->isPortable());
|
||||
const bool isMasterAdmin = (settings->isMaster() && settings->isUserAdmin());
|
||||
|
||||
if (canInstallDriver) {
|
||||
if (canInstallDriver && isMasterAdmin) {
|
||||
installDriver();
|
||||
}
|
||||
}
|
||||
|
||||
void FortManager::checkStartService()
|
||||
{
|
||||
const auto settings = IoC<FortSettings>();
|
||||
|
||||
if (settings->isMaster() || StartupUtil::isServiceRunning())
|
||||
return;
|
||||
|
||||
const bool canStartService = settings->canStartService();
|
||||
const bool isAdmin = settings->isUserAdmin();
|
||||
|
||||
if (canStartService && isAdmin) {
|
||||
StartupUtil::startService();
|
||||
}
|
||||
}
|
||||
|
||||
void FortManager::setupEnvManager()
|
||||
{
|
||||
auto envManager = IoC<EnvManager>();
|
||||
|
@ -45,6 +45,7 @@ private:
|
||||
void closeDriver();
|
||||
|
||||
void checkInstallDriver();
|
||||
void checkStartService();
|
||||
|
||||
void setupEnvManager();
|
||||
void setupConfManager();
|
||||
|
@ -119,6 +119,7 @@ void FortSettings::setupGlobal()
|
||||
|
||||
m_noCache = settings.value("global/noCache").toBool();
|
||||
m_canInstallDriver = settings.value("global/canInstallDriver").toBool();
|
||||
m_canStartService = settings.value("global/canStartService").toBool();
|
||||
m_defaultLanguage = settings.value("global/defaultLanguage").toString();
|
||||
|
||||
m_profilePath = settings.value("global/profileDir").toString();
|
||||
|
@ -33,6 +33,7 @@ public:
|
||||
bool noCache() const { return m_noCache; }
|
||||
bool noSplash() const { return m_noSplash; }
|
||||
bool canInstallDriver() const { return m_canInstallDriver; }
|
||||
bool canStartService() const { return m_canStartService; }
|
||||
|
||||
bool isService() const { return m_isService; }
|
||||
bool hasService() const { return m_hasService; }
|
||||
@ -129,6 +130,7 @@ private:
|
||||
uint m_noCache : 1 = false;
|
||||
uint m_noSplash : 1 = false;
|
||||
uint m_canInstallDriver : 1 = false;
|
||||
uint m_canStartService : 1 = false;
|
||||
uint m_isService : 1 = false;
|
||||
uint m_hasService : 1 = false;
|
||||
uint m_isUserAdmin : 1 = false;
|
||||
|
120
src/ui/util/service/servicehandle.cpp
Normal file
120
src/ui/util/service/servicehandle.cpp
Normal file
@ -0,0 +1,120 @@
|
||||
#include "servicehandle.h"
|
||||
|
||||
#include <QThread>
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <qt_windows.h>
|
||||
|
||||
#include "servicemanageriface.h"
|
||||
|
||||
ServiceHandle::ServiceHandle(
|
||||
const wchar_t *serviceName, quint32 managerAccess, quint32 serviceAccess)
|
||||
{
|
||||
openService(serviceName, managerAccess, serviceAccess);
|
||||
}
|
||||
|
||||
ServiceHandle::~ServiceHandle()
|
||||
{
|
||||
closeService();
|
||||
}
|
||||
|
||||
bool ServiceHandle::queryIsRunning()
|
||||
{
|
||||
SERVICE_STATUS status;
|
||||
if (QueryServiceStatus(SC_HANDLE(m_serviceHandle), &status)) {
|
||||
return (status.dwCurrentState == SERVICE_RUNNING);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ServiceHandle::startService()
|
||||
{
|
||||
return StartServiceW(SC_HANDLE(m_serviceHandle), 0, nullptr);
|
||||
}
|
||||
|
||||
bool ServiceHandle::stopService()
|
||||
{
|
||||
int n = 3; /* count of attempts to stop the service */
|
||||
do {
|
||||
SERVICE_STATUS status;
|
||||
if (QueryServiceStatus(SC_HANDLE(m_serviceHandle), &status)
|
||||
&& status.dwCurrentState == SERVICE_STOPPED)
|
||||
return true;
|
||||
|
||||
const DWORD controlCode = (status.dwControlsAccepted & SERVICE_ACCEPT_STOP) != 0
|
||||
? SERVICE_CONTROL_STOP
|
||||
: FORT_SERVICE_CONTROL_UNINSTALL;
|
||||
|
||||
ControlService(SC_HANDLE(m_serviceHandle), controlCode, &status);
|
||||
|
||||
QThread::msleep(n * 100);
|
||||
} while (--n > 0);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ServiceHandle::createService(const wchar_t *serviceName, const wchar_t *serviceDisplay,
|
||||
const wchar_t *serviceGroup, const wchar_t *dependencies, const QString &command)
|
||||
{
|
||||
m_serviceHandle = qintptr(CreateServiceW(SC_HANDLE(m_managerHandle), serviceName,
|
||||
serviceDisplay, SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START,
|
||||
SERVICE_ERROR_NORMAL, (LPCWSTR) command.utf16(), serviceGroup, 0, dependencies, nullptr,
|
||||
nullptr));
|
||||
}
|
||||
|
||||
bool ServiceHandle::deleteService()
|
||||
{
|
||||
return DeleteService(SC_HANDLE(m_serviceHandle));
|
||||
}
|
||||
|
||||
void ServiceHandle::setServiceDescription(const wchar_t *serviceDescription)
|
||||
{
|
||||
SERVICE_DESCRIPTION sd = { (LPWSTR) serviceDescription };
|
||||
|
||||
ChangeServiceConfig2(SC_HANDLE(m_serviceHandle), SERVICE_CONFIG_DESCRIPTION, &sd);
|
||||
}
|
||||
|
||||
void ServiceHandle::setupServiceRestartConfig()
|
||||
{
|
||||
constexpr int actionsCount = 3;
|
||||
|
||||
SC_ACTION actions[actionsCount];
|
||||
actions[0].Type = SC_ACTION_RESTART;
|
||||
actions[0].Delay = 150;
|
||||
actions[1].Type = SC_ACTION_NONE;
|
||||
actions[1].Delay = 0;
|
||||
actions[2].Type = SC_ACTION_NONE;
|
||||
actions[2].Delay = 0;
|
||||
|
||||
SERVICE_FAILURE_ACTIONS sfa;
|
||||
sfa.dwResetPeriod = 0;
|
||||
sfa.lpCommand = NULL;
|
||||
sfa.lpRebootMsg = NULL;
|
||||
sfa.cActions = actionsCount;
|
||||
sfa.lpsaActions = actions;
|
||||
|
||||
ChangeServiceConfig2(SC_HANDLE(m_serviceHandle), SERVICE_CONFIG_FAILURE_ACTIONS, &sfa);
|
||||
}
|
||||
|
||||
void ServiceHandle::openService(
|
||||
const wchar_t *serviceName, quint32 managerAccess, quint32 serviceAccess)
|
||||
{
|
||||
m_managerHandle = qintptr(OpenSCManagerW(nullptr, nullptr, managerAccess));
|
||||
if (!m_managerHandle)
|
||||
return;
|
||||
|
||||
if (serviceAccess != 0) {
|
||||
m_serviceHandle =
|
||||
qintptr(OpenServiceW(SC_HANDLE(m_managerHandle), serviceName, serviceAccess));
|
||||
}
|
||||
}
|
||||
|
||||
void ServiceHandle::closeService()
|
||||
{
|
||||
if (m_serviceHandle) {
|
||||
CloseServiceHandle(SC_HANDLE(m_serviceHandle));
|
||||
}
|
||||
if (m_managerHandle) {
|
||||
CloseServiceHandle(SC_HANDLE(m_managerHandle));
|
||||
}
|
||||
}
|
37
src/ui/util/service/servicehandle.h
Normal file
37
src/ui/util/service/servicehandle.h
Normal file
@ -0,0 +1,37 @@
|
||||
#ifndef SERVICEHANDLE_H
|
||||
#define SERVICEHANDLE_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class ServiceHandle final
|
||||
{
|
||||
public:
|
||||
explicit ServiceHandle(
|
||||
const wchar_t *serviceName, quint32 managerAccess = 0, quint32 serviceAccess = 0);
|
||||
~ServiceHandle();
|
||||
|
||||
bool isManagerOpened() const { return m_managerHandle != 0; }
|
||||
bool isServiceOpened() const { return m_serviceHandle != 0; }
|
||||
|
||||
bool queryIsRunning();
|
||||
|
||||
bool startService();
|
||||
bool stopService();
|
||||
|
||||
void createService(const wchar_t *serviceName, const wchar_t *serviceDisplay,
|
||||
const wchar_t *serviceGroup, const wchar_t *dependencies, const QString &command);
|
||||
bool deleteService();
|
||||
|
||||
void setServiceDescription(const wchar_t *serviceDescription);
|
||||
void setupServiceRestartConfig();
|
||||
|
||||
private:
|
||||
void openService(const wchar_t *serviceName, quint32 managerAccess, quint32 serviceAccess);
|
||||
void closeService();
|
||||
|
||||
private:
|
||||
qintptr m_managerHandle = 0;
|
||||
qintptr m_serviceHandle = 0;
|
||||
};
|
||||
|
||||
#endif // SERVICEHANDLE_H
|
@ -9,9 +9,10 @@
|
||||
|
||||
#include <fort_version_l.h>
|
||||
|
||||
#include "fileutil.h"
|
||||
#include "regkey.h"
|
||||
#include "service/servicemanageriface.h"
|
||||
#include <util/fileutil.h>
|
||||
#include <util/regkey.h>
|
||||
#include <util/service/servicehandle.h>
|
||||
#include <util/service/servicemanageriface.h>
|
||||
|
||||
namespace {
|
||||
|
||||
@ -91,87 +92,34 @@ void removeAutorunForAllUsers()
|
||||
removeAutorunForUser(regAllUsersRoot, regAllUsersRun);
|
||||
}
|
||||
|
||||
static void setupServiceRestartConfig(SC_HANDLE svc)
|
||||
{
|
||||
constexpr int actionsCount = 3;
|
||||
|
||||
SC_ACTION actions[actionsCount];
|
||||
actions[0].Type = SC_ACTION_RESTART;
|
||||
actions[0].Delay = 150;
|
||||
actions[1].Type = SC_ACTION_NONE;
|
||||
actions[1].Delay = 0;
|
||||
actions[2].Type = SC_ACTION_NONE;
|
||||
actions[2].Delay = 0;
|
||||
|
||||
SERVICE_FAILURE_ACTIONS sfa;
|
||||
sfa.dwResetPeriod = 0;
|
||||
sfa.lpCommand = NULL;
|
||||
sfa.lpRebootMsg = NULL;
|
||||
sfa.cActions = actionsCount;
|
||||
sfa.lpsaActions = actions;
|
||||
|
||||
ChangeServiceConfig2(svc, SERVICE_CONFIG_FAILURE_ACTIONS, &sfa);
|
||||
}
|
||||
|
||||
bool installService(const wchar_t *serviceName, const wchar_t *serviceDisplay,
|
||||
const wchar_t *serviceDescription, const wchar_t *serviceGroup, const wchar_t *dependencies,
|
||||
const QString &command)
|
||||
{
|
||||
bool res = false;
|
||||
const SC_HANDLE mngr = OpenSCManagerW(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
|
||||
if (mngr) {
|
||||
const SC_HANDLE svc = CreateServiceW(mngr, serviceName, serviceDisplay, SERVICE_ALL_ACCESS,
|
||||
SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL,
|
||||
(LPCWSTR) command.utf16(), serviceGroup, 0, dependencies, nullptr, nullptr);
|
||||
if (svc) {
|
||||
SERVICE_DESCRIPTION sd = { (LPWSTR) serviceDescription };
|
||||
ChangeServiceConfig2(svc, SERVICE_CONFIG_DESCRIPTION, &sd);
|
||||
ServiceHandle svc(serviceName, SC_MANAGER_CREATE_SERVICE);
|
||||
if (!svc.isManagerOpened())
|
||||
return false;
|
||||
|
||||
setupServiceRestartConfig(svc);
|
||||
svc.createService(serviceName, serviceDisplay, serviceGroup, dependencies, command);
|
||||
if (!svc.isServiceOpened())
|
||||
return false;
|
||||
|
||||
res = true;
|
||||
CloseServiceHandle(svc);
|
||||
}
|
||||
CloseServiceHandle(mngr);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
svc.setServiceDescription(serviceDescription);
|
||||
svc.setupServiceRestartConfig();
|
||||
|
||||
bool stopServiceControl(SC_HANDLE svc)
|
||||
{
|
||||
int n = 3; /* count of attempts to stop the service */
|
||||
do {
|
||||
SERVICE_STATUS status;
|
||||
if (QueryServiceStatus(svc, &status) && status.dwCurrentState == SERVICE_STOPPED)
|
||||
return true;
|
||||
|
||||
const DWORD controlCode = (status.dwControlsAccepted & SERVICE_ACCEPT_STOP) != 0
|
||||
? SERVICE_CONTROL_STOP
|
||||
: FORT_SERVICE_CONTROL_UNINSTALL;
|
||||
|
||||
ControlService(svc, controlCode, &status);
|
||||
|
||||
QThread::msleep(n * 100);
|
||||
} while (--n > 0);
|
||||
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool uninstallService(const wchar_t *serviceName)
|
||||
{
|
||||
bool res = false;
|
||||
const SC_HANDLE mngr = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
|
||||
if (mngr) {
|
||||
const SC_HANDLE svc = OpenServiceW(mngr, serviceName, SERVICE_ALL_ACCESS | DELETE);
|
||||
if (svc) {
|
||||
stopServiceControl(svc);
|
||||
ServiceHandle svc(serviceName, SC_MANAGER_ALL_ACCESS, SERVICE_ALL_ACCESS | DELETE);
|
||||
if (svc.isServiceOpened()) {
|
||||
svc.stopService();
|
||||
|
||||
res = DeleteService(svc);
|
||||
CloseServiceHandle(svc);
|
||||
}
|
||||
CloseServiceHandle(mngr);
|
||||
return svc.deleteService();
|
||||
}
|
||||
return res;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@ -183,17 +131,9 @@ const wchar_t *StartupUtil::serviceName()
|
||||
|
||||
bool StartupUtil::isServiceInstalled()
|
||||
{
|
||||
bool res = false;
|
||||
const SC_HANDLE mngr = OpenSCManagerW(nullptr, nullptr, SC_MANAGER_CONNECT);
|
||||
if (mngr) {
|
||||
const SC_HANDLE svc = OpenServiceW(mngr, serviceNameStr, SERVICE_INTERROGATE);
|
||||
if (svc) {
|
||||
res = true;
|
||||
CloseServiceHandle(svc);
|
||||
}
|
||||
CloseServiceHandle(mngr);
|
||||
}
|
||||
return res;
|
||||
ServiceHandle svc(serviceNameStr, SC_MANAGER_CONNECT, SERVICE_INTERROGATE);
|
||||
|
||||
return svc.isServiceOpened();
|
||||
}
|
||||
|
||||
void StartupUtil::setServiceInstalled(bool install)
|
||||
@ -209,36 +149,38 @@ void StartupUtil::setServiceInstalled(bool install)
|
||||
serviceDependenciesStr, command);
|
||||
|
||||
startService();
|
||||
|
||||
QThread::msleep(100); // Let the service to start
|
||||
}
|
||||
|
||||
bool StartupUtil::isServiceRunning()
|
||||
{
|
||||
ServiceHandle svc(serviceNameStr, SC_MANAGER_CONNECT, SERVICE_INTERROGATE);
|
||||
if (svc.isServiceOpened()) {
|
||||
return svc.queryIsRunning();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool StartupUtil::startService()
|
||||
{
|
||||
bool res = false;
|
||||
const SC_HANDLE mngr = OpenSCManagerW(nullptr, nullptr, SC_MANAGER_CONNECT);
|
||||
if (mngr) {
|
||||
const SC_HANDLE svc = OpenServiceW(mngr, serviceNameStr, SERVICE_START);
|
||||
if (svc) {
|
||||
res = StartServiceW(svc, 0, nullptr);
|
||||
CloseServiceHandle(svc);
|
||||
}
|
||||
CloseServiceHandle(mngr);
|
||||
ServiceHandle svc(serviceNameStr, SC_MANAGER_CONNECT, SERVICE_START);
|
||||
if (svc.isServiceOpened()) {
|
||||
return svc.startService();
|
||||
}
|
||||
return res;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool StartupUtil::stopService()
|
||||
{
|
||||
bool res = false;
|
||||
const SC_HANDLE mngr = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
|
||||
if (mngr) {
|
||||
const SC_HANDLE svc = OpenServiceW(mngr, serviceNameStr, SERVICE_ALL_ACCESS);
|
||||
if (svc) {
|
||||
res = stopServiceControl(svc);
|
||||
}
|
||||
CloseServiceHandle(mngr);
|
||||
ServiceHandle svc(serviceNameStr, SC_MANAGER_ALL_ACCESS, SERVICE_ALL_ACCESS);
|
||||
if (svc.isServiceOpened()) {
|
||||
return svc.stopService();
|
||||
}
|
||||
return res;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
StartupUtil::AutoRunMode StartupUtil::autoRunMode()
|
||||
|
@ -13,6 +13,8 @@ public:
|
||||
static bool isServiceInstalled();
|
||||
static void setServiceInstalled(bool install);
|
||||
|
||||
static bool isServiceRunning();
|
||||
|
||||
static bool startService();
|
||||
static bool stopService();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user