From 4257457881dff93d6d1991e93b7bf698717b4b04 Mon Sep 17 00:00:00 2001 From: APTX Date: Sat, 2 Mar 2013 15:23:30 +0100 Subject: [PATCH] Hopefully port qtservice to Qt5. --- anioni/qtservice/qtservice_win.cpp | 1228 ++++++++++++++-------------- 1 file changed, 633 insertions(+), 595 deletions(-) diff --git a/anioni/qtservice/qtservice_win.cpp b/anioni/qtservice/qtservice_win.cpp index 74e885b..15ba125 100644 --- a/anioni/qtservice/qtservice_win.cpp +++ b/anioni/qtservice/qtservice_win.cpp @@ -58,6 +58,25 @@ #include #endif +#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) +# include + +typedef bool (*QtServiceEvent)(void *message, long *result) ; + +class QtServiceEventFilter : public QAbstractNativeEventFilter +{ +public: + QtServiceEventFilter(QtServiceEvent e) : ev(e) {} + virtual bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) Q_DECL_OVERRIDE + { + Q_UNUSED(eventType); + return ev(message, result); + } +private: + QtServiceEvent ev; +}; +#endif + typedef SERVICE_STATUS_HANDLE(WINAPI*PRegisterServiceCtrlHandler)(const wchar_t*,LPHANDLER_FUNCTION); static PRegisterServiceCtrlHandler pRegisterServiceCtrlHandler = 0; typedef BOOL(WINAPI*PSetServiceStatus)(SERVICE_STATUS_HANDLE,LPSERVICE_STATUS); @@ -102,290 +121,290 @@ static PQueryServiceConfig2 pQueryServiceConfig2 = 0; static bool winServiceInit() { - if (!pOpenSCManager) { - QLibrary lib("advapi32"); - - // only resolve unicode versions - RESOLVEW(RegisterServiceCtrlHandler); - RESOLVE(SetServiceStatus); - RESOLVEW(ChangeServiceConfig2); - RESOLVE(CloseServiceHandle); - RESOLVEW(CreateService); - RESOLVEW(OpenSCManager); - RESOLVE(DeleteService); - RESOLVEW(OpenService); - RESOLVE(QueryServiceStatus); - RESOLVEW(StartServiceCtrlDispatcher); - RESOLVEW(StartService); // need only Ansi version - RESOLVE(ControlService); - RESOLVE(DeregisterEventSource); - RESOLVEW(ReportEvent); - RESOLVEW(RegisterEventSource); - RESOLVEW(QueryServiceConfig); - RESOLVEW(QueryServiceConfig2); - } - return pOpenSCManager != 0; + if (!pOpenSCManager) { + QLibrary lib("advapi32"); + + // only resolve unicode versions + RESOLVEW(RegisterServiceCtrlHandler); + RESOLVE(SetServiceStatus); + RESOLVEW(ChangeServiceConfig2); + RESOLVE(CloseServiceHandle); + RESOLVEW(CreateService); + RESOLVEW(OpenSCManager); + RESOLVE(DeleteService); + RESOLVEW(OpenService); + RESOLVE(QueryServiceStatus); + RESOLVEW(StartServiceCtrlDispatcher); + RESOLVEW(StartService); // need only Ansi version + RESOLVE(ControlService); + RESOLVE(DeregisterEventSource); + RESOLVEW(ReportEvent); + RESOLVEW(RegisterEventSource); + RESOLVEW(QueryServiceConfig); + RESOLVEW(QueryServiceConfig2); + } + return pOpenSCManager != 0; } bool QtServiceController::isInstalled() const { - Q_D(const QtServiceController); - bool result = false; - if (!winServiceInit()) - return result; - - // Open the Service Control Manager - SC_HANDLE hSCM = pOpenSCManager(0, 0, 0); - if (hSCM) { - // Try to open the service - SC_HANDLE hService = pOpenService(hSCM, (wchar_t*)d->serviceName.utf16(), - SERVICE_QUERY_CONFIG); - - if (hService) { - result = true; - pCloseServiceHandle(hService); - } - pCloseServiceHandle(hSCM); - } - return result; + Q_D(const QtServiceController); + bool result = false; + if (!winServiceInit()) + return result; + + // Open the Service Control Manager + SC_HANDLE hSCM = pOpenSCManager(0, 0, 0); + if (hSCM) { + // Try to open the service + SC_HANDLE hService = pOpenService(hSCM, (wchar_t*)d->serviceName.utf16(), + SERVICE_QUERY_CONFIG); + + if (hService) { + result = true; + pCloseServiceHandle(hService); + } + pCloseServiceHandle(hSCM); + } + return result; } bool QtServiceController::isRunning() const { - Q_D(const QtServiceController); - bool result = false; - if (!winServiceInit()) - return result; - - // Open the Service Control Manager - SC_HANDLE hSCM = pOpenSCManager(0, 0, 0); - if (hSCM) { - // Try to open the service - SC_HANDLE hService = pOpenService(hSCM, (wchar_t *)d->serviceName.utf16(), - SERVICE_QUERY_STATUS); - if (hService) { - SERVICE_STATUS info; - int res = pQueryServiceStatus(hService, &info); - if (res) - result = info.dwCurrentState != SERVICE_STOPPED; - pCloseServiceHandle(hService); - } - pCloseServiceHandle(hSCM); - } - return result; + Q_D(const QtServiceController); + bool result = false; + if (!winServiceInit()) + return result; + + // Open the Service Control Manager + SC_HANDLE hSCM = pOpenSCManager(0, 0, 0); + if (hSCM) { + // Try to open the service + SC_HANDLE hService = pOpenService(hSCM, (wchar_t *)d->serviceName.utf16(), + SERVICE_QUERY_STATUS); + if (hService) { + SERVICE_STATUS info; + int res = pQueryServiceStatus(hService, &info); + if (res) + result = info.dwCurrentState != SERVICE_STOPPED; + pCloseServiceHandle(hService); + } + pCloseServiceHandle(hSCM); + } + return result; } QString QtServiceController::serviceFilePath() const { - Q_D(const QtServiceController); - QString result; - if (!winServiceInit()) - return result; - - // Open the Service Control Manager - SC_HANDLE hSCM = pOpenSCManager(0, 0, 0); - if (hSCM) { - // Try to open the service - SC_HANDLE hService = pOpenService(hSCM, (wchar_t *)d->serviceName.utf16(), - SERVICE_QUERY_CONFIG); - if (hService) { - DWORD sizeNeeded = 0; - char data[8 * 1024]; - if (pQueryServiceConfig(hService, (LPQUERY_SERVICE_CONFIG)data, 8 * 1024, &sizeNeeded)) { - LPQUERY_SERVICE_CONFIG config = (LPQUERY_SERVICE_CONFIG)data; - result = QString::fromUtf16((const ushort*)config->lpBinaryPathName); - } - pCloseServiceHandle(hService); - } - pCloseServiceHandle(hSCM); - } - return result; + Q_D(const QtServiceController); + QString result; + if (!winServiceInit()) + return result; + + // Open the Service Control Manager + SC_HANDLE hSCM = pOpenSCManager(0, 0, 0); + if (hSCM) { + // Try to open the service + SC_HANDLE hService = pOpenService(hSCM, (wchar_t *)d->serviceName.utf16(), + SERVICE_QUERY_CONFIG); + if (hService) { + DWORD sizeNeeded = 0; + char data[8 * 1024]; + if (pQueryServiceConfig(hService, (LPQUERY_SERVICE_CONFIG)data, 8 * 1024, &sizeNeeded)) { + LPQUERY_SERVICE_CONFIG config = (LPQUERY_SERVICE_CONFIG)data; + result = QString::fromUtf16((const ushort*)config->lpBinaryPathName); + } + pCloseServiceHandle(hService); + } + pCloseServiceHandle(hSCM); + } + return result; } QString QtServiceController::serviceDescription() const { - Q_D(const QtServiceController); - QString result; - if (!winServiceInit()) - return result; - - // Open the Service Control Manager - SC_HANDLE hSCM = pOpenSCManager(0, 0, 0); - if (hSCM) { - // Try to open the service - SC_HANDLE hService = pOpenService(hSCM, (wchar_t *)d->serviceName.utf16(), - SERVICE_QUERY_CONFIG); - if (hService) { - DWORD dwBytesNeeded; - char data[8 * 1024]; - if (pQueryServiceConfig2( - hService, - SERVICE_CONFIG_DESCRIPTION, - (unsigned char *)data, - 8096, - &dwBytesNeeded)) { - LPSERVICE_DESCRIPTION desc = (LPSERVICE_DESCRIPTION)data; - if (desc->lpDescription) - result = QString::fromUtf16((const ushort*)desc->lpDescription); - } - pCloseServiceHandle(hService); - } - pCloseServiceHandle(hSCM); - } - return result; + Q_D(const QtServiceController); + QString result; + if (!winServiceInit()) + return result; + + // Open the Service Control Manager + SC_HANDLE hSCM = pOpenSCManager(0, 0, 0); + if (hSCM) { + // Try to open the service + SC_HANDLE hService = pOpenService(hSCM, (wchar_t *)d->serviceName.utf16(), + SERVICE_QUERY_CONFIG); + if (hService) { + DWORD dwBytesNeeded; + char data[8 * 1024]; + if (pQueryServiceConfig2( + hService, + SERVICE_CONFIG_DESCRIPTION, + (unsigned char *)data, + 8096, + &dwBytesNeeded)) { + LPSERVICE_DESCRIPTION desc = (LPSERVICE_DESCRIPTION)data; + if (desc->lpDescription) + result = QString::fromUtf16((const ushort*)desc->lpDescription); + } + pCloseServiceHandle(hService); + } + pCloseServiceHandle(hSCM); + } + return result; } QtServiceController::StartupType QtServiceController::startupType() const { - Q_D(const QtServiceController); - StartupType result = ManualStartup; - if (!winServiceInit()) - return result; - - // Open the Service Control Manager - SC_HANDLE hSCM = pOpenSCManager(0, 0, 0); - if (hSCM) { - // Try to open the service - SC_HANDLE hService = pOpenService(hSCM, (wchar_t *)d->serviceName.utf16(), - SERVICE_QUERY_CONFIG); - if (hService) { - DWORD sizeNeeded = 0; - char data[8 * 1024]; - if (pQueryServiceConfig(hService, (QUERY_SERVICE_CONFIG *)data, 8 * 1024, &sizeNeeded)) { - QUERY_SERVICE_CONFIG *config = (QUERY_SERVICE_CONFIG *)data; - result = config->dwStartType == SERVICE_DEMAND_START ? ManualStartup : AutoStartup; - } - pCloseServiceHandle(hService); - } - pCloseServiceHandle(hSCM); - } - return result; + Q_D(const QtServiceController); + StartupType result = ManualStartup; + if (!winServiceInit()) + return result; + + // Open the Service Control Manager + SC_HANDLE hSCM = pOpenSCManager(0, 0, 0); + if (hSCM) { + // Try to open the service + SC_HANDLE hService = pOpenService(hSCM, (wchar_t *)d->serviceName.utf16(), + SERVICE_QUERY_CONFIG); + if (hService) { + DWORD sizeNeeded = 0; + char data[8 * 1024]; + if (pQueryServiceConfig(hService, (QUERY_SERVICE_CONFIG *)data, 8 * 1024, &sizeNeeded)) { + QUERY_SERVICE_CONFIG *config = (QUERY_SERVICE_CONFIG *)data; + result = config->dwStartType == SERVICE_DEMAND_START ? ManualStartup : AutoStartup; + } + pCloseServiceHandle(hService); + } + pCloseServiceHandle(hSCM); + } + return result; } bool QtServiceController::uninstall() { - Q_D(QtServiceController); - bool result = false; - if (!winServiceInit()) - return result; - - // Open the Service Control Manager - SC_HANDLE hSCM = pOpenSCManager(0, 0, SC_MANAGER_ALL_ACCESS); - if (hSCM) { - // Try to open the service - SC_HANDLE hService = pOpenService(hSCM, (wchar_t *)d->serviceName.utf16(), DELETE); - if (hService) { - if (pDeleteService(hService)) - result = true; - pCloseServiceHandle(hService); - } - pCloseServiceHandle(hSCM); - } - return result; + Q_D(QtServiceController); + bool result = false; + if (!winServiceInit()) + return result; + + // Open the Service Control Manager + SC_HANDLE hSCM = pOpenSCManager(0, 0, SC_MANAGER_ALL_ACCESS); + if (hSCM) { + // Try to open the service + SC_HANDLE hService = pOpenService(hSCM, (wchar_t *)d->serviceName.utf16(), DELETE); + if (hService) { + if (pDeleteService(hService)) + result = true; + pCloseServiceHandle(hService); + } + pCloseServiceHandle(hSCM); + } + return result; } bool QtServiceController::start(const QStringList &args) { - Q_D(QtServiceController); - bool result = false; - if (!winServiceInit()) - return result; - - // Open the Service Control Manager - SC_HANDLE hSCM = pOpenSCManager(0, 0, SC_MANAGER_CONNECT); - if (hSCM) { - // Try to open the service - SC_HANDLE hService = pOpenService(hSCM, (wchar_t *)d->serviceName.utf16(), SERVICE_START); - if (hService) { - QVector argv(args.size()); - for (int i = 0; i < args.size(); ++i) - argv[i] = (const wchar_t*)args.at(i).utf16(); - - if (pStartService(hService, args.size(), argv.data())) - result = true; - pCloseServiceHandle(hService); - } - pCloseServiceHandle(hSCM); - } - return result; + Q_D(QtServiceController); + bool result = false; + if (!winServiceInit()) + return result; + + // Open the Service Control Manager + SC_HANDLE hSCM = pOpenSCManager(0, 0, SC_MANAGER_CONNECT); + if (hSCM) { + // Try to open the service + SC_HANDLE hService = pOpenService(hSCM, (wchar_t *)d->serviceName.utf16(), SERVICE_START); + if (hService) { + QVector argv(args.size()); + for (int i = 0; i < args.size(); ++i) + argv[i] = (const wchar_t*)args.at(i).utf16(); + + if (pStartService(hService, args.size(), argv.data())) + result = true; + pCloseServiceHandle(hService); + } + pCloseServiceHandle(hSCM); + } + return result; } bool QtServiceController::stop() { - Q_D(QtServiceController); - bool result = false; - if (!winServiceInit()) - return result; - - SC_HANDLE hSCM = pOpenSCManager(0, 0, SC_MANAGER_CONNECT); - if (hSCM) { - SC_HANDLE hService = pOpenService(hSCM, (wchar_t *)d->serviceName.utf16(), SERVICE_STOP|SERVICE_QUERY_STATUS); - if (hService) { - SERVICE_STATUS status; - if (pControlService(hService, SERVICE_CONTROL_STOP, &status)) { - bool stopped = status.dwCurrentState == SERVICE_STOPPED; - int i = 0; - while(!stopped && i < 10) { - Sleep(200); - if (!pQueryServiceStatus(hService, &status)) - break; - stopped = status.dwCurrentState == SERVICE_STOPPED; - ++i; - } - result = stopped; - } else { - qErrnoWarning(GetLastError(), "stopping"); - } - pCloseServiceHandle(hService); - } - pCloseServiceHandle(hSCM); - } - return result; + Q_D(QtServiceController); + bool result = false; + if (!winServiceInit()) + return result; + + SC_HANDLE hSCM = pOpenSCManager(0, 0, SC_MANAGER_CONNECT); + if (hSCM) { + SC_HANDLE hService = pOpenService(hSCM, (wchar_t *)d->serviceName.utf16(), SERVICE_STOP|SERVICE_QUERY_STATUS); + if (hService) { + SERVICE_STATUS status; + if (pControlService(hService, SERVICE_CONTROL_STOP, &status)) { + bool stopped = status.dwCurrentState == SERVICE_STOPPED; + int i = 0; + while(!stopped && i < 10) { + Sleep(200); + if (!pQueryServiceStatus(hService, &status)) + break; + stopped = status.dwCurrentState == SERVICE_STOPPED; + ++i; + } + result = stopped; + } else { + qErrnoWarning(GetLastError(), "stopping"); + } + pCloseServiceHandle(hService); + } + pCloseServiceHandle(hSCM); + } + return result; } bool QtServiceController::pause() { - Q_D(QtServiceController); - bool result = false; - if (!winServiceInit()) - return result; - - SC_HANDLE hSCM = pOpenSCManager(0, 0, SC_MANAGER_CONNECT); - if (hSCM) { - SC_HANDLE hService = pOpenService(hSCM, (wchar_t *)d->serviceName.utf16(), - SERVICE_PAUSE_CONTINUE); - if (hService) { - SERVICE_STATUS status; - if (pControlService(hService, SERVICE_CONTROL_PAUSE, &status)) - result = true; - pCloseServiceHandle(hService); - } - pCloseServiceHandle(hSCM); - } - return result; + Q_D(QtServiceController); + bool result = false; + if (!winServiceInit()) + return result; + + SC_HANDLE hSCM = pOpenSCManager(0, 0, SC_MANAGER_CONNECT); + if (hSCM) { + SC_HANDLE hService = pOpenService(hSCM, (wchar_t *)d->serviceName.utf16(), + SERVICE_PAUSE_CONTINUE); + if (hService) { + SERVICE_STATUS status; + if (pControlService(hService, SERVICE_CONTROL_PAUSE, &status)) + result = true; + pCloseServiceHandle(hService); + } + pCloseServiceHandle(hSCM); + } + return result; } bool QtServiceController::resume() { - Q_D(QtServiceController); - bool result = false; - if (!winServiceInit()) - return result; - - SC_HANDLE hSCM = pOpenSCManager(0, 0, SC_MANAGER_CONNECT); - if (hSCM) { - SC_HANDLE hService = pOpenService(hSCM, (wchar_t *)d->serviceName.utf16(), - SERVICE_PAUSE_CONTINUE); - if (hService) { - SERVICE_STATUS status; - if (pControlService(hService, SERVICE_CONTROL_CONTINUE, &status)) - result = true; - pCloseServiceHandle(hService); - } - pCloseServiceHandle(hSCM); - } - return result; + Q_D(QtServiceController); + bool result = false; + if (!winServiceInit()) + return result; + + SC_HANDLE hSCM = pOpenSCManager(0, 0, SC_MANAGER_CONNECT); + if (hSCM) { + SC_HANDLE hService = pOpenService(hSCM, (wchar_t *)d->serviceName.utf16(), + SERVICE_PAUSE_CONTINUE); + if (hService) { + SERVICE_STATUS status; + if (pControlService(hService, SERVICE_CONTROL_CONTINUE, &status)) + result = true; + pCloseServiceHandle(hService); + } + pCloseServiceHandle(hSCM); + } + return result; } bool QtServiceController::sendCommand(int code) @@ -393,24 +412,24 @@ bool QtServiceController::sendCommand(int code) Q_D(QtServiceController); bool result = false; if (!winServiceInit()) - return result; - - if (code < 0 || code > 127 || !isRunning()) - return result; - - SC_HANDLE hSCM = pOpenSCManager(0, 0, SC_MANAGER_CONNECT); - if (hSCM) { - SC_HANDLE hService = pOpenService(hSCM, (wchar_t *)d->serviceName.utf16(), - SERVICE_USER_DEFINED_CONTROL); - if (hService) { - SERVICE_STATUS status; - if (pControlService(hService, 128 + code, &status)) - result = true; - pCloseServiceHandle(hService); - } - pCloseServiceHandle(hSCM); - } - return result; + return result; + + if (code < 0 || code > 127 || !isRunning()) + return result; + + SC_HANDLE hSCM = pOpenSCManager(0, 0, SC_MANAGER_CONNECT); + if (hSCM) { + SC_HANDLE hService = pOpenService(hSCM, (wchar_t *)d->serviceName.utf16(), + SERVICE_USER_DEFINED_CONTROL); + if (hService) { + SERVICE_STATUS status; + if (pControlService(hService, 128 + code, &status)) + result = true; + pCloseServiceHandle(hService); + } + pCloseServiceHandle(hSCM); + } + return result; } #if defined(QTSERVICE_DEBUG) @@ -418,136 +437,144 @@ extern void qtServiceLogDebug(QtMsgType type, const char* msg); #endif void QtServiceBase::logMessage(const QString &message, MessageType type, - int id, uint category, const QByteArray &data) + int id, uint category, const QByteArray &data) { #if defined(QTSERVICE_DEBUG) - QByteArray dbgMsg("[LOGGED "); - switch (type) { - case Error: dbgMsg += "Error] " ; break; - case Warning: dbgMsg += "Warning] "; break; - case Success: dbgMsg += "Success] "; break; - case Information: //fall through - default: dbgMsg += "Information] "; break; - } - dbgMsg += message.toAscii(); - qtServiceLogDebug((QtMsgType)-1, dbgMsg.constData()); + QByteArray dbgMsg("[LOGGED "); + switch (type) { + case Error: dbgMsg += "Error] " ; break; + case Warning: dbgMsg += "Warning] "; break; + case Success: dbgMsg += "Success] "; break; + case Information: //fall through + default: dbgMsg += "Information] "; break; + } + dbgMsg += message.toAscii(); + qtServiceLogDebug((QtMsgType)-1, dbgMsg.constData()); #endif - Q_D(QtServiceBase); - if (!winServiceInit()) - return; - WORD wType; - switch (type) { - case Error: wType = EVENTLOG_ERROR_TYPE; break; - case Warning: wType = EVENTLOG_WARNING_TYPE; break; - case Information: wType = EVENTLOG_INFORMATION_TYPE; break; - default: wType = EVENTLOG_SUCCESS; break; - } - HANDLE h = pRegisterEventSource(0, (wchar_t *)d->controller.serviceName().utf16()); - if (h) { - const wchar_t *msg = (wchar_t*)message.utf16(); - const char *bindata = data.size() ? data.constData() : 0; - pReportEvent(h, wType, category, id, 0, 1, data.size(),(const wchar_t **)&msg, - const_cast(bindata)); - pDeregisterEventSource(h); - } + Q_D(QtServiceBase); + if (!winServiceInit()) + return; + WORD wType; + switch (type) { + case Error: wType = EVENTLOG_ERROR_TYPE; break; + case Warning: wType = EVENTLOG_WARNING_TYPE; break; + case Information: wType = EVENTLOG_INFORMATION_TYPE; break; + default: wType = EVENTLOG_SUCCESS; break; + } + HANDLE h = pRegisterEventSource(0, (wchar_t *)d->controller.serviceName().utf16()); + if (h) { + const wchar_t *msg = (wchar_t*)message.utf16(); + const char *bindata = data.size() ? data.constData() : 0; + pReportEvent(h, wType, category, id, 0, 1, data.size(),(const wchar_t **)&msg, + const_cast(bindata)); + pDeregisterEventSource(h); + } } class QtServiceControllerHandler : public QObject { - Q_OBJECT + Q_OBJECT public: - QtServiceControllerHandler(QtServiceSysPrivate *sys); + QtServiceControllerHandler(QtServiceSysPrivate *sys); protected: - void customEvent(QEvent *e); + void customEvent(QEvent *e); private: - QtServiceSysPrivate *d_sys; + QtServiceSysPrivate *d_sys; }; class QtServiceSysPrivate { public: - enum { - QTSERVICE_STARTUP = 256 - }; - QtServiceSysPrivate(); - - void setStatus( DWORD dwState ); - void setServiceFlags(QtServiceBase::ServiceFlags flags); - DWORD serviceFlags(QtServiceBase::ServiceFlags flags) const; - inline bool available() const; - static void WINAPI serviceMain( DWORD dwArgc, wchar_t** lpszArgv ); - static void WINAPI handler( DWORD dwOpcode ); - - SERVICE_STATUS status; - SERVICE_STATUS_HANDLE serviceStatus; - QStringList serviceArgs; - - static QtServiceSysPrivate *instance; - static QCoreApplication::EventFilter nextFilter; + enum { + QTSERVICE_STARTUP = 256 + }; + QtServiceSysPrivate(); + + void setStatus( DWORD dwState ); + void setServiceFlags(QtServiceBase::ServiceFlags flags); + DWORD serviceFlags(QtServiceBase::ServiceFlags flags) const; + inline bool available() const; + static void WINAPI serviceMain( DWORD dwArgc, wchar_t** lpszArgv ); + static void WINAPI handler( DWORD dwOpcode ); + + SERVICE_STATUS status; + SERVICE_STATUS_HANDLE serviceStatus; + QStringList serviceArgs; + + static QtServiceSysPrivate *instance; +#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) + static QtServiceEventFilter *serviceFilter; +#else + static QCoreApplication::EventFilter nextFilter; +#endif - QWaitCondition condition; - QMutex mutex; - QSemaphore startSemaphore; - QSemaphore startSemaphore2; + QWaitCondition condition; + QMutex mutex; + QSemaphore startSemaphore; + QSemaphore startSemaphore2; - QtServiceControllerHandler *controllerHandler; + QtServiceControllerHandler *controllerHandler; - void handleCustomEvent(QEvent *e); + void handleCustomEvent(QEvent *e); }; QtServiceControllerHandler::QtServiceControllerHandler(QtServiceSysPrivate *sys) - : QObject(), d_sys(sys) + : QObject(), d_sys(sys) { } void QtServiceControllerHandler::customEvent(QEvent *e) { - d_sys->handleCustomEvent(e); + d_sys->handleCustomEvent(e); } QtServiceSysPrivate *QtServiceSysPrivate::instance = 0; +#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) +QtServiceEventFilter *QtServiceSysPrivate::serviceFilter = 0; +#else QCoreApplication::EventFilter QtServiceSysPrivate::nextFilter = 0; +#endif QtServiceSysPrivate::QtServiceSysPrivate() { - instance = this; + instance = this; } inline bool QtServiceSysPrivate::available() const { - return 0 != pOpenSCManager; + return 0 != pOpenSCManager; } void WINAPI QtServiceSysPrivate::serviceMain(DWORD dwArgc, wchar_t** lpszArgv) { - if (!instance || !QtServiceBase::instance()) - return; + if (!instance || !QtServiceBase::instance()) + return; - // Windows spins off a random thread to call this function on - // startup, so here we just signal to the QApplication event loop - // in the main thread to go ahead with start()'ing the service. + // Windows spins off a random thread to call this function on + // startup, so here we just signal to the QApplication event loop + // in the main thread to go ahead with start()'ing the service. - for (DWORD i = 0; i < dwArgc; i++) - instance->serviceArgs.append(QString::fromUtf16((unsigned short*)lpszArgv[i])); + for (DWORD i = 0; i < dwArgc; i++) + instance->serviceArgs.append(QString::fromUtf16((unsigned short*)lpszArgv[i])); - instance->startSemaphore.release(); // let the qapp creation start - instance->startSemaphore2.acquire(); // wait until its done - // Register the control request handler - instance->serviceStatus = pRegisterServiceCtrlHandler((TCHAR*)QtServiceBase::instance()->serviceName().utf16(), handler); + instance->startSemaphore.release(); // let the qapp creation start + instance->startSemaphore2.acquire(); // wait until its done + // Register the control request handler + instance->serviceStatus = pRegisterServiceCtrlHandler((TCHAR*)QtServiceBase::instance()->serviceName().utf16(), handler); - if (!instance->serviceStatus) // cannot happen - something is utterly wrong - return; + if (!instance->serviceStatus) // cannot happen - something is utterly wrong + return; - handler(QTSERVICE_STARTUP); // Signal startup to the application - - // causes QtServiceBase::start() to be called in the main thread + handler(QTSERVICE_STARTUP); // Signal startup to the application - + // causes QtServiceBase::start() to be called in the main thread - // The MSDN doc says that this thread should just exit - the service is - // running in the main thread (here, via callbacks in the handler thread). + // The MSDN doc says that this thread should just exit - the service is + // running in the main thread (here, via callbacks in the handler thread). } @@ -558,119 +585,119 @@ void WINAPI QtServiceSysPrivate::serviceMain(DWORD dwArgc, wchar_t** lpszArgv) // and a QMutex to synchronize. void QtServiceSysPrivate::handleCustomEvent(QEvent *e) { - int code = e->type() - QEvent::User; - - switch(code) { - case QTSERVICE_STARTUP: // Startup - QtServiceBase::instance()->start(); - break; - case SERVICE_CONTROL_STOP: - QtServiceBase::instance()->stop(); - QCoreApplication::instance()->quit(); - break; - case SERVICE_CONTROL_PAUSE: - QtServiceBase::instance()->pause(); - break; - case SERVICE_CONTROL_CONTINUE: - QtServiceBase::instance()->resume(); - break; - default: + int code = e->type() - QEvent::User; + + switch(code) { + case QTSERVICE_STARTUP: // Startup + QtServiceBase::instance()->start(); + break; + case SERVICE_CONTROL_STOP: + QtServiceBase::instance()->stop(); + QCoreApplication::instance()->quit(); + break; + case SERVICE_CONTROL_PAUSE: + QtServiceBase::instance()->pause(); + break; + case SERVICE_CONTROL_CONTINUE: + QtServiceBase::instance()->resume(); + break; + default: if (code >= 128 && code <= 255) - QtServiceBase::instance()->processCommand(code - 128); - break; - } + QtServiceBase::instance()->processCommand(code - 128); + break; + } - mutex.lock(); - condition.wakeAll(); - mutex.unlock(); + mutex.lock(); + condition.wakeAll(); + mutex.unlock(); } void WINAPI QtServiceSysPrivate::handler( DWORD code ) { - if (!instance) - return; - - instance->mutex.lock(); - switch (code) { - case QTSERVICE_STARTUP: // QtService startup (called from WinMain when started) - instance->setStatus(SERVICE_START_PENDING); - QCoreApplication::postEvent(instance->controllerHandler, new QEvent(QEvent::Type(QEvent::User + code))); - instance->condition.wait(&instance->mutex); - instance->setStatus(SERVICE_RUNNING); - break; - case SERVICE_CONTROL_STOP: // 1 - instance->setStatus(SERVICE_STOP_PENDING); - QCoreApplication::postEvent(instance->controllerHandler, new QEvent(QEvent::Type(QEvent::User + code))); - instance->condition.wait(&instance->mutex); - // status will be reported as stopped by start() when qapp::exec returns - break; - - case SERVICE_CONTROL_PAUSE: // 2 - instance->setStatus(SERVICE_PAUSE_PENDING); - QCoreApplication::postEvent(instance->controllerHandler, new QEvent(QEvent::Type(QEvent::User + code))); - instance->condition.wait(&instance->mutex); - instance->setStatus(SERVICE_PAUSED); - break; - - case SERVICE_CONTROL_CONTINUE: // 3 - instance->setStatus(SERVICE_CONTINUE_PENDING); - QCoreApplication::postEvent(instance->controllerHandler, new QEvent(QEvent::Type(QEvent::User + code))); - instance->condition.wait(&instance->mutex); - instance->setStatus(SERVICE_RUNNING); - break; - - case SERVICE_CONTROL_INTERROGATE: // 4 - break; - - case SERVICE_CONTROL_SHUTDOWN: // 5 - // Don't waste time with reporting stop pending, just do it - QCoreApplication::postEvent(instance->controllerHandler, new QEvent(QEvent::Type(QEvent::User + SERVICE_CONTROL_STOP))); - instance->condition.wait(&instance->mutex); - // status will be reported as stopped by start() when qapp::exec returns - break; - - default: - if ( code >= 128 && code <= 255 ) { - QCoreApplication::postEvent(instance->controllerHandler, new QEvent(QEvent::Type(QEvent::User + code))); - instance->condition.wait(&instance->mutex); - } - break; - } - - instance->mutex.unlock(); - - // Report current status - if (instance->available() && instance->status.dwCurrentState != SERVICE_STOPPED) - pSetServiceStatus(instance->serviceStatus, &instance->status); + if (!instance) + return; + + instance->mutex.lock(); + switch (code) { + case QTSERVICE_STARTUP: // QtService startup (called from WinMain when started) + instance->setStatus(SERVICE_START_PENDING); + QCoreApplication::postEvent(instance->controllerHandler, new QEvent(QEvent::Type(QEvent::User + code))); + instance->condition.wait(&instance->mutex); + instance->setStatus(SERVICE_RUNNING); + break; + case SERVICE_CONTROL_STOP: // 1 + instance->setStatus(SERVICE_STOP_PENDING); + QCoreApplication::postEvent(instance->controllerHandler, new QEvent(QEvent::Type(QEvent::User + code))); + instance->condition.wait(&instance->mutex); + // status will be reported as stopped by start() when qapp::exec returns + break; + + case SERVICE_CONTROL_PAUSE: // 2 + instance->setStatus(SERVICE_PAUSE_PENDING); + QCoreApplication::postEvent(instance->controllerHandler, new QEvent(QEvent::Type(QEvent::User + code))); + instance->condition.wait(&instance->mutex); + instance->setStatus(SERVICE_PAUSED); + break; + + case SERVICE_CONTROL_CONTINUE: // 3 + instance->setStatus(SERVICE_CONTINUE_PENDING); + QCoreApplication::postEvent(instance->controllerHandler, new QEvent(QEvent::Type(QEvent::User + code))); + instance->condition.wait(&instance->mutex); + instance->setStatus(SERVICE_RUNNING); + break; + + case SERVICE_CONTROL_INTERROGATE: // 4 + break; + + case SERVICE_CONTROL_SHUTDOWN: // 5 + // Don't waste time with reporting stop pending, just do it + QCoreApplication::postEvent(instance->controllerHandler, new QEvent(QEvent::Type(QEvent::User + SERVICE_CONTROL_STOP))); + instance->condition.wait(&instance->mutex); + // status will be reported as stopped by start() when qapp::exec returns + break; + + default: + if ( code >= 128 && code <= 255 ) { + QCoreApplication::postEvent(instance->controllerHandler, new QEvent(QEvent::Type(QEvent::User + code))); + instance->condition.wait(&instance->mutex); + } + break; + } + + instance->mutex.unlock(); + + // Report current status + if (instance->available() && instance->status.dwCurrentState != SERVICE_STOPPED) + pSetServiceStatus(instance->serviceStatus, &instance->status); } void QtServiceSysPrivate::setStatus(DWORD state) { - if (!available()) + if (!available()) return; - status.dwCurrentState = state; - pSetServiceStatus(serviceStatus, &status); + status.dwCurrentState = state; + pSetServiceStatus(serviceStatus, &status); } void QtServiceSysPrivate::setServiceFlags(QtServiceBase::ServiceFlags flags) { - if (!available()) - return; - status.dwControlsAccepted = serviceFlags(flags); - pSetServiceStatus(serviceStatus, &status); + if (!available()) + return; + status.dwControlsAccepted = serviceFlags(flags); + pSetServiceStatus(serviceStatus, &status); } DWORD QtServiceSysPrivate::serviceFlags(QtServiceBase::ServiceFlags flags) const { - DWORD control = 0; - if (flags & QtServiceBase::CanBeSuspended) - control |= SERVICE_ACCEPT_PAUSE_CONTINUE; - if (!(flags & QtServiceBase::CannotBeStopped)) - control |= SERVICE_ACCEPT_STOP; - if (flags & QtServiceBase::NeedsStopOnShutdown) - control |= SERVICE_ACCEPT_SHUTDOWN; + DWORD control = 0; + if (flags & QtServiceBase::CanBeSuspended) + control |= SERVICE_ACCEPT_PAUSE_CONTINUE; + if (!(flags & QtServiceBase::CannotBeStopped)) + control |= SERVICE_ACCEPT_STOP; + if (flags & QtServiceBase::NeedsStopOnShutdown) + control |= SERVICE_ACCEPT_SHUTDOWN; - return control; + return control; } #include "qtservice_win.moc" @@ -679,37 +706,37 @@ DWORD QtServiceSysPrivate::serviceFlags(QtServiceBase::ServiceFlags flags) const class HandlerThread : public QThread { public: - HandlerThread() - : success(true), console(false), QThread() - {} + HandlerThread() + : success(true), console(false), QThread() + {} - bool calledOk() { return success; } - bool runningAsConsole() { return console; } + bool calledOk() { return success; } + bool runningAsConsole() { return console; } protected: - bool success, console; - void run() - { - SERVICE_TABLE_ENTRYW st [2]; - st[0].lpServiceName = (wchar_t*)QtServiceBase::instance()->serviceName().utf16(); - st[0].lpServiceProc = QtServiceSysPrivate::serviceMain; - st[1].lpServiceName = 0; - st[1].lpServiceProc = 0; - - success = (pStartServiceCtrlDispatcher(st) != 0); // should block - - if (!success) { - if (GetLastError() == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) { - // Means we're started from console, not from service mgr - // start() will ask the mgr to start another instance of us as a service instead - console = true; - } - else { - QtServiceBase::instance()->logMessage(QString("The Service failed to start [%1]").arg(qt_error_string(GetLastError())), QtServiceBase::Error); - } - QtServiceSysPrivate::instance->startSemaphore.release(); // let start() continue, since serviceMain won't be doing it - } - } + bool success, console; + void run() + { + SERVICE_TABLE_ENTRYW st [2]; + st[0].lpServiceName = (wchar_t*)QtServiceBase::instance()->serviceName().utf16(); + st[0].lpServiceProc = QtServiceSysPrivate::serviceMain; + st[1].lpServiceName = 0; + st[1].lpServiceProc = 0; + + success = (pStartServiceCtrlDispatcher(st) != 0); // should block + + if (!success) { + if (GetLastError() == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) { + // Means we're started from console, not from service mgr + // start() will ask the mgr to start another instance of us as a service instead + console = true; + } + else { + QtServiceBase::instance()->logMessage(QString("The Service failed to start [%1]").arg(qt_error_string(GetLastError())), QtServiceBase::Error); + } + QtServiceSysPrivate::instance->startSemaphore.release(); // let start() continue, since serviceMain won't be doing it + } + } }; /* @@ -717,15 +744,20 @@ protected: */ bool myEventFilter(void* message, long* result) { - MSG* msg = reinterpret_cast(message); - if (!msg || (msg->message != WM_ENDSESSION) || !(msg->lParam & ENDSESSION_LOGOFF)) - return QtServiceSysPrivate::nextFilter ? QtServiceSysPrivate::nextFilter(message, result) : false; + MSG* msg = reinterpret_cast(message); - if (QtServiceSysPrivate::nextFilter) - QtServiceSysPrivate::nextFilter(message, result); - if (result) - *result = TRUE; - return true; + if (!msg || (msg->message != WM_ENDSESSION) || !(msg->lParam & ENDSESSION_LOGOFF)) +#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) + return false; +#else + return QtServiceSysPrivate::nextFilter ? QtServiceSysPrivate::nextFilter(message, result) : false; + + if (QtServiceSysPrivate::nextFilter) + QtServiceSysPrivate::nextFilter(message, result); +#endif + if (result) + *result = TRUE; + return true; } /* There are three ways we can be started: @@ -745,140 +777,146 @@ bool myEventFilter(void* message, long* result) ServiceBasePrivate::run(), which runs the application as a normal program. */ - bool QtServiceBasePrivate::start() { - sysInit(); - if (!winServiceInit()) - return false; - - // Since StartServiceCtrlDispatcher() blocks waiting for service - // control events, we need to call it in another thread, so that - // the main thread can run the QApplication event loop. - HandlerThread* ht = new HandlerThread(); - ht->start(); - - QtServiceSysPrivate* sys = QtServiceSysPrivate::instance; - - // Wait until service args have been received by serviceMain. - // If Windows doesn't call serviceMain (or - // StartServiceControlDispatcher doesn't return an error) within - // a timeout of 20 secs, something is very wrong; give up - if (!sys->startSemaphore.tryAcquire(1, 20000)) - return false; - - if (!ht->calledOk()) { - if (ht->runningAsConsole()) - return controller.start(args.mid(1)); - else - return false; - } - - int argc = sys->serviceArgs.size(); - QVector argv(argc); - QList argvData; - for (int i = 0; i < argc; ++i) - argvData.append(sys->serviceArgs.at(i).toLocal8Bit()); - for (int i = 0; i < argc; ++i) - argv[i] = argvData[i].data(); - - q_ptr->createApplication(argc, argv.data()); - QCoreApplication *app = QCoreApplication::instance(); - if (!app) - return false; - QtServiceSysPrivate::nextFilter = app->setEventFilter(myEventFilter); - - sys->controllerHandler = new QtServiceControllerHandler(sys); - - sys->startSemaphore2.release(); // let serviceMain continue (and end) - - sys->status.dwWin32ExitCode = q_ptr->executeApplication(); - sys->setStatus(SERVICE_STOPPED); - - if (ht->isRunning()) - ht->wait(1000); // let the handler thread finish - delete sys->controllerHandler; - sys->controllerHandler = 0; - if (ht->isFinished()) - delete ht; - delete app; - sysCleanup(); - return true; + sysInit(); + if (!winServiceInit()) + return false; + + // Since StartServiceCtrlDispatcher() blocks waiting for service + // control events, we need to call it in another thread, so that + // the main thread can run the QApplication event loop. + HandlerThread* ht = new HandlerThread(); + ht->start(); + + QtServiceSysPrivate* sys = QtServiceSysPrivate::instance; + + // Wait until service args have been received by serviceMain. + // If Windows doesn't call serviceMain (or + // StartServiceControlDispatcher doesn't return an error) within + // a timeout of 20 secs, something is very wrong; give up + if (!sys->startSemaphore.tryAcquire(1, 20000)) + return false; + + if (!ht->calledOk()) { + if (ht->runningAsConsole()) + return controller.start(args.mid(1)); + else + return false; + } + + int argc = sys->serviceArgs.size(); + QVector argv(argc); + QList argvData; + for (int i = 0; i < argc; ++i) + argvData.append(sys->serviceArgs.at(i).toLocal8Bit()); + for (int i = 0; i < argc; ++i) + argv[i] = argvData[i].data(); + + q_ptr->createApplication(argc, argv.data()); + QCoreApplication *app = QCoreApplication::instance(); + if (!app) + return false; +#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) + if (!QtServiceSysPrivate::serviceFilter) + { + QtServiceSysPrivate::serviceFilter = new QtServiceEventFilter(myEventFilter); + app->installNativeEventFilter(QtServiceSysPrivate::serviceFilter); + } +#else + QtServiceSysPrivate::nextFilter = app->setEventFilter(myEventFilter); +#endif + sys->controllerHandler = new QtServiceControllerHandler(sys); + + sys->startSemaphore2.release(); // let serviceMain continue (and end) + + sys->status.dwWin32ExitCode = q_ptr->executeApplication(); + sys->setStatus(SERVICE_STOPPED); + + if (ht->isRunning()) + ht->wait(1000); // let the handler thread finish + delete sys->controllerHandler; + sys->controllerHandler = 0; + if (ht->isFinished()) + delete ht; + delete app; + sysCleanup(); + return true; } bool QtServiceBasePrivate::install(const QString &account, const QString &password) { - bool result = false; - if (!winServiceInit()) - return result; - - // Open the Service Control Manager - SC_HANDLE hSCM = pOpenSCManager(0, 0, SC_MANAGER_ALL_ACCESS); - if (hSCM) { - QString acc = account; - DWORD dwStartType = startupType == QtServiceController::AutoStartup ? SERVICE_AUTO_START : SERVICE_DEMAND_START; - DWORD dwServiceType = SERVICE_WIN32_OWN_PROCESS; - wchar_t *act = 0; - wchar_t *pwd = 0; - if (!acc.isEmpty()) { - // The act string must contain a string of the format "Domain\UserName", - // so if only a username was specified without a domain, default to the local machine domain. - if (!acc.contains(QChar('\\'))) { - acc.prepend(QLatin1String(".\\")); - } - if (!acc.endsWith(QLatin1String("\\LocalSystem"))) - act = (wchar_t*)acc.utf16(); - } - if (!password.isEmpty() && act) { - pwd = (wchar_t*)password.utf16(); - } - - // Only set INTERACTIVE if act is LocalSystem. (and act should be 0 if it is LocalSystem). - if (!act) dwServiceType |= SERVICE_INTERACTIVE_PROCESS; - - // Create the service - SC_HANDLE hService = pCreateService(hSCM, (wchar_t *)controller.serviceName().utf16(), - (wchar_t *)controller.serviceName().utf16(), - SERVICE_ALL_ACCESS, - dwServiceType, // QObject::inherits ( const char * className ) for no inter active ???? - dwStartType, SERVICE_ERROR_NORMAL, (wchar_t *)filePath().utf16(), - 0, 0, 0, - act, pwd); - if (hService) { - result = true; - if (!serviceDescription.isEmpty()) { - SERVICE_DESCRIPTION sdesc; - sdesc.lpDescription = (wchar_t *)serviceDescription.utf16(); - pChangeServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION, &sdesc); - } - pCloseServiceHandle(hService); - } - pCloseServiceHandle(hSCM); - } - return result; + bool result = false; + if (!winServiceInit()) + return result; + + // Open the Service Control Manager + SC_HANDLE hSCM = pOpenSCManager(0, 0, SC_MANAGER_ALL_ACCESS); + if (hSCM) { + QString acc = account; + DWORD dwStartType = startupType == QtServiceController::AutoStartup ? SERVICE_AUTO_START : SERVICE_DEMAND_START; + DWORD dwServiceType = SERVICE_WIN32_OWN_PROCESS; + wchar_t *act = 0; + wchar_t *pwd = 0; + if (!acc.isEmpty()) { + // The act string must contain a string of the format "Domain\UserName", + // so if only a username was specified without a domain, default to the local machine domain. + if (!acc.contains(QChar('\\'))) { + acc.prepend(QLatin1String(".\\")); + } + if (!acc.endsWith(QLatin1String("\\LocalSystem"))) + act = (wchar_t*)acc.utf16(); + } + if (!password.isEmpty() && act) { + pwd = (wchar_t*)password.utf16(); + } + + // Only set INTERACTIVE if act is LocalSystem. (and act should be 0 if it is LocalSystem). + if (!act) dwServiceType |= SERVICE_INTERACTIVE_PROCESS; + + // Create the service + SC_HANDLE hService = pCreateService(hSCM, (wchar_t *)controller.serviceName().utf16(), + (wchar_t *)controller.serviceName().utf16(), + SERVICE_ALL_ACCESS, + dwServiceType, // QObject::inherits ( const char * className ) for no inter active ???? + dwStartType, SERVICE_ERROR_NORMAL, (wchar_t *)filePath().utf16(), + 0, 0, 0, + act, pwd); + if (hService) { + result = true; + if (!serviceDescription.isEmpty()) { + SERVICE_DESCRIPTION sdesc; + sdesc.lpDescription = (wchar_t *)serviceDescription.utf16(); + pChangeServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION, &sdesc); + } + pCloseServiceHandle(hService); + } + pCloseServiceHandle(hSCM); + } + return result; } QString QtServiceBasePrivate::filePath() const { - wchar_t path[_MAX_PATH]; - ::GetModuleFileNameW( 0, path, sizeof(path) ); - return QString::fromUtf16((unsigned short*)path); + wchar_t path[_MAX_PATH]; + ::GetModuleFileNameW( 0, path, sizeof(path) ); + return QString::fromUtf16((unsigned short*)path); } bool QtServiceBasePrivate::sysInit() { - sysd = new QtServiceSysPrivate(); + sysd = new QtServiceSysPrivate(); - sysd->serviceStatus = 0; - sysd->status.dwServiceType = SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_PROCESS; - sysd->status.dwCurrentState = SERVICE_STOPPED; - sysd->status.dwControlsAccepted = sysd->serviceFlags(serviceFlags); - sysd->status.dwWin32ExitCode = NO_ERROR; - sysd->status.dwServiceSpecificExitCode = 0; - sysd->status.dwCheckPoint = 0; - sysd->status.dwWaitHint = 0; + sysd->serviceStatus = 0; + sysd->status.dwServiceType = SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_PROCESS; + sysd->status.dwCurrentState = SERVICE_STOPPED; + sysd->status.dwControlsAccepted = sysd->serviceFlags(serviceFlags); + sysd->status.dwWin32ExitCode = NO_ERROR; + sysd->status.dwServiceSpecificExitCode = 0; + sysd->status.dwCheckPoint = 0; + sysd->status.dwWaitHint = 0; - return true; + return true; } void QtServiceBasePrivate::sysSetPath() @@ -888,19 +926,19 @@ void QtServiceBasePrivate::sysSetPath() void QtServiceBasePrivate::sysCleanup() { - if (sysd) { - delete sysd; - sysd = 0; - } + if (sysd) { + delete sysd; + sysd = 0; + } } void QtServiceBase::setServiceFlags(QtServiceBase::ServiceFlags flags) { - if (d_ptr->serviceFlags == flags) - return; - d_ptr->serviceFlags = flags; - if (d_ptr->sysd) - d_ptr->sysd->setServiceFlags(flags); + if (d_ptr->serviceFlags == flags) + return; + d_ptr->serviceFlags = flags; + if (d_ptr->sysd) + d_ptr->sysd->setServiceFlags(flags); } -- 2.52.0