poco/Util/src/WinService.cpp
Roger Meier b0581433a7 LICENSE: add info about SPDX-License-Identifier usage and use it
fix: remove executable flag and change back to 100644 (was 100755)

Signed-off-by: Roger Meier <r.meier@siemens.com>
2014-05-14 08:38:09 +02:00

333 lines
7.0 KiB
C++

//
// WinService.cpp
//
// $Id: //poco/1.4/Util/src/WinService.cpp#4 $
//
// Library: Util
// Package: Windows
// Module: WinService
//
// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#if !defined(_WIN32_WCE)
#include "Poco/Util/WinService.h"
#include "Poco/Util/WinRegistryKey.h"
#include "Poco/Thread.h"
#include "Poco/Exception.h"
#if defined(POCO_WIN32_UTF8)
#include "Poco/UnicodeConverter.h"
#endif
using Poco::Thread;
using Poco::SystemException;
using Poco::NotFoundException;
using Poco::OutOfMemoryException;
namespace Poco {
namespace Util {
const int WinService::STARTUP_TIMEOUT = 30000;
const std::string WinService::REGISTRY_KEY("SYSTEM\\CurrentControlSet\\Services\\");
const std::string WinService::REGISTRY_DESCRIPTION("Description");
WinService::WinService(const std::string& name):
_name(name),
_svcHandle(0)
{
_scmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (!_scmHandle) throw SystemException("cannot open Service Control Manager");
}
WinService::~WinService()
{
close();
CloseServiceHandle(_scmHandle);
}
const std::string& WinService::name() const
{
return _name;
}
std::string WinService::displayName() const
{
POCO_LPQUERY_SERVICE_CONFIG pSvcConfig = config();
#if defined(POCO_WIN32_UTF8)
std::wstring udispName(pSvcConfig->lpDisplayName);
std::string dispName;
Poco::UnicodeConverter::toUTF8(udispName, dispName);
#else
std::string dispName(pSvcConfig->lpDisplayName);
#endif
LocalFree(pSvcConfig);
return dispName;
}
std::string WinService::path() const
{
POCO_LPQUERY_SERVICE_CONFIG pSvcConfig = config();
#if defined(POCO_WIN32_UTF8)
std::wstring upath(pSvcConfig->lpBinaryPathName);
std::string path;
UnicodeConverter::toUTF8(upath, path);
#else
std::string path(pSvcConfig->lpBinaryPathName);
#endif
LocalFree(pSvcConfig);
return path;
}
void WinService::registerService(const std::string& path, const std::string& displayName)
{
close();
#if defined(POCO_WIN32_UTF8)
std::wstring uname;
Poco::UnicodeConverter::toUTF16(_name, uname);
std::wstring udisplayName;
Poco::UnicodeConverter::toUTF16(displayName, udisplayName);
std::wstring upath;
Poco::UnicodeConverter::toUTF16(path, upath);
_svcHandle = CreateServiceW(
_scmHandle,
uname.c_str(),
udisplayName.c_str(),
SERVICE_ALL_ACCESS,
SERVICE_WIN32_OWN_PROCESS,
SERVICE_DEMAND_START,
SERVICE_ERROR_NORMAL,
upath.c_str(),
NULL, NULL, NULL, NULL, NULL);
#else
_svcHandle = CreateServiceA(
_scmHandle,
_name.c_str(),
displayName.c_str(),
SERVICE_ALL_ACCESS,
SERVICE_WIN32_OWN_PROCESS,
SERVICE_DEMAND_START,
SERVICE_ERROR_NORMAL,
path.c_str(),
NULL, NULL, NULL, NULL, NULL);
#endif
if (!_svcHandle)
throw SystemException("cannot register service", _name);
}
void WinService::registerService(const std::string& path)
{
registerService(path, _name);
}
void WinService::unregisterService()
{
open();
if (!DeleteService(_svcHandle))
throw SystemException("cannot unregister service", _name);
}
bool WinService::isRegistered() const
{
return tryOpen();
}
bool WinService::isRunning() const
{
open();
SERVICE_STATUS ss;
if (!QueryServiceStatus(_svcHandle, &ss))
throw SystemException("cannot query service status", _name);
return ss.dwCurrentState == SERVICE_RUNNING;
}
void WinService::start()
{
open();
if (!StartService(_svcHandle, 0, NULL))
throw SystemException("cannot start service", _name);
SERVICE_STATUS svcStatus;
long msecs = 0;
while (msecs < STARTUP_TIMEOUT)
{
if (!QueryServiceStatus(_svcHandle, &svcStatus)) break;
if (svcStatus.dwCurrentState != SERVICE_START_PENDING) break;
Thread::sleep(250);
msecs += 250;
}
if (!QueryServiceStatus(_svcHandle, &svcStatus))
throw SystemException("cannot query status of starting service", _name);
else if (svcStatus.dwCurrentState != SERVICE_RUNNING)
throw SystemException("service failed to start within a reasonable time", _name);
}
void WinService::stop()
{
open();
SERVICE_STATUS svcStatus;
if (!ControlService(_svcHandle, SERVICE_CONTROL_STOP, &svcStatus))
throw SystemException("cannot stop service", _name);
}
void WinService::setStartup(WinService::Startup startup)
{
open();
DWORD startType;
switch (startup)
{
case SVC_AUTO_START:
startType = SERVICE_AUTO_START;
break;
case SVC_MANUAL_START:
startType = SERVICE_DEMAND_START;
break;
case SVC_DISABLED:
startType = SERVICE_DISABLED;
break;
default:
startType = SERVICE_NO_CHANGE;
}
if (!ChangeServiceConfig(_svcHandle, SERVICE_NO_CHANGE, startType, SERVICE_NO_CHANGE, NULL, NULL, NULL, NULL, NULL, NULL, NULL))
{
throw SystemException("cannot change service startup mode");
}
}
WinService::Startup WinService::getStartup() const
{
POCO_LPQUERY_SERVICE_CONFIG pSvcConfig = config();
Startup result;
switch (pSvcConfig->dwStartType)
{
case SERVICE_AUTO_START:
case SERVICE_BOOT_START:
case SERVICE_SYSTEM_START:
result = SVC_AUTO_START;
break;
case SERVICE_DEMAND_START:
result = SVC_MANUAL_START;
break;
case SERVICE_DISABLED:
result = SVC_DISABLED;
break;
default:
poco_debugger();
result = SVC_MANUAL_START;
}
LocalFree(pSvcConfig);
return result;
}
void WinService::setDescription(const std::string& description)
{
std::string key(REGISTRY_KEY);
key += _name;
WinRegistryKey regKey(HKEY_LOCAL_MACHINE, key);
regKey.setString(REGISTRY_DESCRIPTION, description);
}
std::string WinService::getDescription() const
{
std::string key(REGISTRY_KEY);
key += _name;
WinRegistryKey regKey(HKEY_LOCAL_MACHINE, key, true);
return regKey.getString(REGISTRY_DESCRIPTION);
}
void WinService::open() const
{
if (!tryOpen())
throw NotFoundException("service does not exist", _name);
}
bool WinService::tryOpen() const
{
if (!_svcHandle)
{
#if defined(POCO_WIN32_UTF8)
std::wstring uname;
Poco::UnicodeConverter::toUTF16(_name, uname);
_svcHandle = OpenServiceW(_scmHandle, uname.c_str(), SERVICE_ALL_ACCESS);
#else
_svcHandle = OpenServiceA(_scmHandle, _name.c_str(), SERVICE_ALL_ACCESS);
#endif
}
return _svcHandle != 0;
}
void WinService::close() const
{
if (_svcHandle)
{
CloseServiceHandle(_svcHandle);
_svcHandle = 0;
}
}
POCO_LPQUERY_SERVICE_CONFIG WinService::config() const
{
open();
int size = 4096;
DWORD bytesNeeded;
POCO_LPQUERY_SERVICE_CONFIG pSvcConfig = (POCO_LPQUERY_SERVICE_CONFIG) LocalAlloc(LPTR, size);
if (!pSvcConfig) throw OutOfMemoryException("cannot allocate service config buffer");
try
{
#if defined(POCO_WIN32_UTF8)
while (!QueryServiceConfigW(_svcHandle, pSvcConfig, size, &bytesNeeded))
#else
while (!QueryServiceConfigA(_svcHandle, pSvcConfig, size, &bytesNeeded))
#endif
{
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
LocalFree(pSvcConfig);
size = bytesNeeded;
pSvcConfig = (POCO_LPQUERY_SERVICE_CONFIG) LocalAlloc(LPTR, size);
}
else throw SystemException("cannot query service configuration", _name);
}
}
catch (...)
{
LocalFree(pSvcConfig);
throw;
}
return pSvcConfig;
}
} } // namespace Poco::Util
#endif // !defined(_WIN32_WCE)