Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Hooks and Display Name #15

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 99 additions & 2 deletions qtservice/src/qtservice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,7 @@ public slots:
QtServiceBase *QtServiceBasePrivate::instance = 0;

QtServiceBasePrivate::QtServiceBasePrivate(const QString &name)
: startupType(QtServiceController::ManualStartup), serviceFlags(0), controller(name)
: startupType(QtServiceController::ManualStartup), controller(name)
{

}
Expand Down Expand Up @@ -623,6 +623,21 @@ int QtServiceBasePrivate::run(bool asService, const QStringList &argList)
\value NeedsStopOnShutdown (Windows only) The service will be stopped before the system shuts down. Note that Microsoft recommends this only for services that must absolutely clean up during shutdown, because there is a limited time available for shutdown of services.
*/

/*!
\typedef QtServiceBase::PreHook

This typedef describes a hook, which can be executed before
(un-)installation. If the return value of the hook is false, the
action is canceled and no further hooks are called.
*/

/*!
\typedef QtServiceBase::PostHook

This typedef describes a hook, which can be executed after
(un-)installation.
*/

/*!
Creates a service instance called \a name. The \a argc and \a argv
parameters are parsed after the exec() function has been
Expand Down Expand Up @@ -663,7 +678,7 @@ QtServiceBase::QtServiceBase(int argc, char **argv, const QString &name)
d_ptr = new QtServiceBasePrivate(nm);
d_ptr->q_ptr = this;

d_ptr->serviceFlags = 0;
d_ptr->serviceFlags = {};
d_ptr->sysd = 0;
for (int i = 0; i < argc; ++i)
d_ptr->args.append(QString::fromLocal8Bit(argv[i]));
Expand Down Expand Up @@ -695,6 +710,27 @@ QString QtServiceBase::serviceName() const
return d_ptr->controller.serviceName();
}

/*!
Returns the optional display name of the service.

\sa setDisplayName(), serviceName()
*/
QString QtServiceBase::displayName() const
{
return d_ptr->displayName;
}

/*!
Sets the optional display name of the service. If left empty the display
name is equal to the service name.

\sa displayName(), serviceName()
*/
void QtServiceBase::setDisplayName(const QString &displayName)
{
d_ptr->displayName = displayName;
}

/*!
Returns the description of the service.

Expand Down Expand Up @@ -782,10 +818,25 @@ int QtServiceBase::exec()
account = d_ptr->args.at(2);
if (d_ptr->args.size() > 3)
password = d_ptr->args.at(3);

for (std::size_t i = 0; i < d_ptr->PreInstallHooks.size(); ++i)
{
if (!d_ptr->PreInstallHooks[i]())
{
fprintf(stderr, "The service %s did not want to be installed, by hook %zu\n", serviceName().toLatin1().constData(), i);
return -2;
}
}

if (!d_ptr->install(account, password)) {
fprintf(stderr, "The service %s could not be installed\n", serviceName().toLatin1().constData());
return -1;
} else {
for (auto& hook : d_ptr->PostInstallHooks)
{
hook();
}

printf("The service %s has been installed under: %s\n",
serviceName().toLatin1().constData(), d_ptr->filePath().toLatin1().constData());
}
Expand All @@ -795,10 +846,24 @@ int QtServiceBase::exec()
return 0;
} else if (a == QLatin1String("-u") || a == QLatin1String("-uninstall")) {
if (d_ptr->controller.isInstalled()) {
for (std::size_t i = 0; i < d_ptr->PreUninstallHooks.size(); ++i)
{
if (!d_ptr->PreUninstallHooks[i]())
{
fprintf(stderr, "The service %s did not want to be uninstalled, by hook %zu\n", serviceName().toLatin1().constData(), i);
return -2;
}
}

if (!d_ptr->controller.uninstall()) {
fprintf(stderr, "The service %s could not be uninstalled\n", serviceName().toLatin1().constData());
return -1;
} else {
for (auto& hook : d_ptr->PostUninstallHooks)
{
hook();
}

printf("The service %s has been uninstalled.\n",
serviceName().toLatin1().constData());
}
Expand Down Expand Up @@ -883,6 +948,38 @@ int QtServiceBase::exec()
\sa MessageType
*/

/*!
Registers a pre install hook.
*/
void QtServiceBase::registerPreInstallHook(PreHook hook)
{
d_ptr->PreInstallHooks.emplace_back(std::move(hook));
}

