aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/um/service/src
diff options
context:
space:
mode:
Diffstat (limited to 'um/service/src')
-rw-r--r--um/service/src/device.cpp136
-rw-r--r--um/service/src/handle.cpp27
-rw-r--r--um/service/src/service.cpp276
-rw-r--r--um/service/src/service_handle.cpp27
-rw-r--r--um/service/src/service_manager.cpp44
-rw-r--r--um/service/src/windows_error.cpp39
6 files changed, 549 insertions, 0 deletions
diff --git a/um/service/src/device.cpp b/um/service/src/device.cpp
new file mode 100644
index 0000000..5643106
--- /dev/null
+++ b/um/service/src/device.cpp
@@ -0,0 +1,136 @@
+// Copyright (c) 2015 Egor Tensin <Egor.Tensin@gmail.com>
+// This file is part of the "Windows 7 drivers" project.
+// For details, see https://github.com/egor-tensin/windows7-drivers.
+// Distributed under the MIT License.
+
+#include "libservice/all.hpp"
+
+#include <Windows.h>
+
+#include <cstddef>
+
+#include <limits>
+#include <stdexcept>
+#include <string>
+#include <system_error>
+#include <utility>
+
+namespace libservice
+{
+ namespace
+ {
+ Handle open_device(const std::string& path)
+ {
+ const auto raw = CreateFileA(
+ path.c_str(),
+ GENERIC_READ | GENERIC_WRITE,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if (INVALID_HANDLE_VALUE == raw)
+ {
+ const auto ec = GetLastError();
+ throw std::system_error(
+ ec, WindowsErrorCategory::get(), LIBSERVICE_ERROR_PREFIX);
+ }
+
+ return Handle(raw);
+ }
+ }
+
+ Device Device::open(const std::string& path)
+ {
+ return Device(open_device(path));
+ }
+
+ std::size_t Device::get_required_output_size(
+ Code code,
+ const void* in_buf,
+ std::size_t in_buf_size) const
+ {
+ DWORD nbreq;
+
+ if (in_buf_size > std::numeric_limits<DWORD>::max())
+ throw std::range_error("input buffer size is too large");
+
+ std::size_t nbwritten = DeviceIoControl(
+ handle,
+ code,
+ const_cast<void*>(in_buf),
+ static_cast<DWORD>(in_buf_size),
+ NULL,
+ 0,
+ &nbreq,
+ NULL);
+
+ if (0 == nbwritten)
+ {
+ const auto ec = GetLastError();
+
+ switch (ec)
+ {
+ case ERROR_MORE_DATA:
+ return nbreq;
+
+ default:
+ throw std::system_error(
+ ec, WindowsErrorCategory::get(), LIBSERVICE_ERROR_PREFIX);
+ }
+ }
+
+ return nbwritten;
+ }
+
+ std::size_t Device::send_control_code(
+ Code code,
+ const void* in_buf,
+ std::size_t in_buf_size,
+ void* out_buf,
+ std::size_t out_buf_size) const
+ {
+ DWORD nbreq;
+
+ if (in_buf_size > std::numeric_limits<DWORD>::max())
+ throw std::range_error("input buffer size is too large");
+ if (out_buf_size > std::numeric_limits<DWORD>::max())
+ throw std::range_error("output buffer size is too large");
+
+ std::size_t nbwritten = DeviceIoControl(
+ handle,
+ code,
+ const_cast<void*>(in_buf),
+ static_cast<DWORD>(in_buf_size),
+ out_buf,
+ static_cast<DWORD>(out_buf_size),
+ &nbreq,
+ NULL);
+
+ if (0 == nbwritten)
+ {
+ const auto ec = GetLastError();
+ throw std::system_error(
+ ec, WindowsErrorCategory::get(), LIBSERVICE_ERROR_PREFIX);
+ }
+
+ return nbwritten;
+ }
+
+ void swap(Device& a, Device& b) LIBSERVICE_NOEXCEPT
+ {
+ a.swap(b);
+ }
+}
+
+namespace std
+{
+ template <>
+ void swap<libservice::Device>(
+ libservice::Device& a,
+ libservice::Device& b)
+ {
+ a.swap(b);
+ }
+}
diff --git a/um/service/src/handle.cpp b/um/service/src/handle.cpp
new file mode 100644
index 0000000..7567781
--- /dev/null
+++ b/um/service/src/handle.cpp
@@ -0,0 +1,27 @@
+// Copyright (c) 2015 Egor Tensin <Egor.Tensin@gmail.com>
+// This file is part of the "Windows 7 drivers" project.
+// For details, see https://github.com/egor-tensin/windows7-drivers.
+// Distributed under the MIT License.
+
+#include "libservice/all.hpp"
+
+#include <utility>
+
+namespace libservice
+{
+ void swap(Handle& a, Handle& b) LIBSERVICE_NOEXCEPT
+ {
+ a.swap(b);
+ }
+}
+
+namespace std
+{
+ template <>
+ void swap<libservice::Handle>(
+ libservice::Handle& a,
+ libservice::Handle& b) LIBSERVICE_NOEXCEPT
+ {
+ a.swap(b);
+ }
+}
diff --git a/um/service/src/service.cpp b/um/service/src/service.cpp
new file mode 100644
index 0000000..8b5e043
--- /dev/null
+++ b/um/service/src/service.cpp
@@ -0,0 +1,276 @@
+// Copyright (c) 2015 Egor Tensin <Egor.Tensin@gmail.com>
+// This file is part of the "Windows 7 drivers" project.
+// For details, see https://github.com/egor-tensin/windows7-drivers.
+// Distributed under the MIT License.
+
+#include "libservice/all.hpp"
+
+#include <Windows.h>
+
+#include <string>
+#include <system_error>
+#include <utility>
+#include <vector>
+
+namespace libservice
+{
+ namespace
+ {
+ ServiceHandle open_service(
+ const ServiceManager& mgr,
+ const std::string& name)
+ {
+ const auto raw = OpenServiceA(
+ mgr,
+ name.c_str(),
+ SERVICE_ALL_ACCESS);
+
+ if (NULL == raw)
+ {
+ const auto ec = GetLastError();
+ throw std::system_error(
+ ec, WindowsErrorCategory::get(), LIBSERVICE_ERROR_PREFIX);
+ }
+
+ return raw;
+ }
+
+ ServiceHandle install_service(
+ const ServiceManager& mgr,
+ const std::string& name,
+ const std::string& bin_path)
+ {
+ const auto raw = CreateServiceA(
+ mgr,
+ name.c_str(),
+ name.c_str(),
+ SERVICE_ALL_ACCESS,
+ SERVICE_KERNEL_DRIVER,
+ SERVICE_DEMAND_START,
+ SERVICE_ERROR_NORMAL,
+ bin_path.c_str(),
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+
+ if (NULL == raw)
+ {
+ const auto ec = GetLastError();
+ throw std::system_error(
+ ec, WindowsErrorCategory::get(), LIBSERVICE_ERROR_PREFIX);
+ }
+
+ return raw;
+ }
+
+ void start_service(const ServiceHandle& handle)
+ {
+ if (!StartService(handle, 0, NULL))
+ {
+ const auto ec = GetLastError();
+ throw std::system_error(
+ ec, WindowsErrorCategory::get(), LIBSERVICE_ERROR_PREFIX);
+ }
+ }
+
+ void stop_service(const ServiceHandle& handle)
+ {
+ SERVICE_STATUS service_status;
+
+ if (!ControlService(handle, SERVICE_CONTROL_STOP, &service_status))
+ {
+ const auto ec = GetLastError();
+ throw std::system_error(
+ ec, WindowsErrorCategory::get(), LIBSERVICE_ERROR_PREFIX);
+ }
+ }
+
+ void uninstall_service(const ServiceHandle& handle)
+ {
+ if (!DeleteService(handle))
+ {
+ const auto ec = GetLastError();
+ throw std::system_error(
+ ec, WindowsErrorCategory::get(), LIBSERVICE_ERROR_PREFIX);
+ }
+ }
+
+ bool service_exists(
+ const ServiceManager& mgr,
+ const std::string& name)
+ {
+ const auto raw = OpenServiceA(
+ mgr,
+ name.c_str(),
+ SERVICE_QUERY_STATUS);
+
+ if (NULL != raw)
+ {
+ ServiceHandle handle(raw);
+ return true;
+ }
+
+ const auto ec = GetLastError();
+
+ switch (ec)
+ {
+ case ERROR_SERVICE_DOES_NOT_EXIST:
+ return false;
+
+ default:
+ throw std::system_error(
+ ec, WindowsErrorCategory::get(), LIBSERVICE_ERROR_PREFIX);
+ }
+ }
+
+ SERVICE_STATUS_PROCESS query_service_status(const ServiceHandle& handle)
+ {
+ SERVICE_STATUS_PROCESS status;
+ DWORD nbreq;
+
+ const auto buf_ptr = reinterpret_cast<BYTE*>(&status);
+ const auto buf_size = sizeof(status);
+
+ if (!QueryServiceStatusEx(
+ handle, SC_STATUS_PROCESS_INFO, buf_ptr, buf_size, &nbreq))
+ {
+ const auto ec = GetLastError();
+ throw std::system_error(
+ ec, WindowsErrorCategory::get(), LIBSERVICE_ERROR_PREFIX);
+ }
+
+ return status;
+ }
+
+ DWORD query_service_state(const ServiceHandle& handle)
+ {
+ return query_service_status(handle).dwCurrentState;
+ }
+
+ SERVICE_STATUS_PROCESS wait_for_service_state(
+ const ServiceHandle& handle,
+ const DWORD desired_state)
+ {
+ auto status = query_service_status(handle);
+
+ DWORD old_timestamp = GetTickCount();
+
+ DWORD old_check_point = status.dwCheckPoint;
+ DWORD old_wait_hint = status.dwWaitHint;
+
+ while (desired_state != status.dwCurrentState)
+ {
+ DWORD wait_time = old_wait_hint / 10;
+
+ if (wait_time < 1000)
+ wait_time = 1000;
+ else if (wait_time > 10000)
+ wait_time = 10000;
+
+ Sleep(wait_time);
+
+ status = query_service_status(handle);
+
+ if (desired_state == status.dwCurrentState)
+ break;
+
+ if (status.dwCheckPoint > old_check_point)
+ {
+ old_timestamp = GetTickCount();
+
+ old_check_point = status.dwCheckPoint;
+ old_wait_hint = status.dwWaitHint;
+ }
+ else if (GetTickCount() - old_timestamp > old_wait_hint)
+ {
+ return status;
+ }
+ }
+
+ return status;
+ }
+ }
+
+ Service Service::open(
+ const ServiceManager& mgr,
+ const std::string& name)
+ {
+ return open_service(mgr, name);
+ }
+
+ Service Service::install(
+ const ServiceManager& mgr,
+ const std::string& name,
+ const std::string& bin_path)
+ {
+ return install_service(mgr, name, bin_path);
+ }
+
+ bool Service::exists(
+ const ServiceManager& mgr,
+ const std::string& name)
+ {
+ return service_exists(mgr, name);
+ }
+
+ void Service::start() const
+ {
+ const auto state = query_service_state(handle);
+
+ switch (state)
+ {
+ case SERVICE_STOPPED:
+ break;
+
+ case SERVICE_STOP_PENDING:
+ wait_for_service_state(handle, SERVICE_STOPPED);
+ break;
+
+ default:
+ return;
+ }
+
+ start_service(handle);
+ wait_for_service_state(handle, SERVICE_RUNNING);
+ }
+
+ void Service::stop() const
+ {
+ switch (query_service_state(handle))
+ {
+ case SERVICE_STOPPED:
+ return;
+
+ case SERVICE_STOP_PENDING:
+ wait_for_service_state(handle, SERVICE_STOPPED);
+ return;
+ }
+
+ stop_service(handle);
+ wait_for_service_state(handle, SERVICE_STOPPED);
+ }
+
+ void Service::uninstall() const
+ {
+ stop();
+ uninstall_service(handle);
+ }
+
+ void swap(Service& a, Service& b) LIBSERVICE_NOEXCEPT
+ {
+ a.swap(b);
+ }
+}
+
+namespace std
+{
+ template <>
+ void swap<libservice::Service>(
+ libservice::Service& a,
+ libservice::Service& b) LIBSERVICE_NOEXCEPT
+ {
+ a.swap(b);
+ }
+}
diff --git a/um/service/src/service_handle.cpp b/um/service/src/service_handle.cpp
new file mode 100644
index 0000000..adce7f0
--- /dev/null
+++ b/um/service/src/service_handle.cpp
@@ -0,0 +1,27 @@
+// Copyright (c) 2015 Egor Tensin <Egor.Tensin@gmail.com>
+// This file is part of the "Windows 7 drivers" project.
+// For details, see https://github.com/egor-tensin/windows7-drivers.
+// Distributed under the MIT License.
+
+#include "libservice/all.hpp"
+
+#include <utility>
+
+namespace libservice
+{
+ void swap(ServiceHandle& a, ServiceHandle& b) LIBSERVICE_NOEXCEPT
+ {
+ a.swap(b);
+ }
+}
+
+namespace std
+{
+ template <>
+ void swap<libservice::ServiceHandle>(
+ libservice::ServiceHandle& a,
+ libservice::ServiceHandle& b) LIBSERVICE_NOEXCEPT
+ {
+ a.swap(b);
+ }
+}
diff --git a/um/service/src/service_manager.cpp b/um/service/src/service_manager.cpp
new file mode 100644
index 0000000..61662de
--- /dev/null
+++ b/um/service/src/service_manager.cpp
@@ -0,0 +1,44 @@
+// Copyright (c) 2015 Egor Tensin <Egor.Tensin@gmail.com>
+// This file is part of the "Windows 7 drivers" project.
+// For details, see https://github.com/egor-tensin/windows7-drivers.
+// Distributed under the MIT License.
+
+#include "libservice/all.hpp"
+
+#include <Windows.h>
+
+#include <system_error>
+#include <utility>
+
+namespace libservice
+{
+ ServiceManager ServiceManager::open()
+ {
+ SC_HANDLE raw = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
+
+ if (NULL == raw)
+ {
+ const auto ec = GetLastError();
+ throw std::system_error(
+ ec, WindowsErrorCategory::get(), LIBSERVICE_ERROR_PREFIX);
+ }
+
+ return ServiceHandle(raw);
+ }
+
+ void swap(ServiceManager& a, ServiceManager& b) LIBSERVICE_NOEXCEPT
+ {
+ a.swap(b);
+ }
+}
+
+namespace std
+{
+ template <>
+ void swap<libservice::ServiceManager>(
+ libservice::ServiceManager& a,
+ libservice::ServiceManager& b) LIBSERVICE_NOEXCEPT
+ {
+ a.swap(b);
+ }
+}
diff --git a/um/service/src/windows_error.cpp b/um/service/src/windows_error.cpp
new file mode 100644
index 0000000..f27018b
--- /dev/null
+++ b/um/service/src/windows_error.cpp
@@ -0,0 +1,39 @@
+// Copyright (c) 2015 Egor Tensin <Egor.Tensin@gmail.com>
+// This file is part of the "Windows 7 drivers" project.
+// For details, see https://github.com/egor-tensin/windows7-drivers.
+// Distributed under the MIT License.
+
+#include "libservice/all.hpp"
+
+#include <Windows.h>
+
+#include <string>
+
+namespace libservice
+{
+ std::string WindowsErrorCategory::message(int code) const
+ {
+ char* buf_ptr;
+
+ const auto nbwritten = FormatMessageA(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER
+ | FORMAT_MESSAGE_FROM_SYSTEM
+ | FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ code,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ reinterpret_cast<char*>(&buf_ptr),
+ 0,
+ NULL);
+
+ if (0 == nbwritten)
+ {
+ LocalFree(buf_ptr);
+ return "Couldn't format error message";
+ }
+
+ std::string str(buf_ptr, nbwritten - 2);
+ LocalFree(buf_ptr);
+ return str;
+ }
+}