/*!
Registers a post install hook.
*/
void QtServiceBase::registerPostInstallHook(PostHook hook)
{
d_ptr->PostInstallHooks.emplace_back(std::move(hook));
}

/*!
Registers a pre uninstall hook.
*/
void QtServiceBase::registerPreUninstallHook(PreHook hook)
{
d_ptr->PreUninstallHooks.emplace_back(std::move(hook));
}

/*!
Registers a post uninstall hook.
*/
void QtServiceBase::registerPostUninstallHook(PostHook hook)
{
d_ptr->PostUninstallHooks.emplace_back(std::move(hook));
}

/*!
Returns a pointer to the current application's QtServiceBase
instance.
Expand Down
13 changes: 13 additions & 0 deletions qtservice/src/qtservice.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@

#include <QCoreApplication>

#include <functional>

#if defined(Q_OS_WIN)
# if !defined(QT_QTSERVICE_EXPORT) && !defined(QT_QTSERVICE_IMPORT)
# define QT_QTSERVICE_EXPORT
Expand Down Expand Up @@ -119,11 +121,17 @@ class QT_QTSERVICE_EXPORT QtServiceBase

Q_DECLARE_FLAGS(ServiceFlags, ServiceFlag)

using PreHook = std::function<bool()>;
using PostHook = std::function<void()>;

QtServiceBase(int argc, char **argv, const QString &name);
virtual ~QtServiceBase();

QString serviceName() const;

QString displayName() const;
void setDisplayName(const QString &displayName);

QString serviceDescription() const;
void setServiceDescription(const QString &description);

Expand All @@ -138,6 +146,11 @@ class QT_QTSERVICE_EXPORT QtServiceBase
void logMessage(const QString &message, MessageType type = Success,
int id = 0, uint category = 0, const QByteArray &data = QByteArray());

void registerPreInstallHook(PreHook hook);
void registerPostInstallHook(PostHook hook);
void registerPreUninstallHook(PreHook hook);
void registerPostUninstallHook(PostHook hook);

static QtServiceBase *instance();

protected:
Expand Down
11 changes: 10 additions & 1 deletion qtservice/src/qtservice_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,12 @@
#ifndef QTSERVICE_P_H
#define QTSERVICE_P_H

#include <QStringList>
#include "qtservice.h"

#include <QStringList>

#include <vector>

class QtServiceControllerPrivate
{
Q_DECLARE_PUBLIC(QtServiceController)
Expand All @@ -62,11 +65,17 @@ class QtServiceBasePrivate

QtServiceBase *q_ptr;

QString displayName;
QString serviceDescription;
QtServiceController::StartupType startupType;
QtServiceBase::ServiceFlags serviceFlags;
QStringList args;

std::vector<QtServiceBase::PreHook> PreInstallHooks;
std::vector<QtServiceBase::PostHook> PostInstallHooks;
std::vector<QtServiceBase::PreHook > PreUninstallHooks;
std::vector<QtServiceBase::PostHook> PostUninstallHooks;

static class QtServiceBase *instance;

QtServiceController controller;
Expand Down
3 changes: 2 additions & 1 deletion qtservice/src/qtservice_win.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -862,6 +862,7 @@ bool QtServiceBasePrivate::install(const QString &account, const QString &passwo
SC_HANDLE hSCM = pOpenSCManager(0, 0, SC_MANAGER_ALL_ACCESS);
if (hSCM) {
QString acc = account;
QString dis = displayName.isEmpty() ? controller.serviceName() : displayName;
DWORD dwStartType = startupType == QtServiceController::AutoStartup ? SERVICE_AUTO_START : SERVICE_DEMAND_START;
DWORD dwServiceType = SERVICE_WIN32_OWN_PROCESS;
wchar_t *act = 0;
Expand All @@ -884,7 +885,7 @@ bool QtServiceBasePrivate::install(const QString &account, const QString &passwo

// Create the service
SC_HANDLE hService = pCreateService(hSCM, (wchar_t *)controller.serviceName().utf16(),
(wchar_t *)controller.serviceName().utf16(),
(wchar_t *)dis.utf16(),
SERVICE_ALL_ACCESS,
dwServiceType, // QObject::inherits ( const char * className ) for no inter active ????
dwStartType, SERVICE_ERROR_NORMAL, (wchar_t *)filePath().utf16(),
Expand Down