aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/um
diff options
context:
space:
mode:
Diffstat (limited to 'um')
-rw-r--r--um/CMakeLists.txt6
-rw-r--r--um/README.md38
-rw-r--r--um/libnt_path_converter/CMakeLists.txt10
-rw-r--r--um/libnt_path_converter/README.md31
-rw-r--r--um/libnt_path_converter/include/libnt_path_converter/all.hpp8
-rw-r--r--um/libnt_path_converter/include/libnt_path_converter/device.hpp21
-rw-r--r--um/libnt_path_converter/src/device.cpp48
-rw-r--r--um/libnt_path_converter/utils/CMakeLists.txt2
-rw-r--r--um/libnt_path_converter/utils/convert_nt_path.cpp26
-rw-r--r--um/libservice/CMakeLists.txt10
-rw-r--r--um/libservice/README.md53
-rw-r--r--um/libservice/include/libservice/all.hpp15
-rw-r--r--um/libservice/include/libservice/common.hpp17
-rw-r--r--um/libservice/include/libservice/device.hpp75
-rw-r--r--um/libservice/include/libservice/handle.hpp77
-rw-r--r--um/libservice/include/libservice/service.hpp73
-rw-r--r--um/libservice/include/libservice/service_handle.hpp76
-rw-r--r--um/libservice/include/libservice/service_manager.hpp63
-rw-r--r--um/libservice/include/libservice/singleton.hpp43
-rw-r--r--um/libservice/include/libservice/windows_error.hpp31
-rw-r--r--um/libservice/src/device.cpp136
-rw-r--r--um/libservice/src/handle.cpp27
-rw-r--r--um/libservice/src/service.cpp276
-rw-r--r--um/libservice/src/service_handle.cpp27
-rw-r--r--um/libservice/src/service_manager.cpp44
-rw-r--r--um/libservice/src/windows_error.cpp39
-rw-r--r--um/libservice/test/CMakeLists.txt4
-rw-r--r--um/libservice/test/windows_error.cpp29
-rw-r--r--um/libservice/utils/CMakeLists.txt11
-rw-r--r--um/libservice/utils/install_service.cpp29
-rw-r--r--um/libservice/utils/start_service.cpp29
-rw-r--r--um/libservice/utils/stop_service.cpp29
-rw-r--r--um/libservice/utils/uninstall_service.cpp29
-rw-r--r--um/libsimple/CMakeLists.txt9
-rw-r--r--um/libsimple/README.md43
-rw-r--r--um/libsimple/include/libsimple/all.hpp8
-rw-r--r--um/libsimple/include/libsimple/device.hpp19
-rw-r--r--um/libsimple/src/device.cpp37
-rw-r--r--um/libsimple/utils/CMakeLists.txt2
-rw-r--r--um/libsimple/utils/exchange_ints.cpp44
40 files changed, 1594 insertions, 0 deletions
diff --git a/um/CMakeLists.txt b/um/CMakeLists.txt
new file mode 100644
index 0000000..31c8511
--- /dev/null
+++ b/um/CMakeLists.txt
@@ -0,0 +1,6 @@
+project(windows7_drivers_utils)
+
+add_subdirectory(libservice)
+
+add_subdirectory(libnt_path_converter)
+add_subdirectory(libsimple)
diff --git a/um/README.md b/um/README.md
new file mode 100644
index 0000000..f18091a
--- /dev/null
+++ b/um/README.md
@@ -0,0 +1,38 @@
+Driver utilities
+================
+
+A couple of usage examples are included along with the drivers.
+
+* [libservice]: Utilities to load/unload the drivers.
+* [libsimple]: [simple] driver usage examples.
+* [libnt_path_converter]: [nt_path_converter] driver usage examples.
+
+[libservice]: libservice/README.md
+[libsimple]: libsimple/README.md
+[simple]: ../km/src/simple
+[libnt_path_converter]: libnt_path_converter/README.md
+[nt_path_converter]: ../km/src/special/nt_path_converter
+
+Building the utilities
+----------------------
+
+Create the build files using CMake and build using Visual Studio.
+
+For example, using Visual Studio 2013 Update 4 for Windows Desktop (targetting
+x86):
+
+ > cd
+ C:\workspace\build\windows7-drivers
+
+ > cmake -G "Visual Studio 12 2013" C:\workspace\personal\windows7-drivers\um
+ ...
+
+ > msbuild windows7_drivers_utils.sln
+ ...
+
+See also
+--------
+
+* [License]
+
+[License]: ../README.md#license
diff --git a/um/libnt_path_converter/CMakeLists.txt b/um/libnt_path_converter/CMakeLists.txt
new file mode 100644
index 0000000..69f85d0
--- /dev/null
+++ b/um/libnt_path_converter/CMakeLists.txt
@@ -0,0 +1,10 @@
+project(libnt_path_converter)
+file(GLOB libnt_path_converter_sources "src/*.cpp")
+file(GLOB_RECURSE libnt_path_converter_headers "include/*.hpp")
+add_library(libnt_path_converter
+ ${libnt_path_converter_sources}
+ ${libnt_path_converter_headers})
+target_link_libraries(libnt_path_converter libservice)
+target_include_directories(libnt_path_converter PUBLIC include/)
+
+add_subdirectory(utils)
diff --git a/um/libnt_path_converter/README.md b/um/libnt_path_converter/README.md
new file mode 100644
index 0000000..74653dc
--- /dev/null
+++ b/um/libnt_path_converter/README.md
@@ -0,0 +1,31 @@
+nt_path_converter driver utilities
+==================================
+
+[nt_path_converter] driver usage examples.
+
+[nt_path_converter]: ../../km/src/special/nt_path_converter
+
+Usage
+-----
+
+### convert_nt_path.exe
+
+ Usage: convert_nt_path.exe [NT_PATH...]
+
+Converts a NT-style path to a DOS-style path.
+The NT namespace can be explored using the [WinObj] utility.
+For example:
+
+ > convert_nt_path.exe \Device\HarddiskVolume2\Windows
+ C:\Windows
+
+[WinObj]: https://technet.microsoft.com/en-us/library/bb896657.aspx
+
+See also
+--------
+
+* [Building the utilities]
+* [License]
+
+[Building the utilities]: ../README.md#building-the-utilities
+[License]: ../../README.md#license
diff --git a/um/libnt_path_converter/include/libnt_path_converter/all.hpp b/um/libnt_path_converter/include/libnt_path_converter/all.hpp
new file mode 100644
index 0000000..474b802
--- /dev/null
+++ b/um/libnt_path_converter/include/libnt_path_converter/all.hpp
@@ -0,0 +1,8 @@
+// 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.
+
+#pragma once
+
+#include "device.hpp"
diff --git a/um/libnt_path_converter/include/libnt_path_converter/device.hpp b/um/libnt_path_converter/include/libnt_path_converter/device.hpp
new file mode 100644
index 0000000..e1d75fb
--- /dev/null
+++ b/um/libnt_path_converter/include/libnt_path_converter/device.hpp
@@ -0,0 +1,21 @@
+// 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.
+
+#pragma once
+
+#include "libservice/all.hpp"
+
+#include <string>
+
+namespace libnt_path_converter
+{
+ class Device : libservice::Device
+ {
+ public:
+ Device();
+
+ std::wstring convert_nt_path(const std::wstring&);
+ };
+}
diff --git a/um/libnt_path_converter/src/device.cpp b/um/libnt_path_converter/src/device.cpp
new file mode 100644
index 0000000..90cd12f
--- /dev/null
+++ b/um/libnt_path_converter/src/device.cpp
@@ -0,0 +1,48 @@
+// 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 "libnt_path_converter/device.hpp"
+
+#include "libservice/all.hpp"
+
+#include <Windows.h>
+
+#include <string>
+#include <vector>
+
+namespace libnt_path_converter
+{
+ namespace
+ {
+ const char* const device_path = "\\\\.\\nt_path_converter";
+ const auto control_code = CTL_CODE(0x8000, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS);
+ }
+
+ Device::Device()
+ : libservice::Device(libservice::Device::open(device_path))
+ { }
+
+ std::wstring Device::convert_nt_path(const std::wstring& src)
+ {
+ const auto in_buf = src.c_str();
+ const auto in_buf_size = (src.size() + 1) * sizeof(wchar_t);
+
+ const auto nbreq = get_required_output_size(
+ control_code,
+ in_buf,
+ in_buf_size);
+
+ std::vector<unsigned char> output(nbreq);
+
+ send_control_code(
+ control_code,
+ in_buf,
+ in_buf_size,
+ output.data(),
+ nbreq);
+
+ return reinterpret_cast<wchar_t*>(output.data());
+ }
+}
diff --git a/um/libnt_path_converter/utils/CMakeLists.txt b/um/libnt_path_converter/utils/CMakeLists.txt
new file mode 100644
index 0000000..9915995
--- /dev/null
+++ b/um/libnt_path_converter/utils/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_executable(convert_nt_path convert_nt_path.cpp)
+target_link_libraries(convert_nt_path libnt_path_converter)
diff --git a/um/libnt_path_converter/utils/convert_nt_path.cpp b/um/libnt_path_converter/utils/convert_nt_path.cpp
new file mode 100644
index 0000000..0055db2
--- /dev/null
+++ b/um/libnt_path_converter/utils/convert_nt_path.cpp
@@ -0,0 +1,26 @@
+// 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 "libnt_path_converter/all.hpp"
+
+#include <exception>
+#include <iostream>
+
+int wmain(int argc, wchar_t* argv[])
+{
+ try
+ {
+ libnt_path_converter::Device dev;
+ for (int i = 1; i < argc; ++i)
+ std::wcout << dev.convert_nt_path(argv[i]) << L"\n";
+ }
+ catch (const std::exception& e)
+ {
+ std::wcerr << e.what() << "\n";
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/um/libservice/CMakeLists.txt b/um/libservice/CMakeLists.txt
new file mode 100644
index 0000000..34b3d13
--- /dev/null
+++ b/um/libservice/CMakeLists.txt
@@ -0,0 +1,10 @@
+file(GLOB libservice_sources "src/*.cpp")
+file(GLOB_RECURSE libservice_headers "include/*.hpp")
+add_library(libservice
+ ${libservice_sources}
+ ${libservice_headers})
+target_include_directories(libservice PUBLIC include)
+target_compile_definitions(libservice PRIVATE NOMINMAX)
+
+add_subdirectory(test)
+add_subdirectory(utils)
diff --git a/um/libservice/README.md b/um/libservice/README.md
new file mode 100644
index 0000000..f9fb601
--- /dev/null
+++ b/um/libservice/README.md
@@ -0,0 +1,53 @@
+Driver management utilities
+===========================
+
+Utilities to load/unload the drivers.
+
+Usage
+-----
+
+### install_service.exe
+
+ Usage: install_service.exe NAME SYS_PATH
+
+Installs a driver as a service.
+The same as
+
+ > sc create NAME type= kernel binPath= SYS_PATH
+
+### start_service.exe
+
+ Usage: start_service.exe NAME
+
+Starts the service `NAME` (loading the corresponding driver).
+The same as
+
+ > net start NAME
+
+### stop_service.exe
+
+ Usage: stop_service.exe NAME
+
+Stops the service `NAME` (unloading the corresponding driver).
+The same as
+
+ > net stop NAME
+
+### uninstall_service.exe
+
+ Usage: uninstall_service.exe NAME
+
+Uninstalls the service `NAME`, wiping the corresponding record from the
+registry.
+The same as
+
+ > sc delete NAME
+
+See also
+--------
+
+* [Building the utilities]
+* [License]
+
+[Building the utilities]: ../README.md#building-the-utilities
+[License]: ../../README.md#license
diff --git a/um/libservice/include/libservice/all.hpp b/um/libservice/include/libservice/all.hpp
new file mode 100644
index 0000000..a5761e0
--- /dev/null
+++ b/um/libservice/include/libservice/all.hpp
@@ -0,0 +1,15 @@
+// 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.
+
+#pragma once
+
+#include "common.hpp"
+#include "device.hpp"
+#include "handle.hpp"
+#include "service.hpp"
+#include "service_handle.hpp"
+#include "service_manager.hpp"
+#include "singleton.hpp"
+#include "windows_error.hpp"
diff --git a/um/libservice/include/libservice/common.hpp b/um/libservice/include/libservice/common.hpp
new file mode 100644
index 0000000..a1c46fb
--- /dev/null
+++ b/um/libservice/include/libservice/common.hpp
@@ -0,0 +1,17 @@
+// 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.
+
+#pragma once
+
+#define LIBSERVICE_FILE_PATH __FILE__
+#define LIBSERVICE_LINE_NUMBER __LINE__
+#define LIBSERVICE_FUNCTION_NAME __FUNCTION__
+
+#define LIBSERVICE_TO_STRING(s) LIBSERVICE_TO_STRING_(s)
+#define LIBSERVICE_TO_STRING_(s) #s
+
+#define LIBSERVICE_LINE_NUMBER_STRING LIBSERVICE_TO_STRING(LIBSERVICE_LINE_NUMBER)
+
+#define LIBSERVICE_NOEXCEPT throw()
diff --git a/um/libservice/include/libservice/device.hpp b/um/libservice/include/libservice/device.hpp
new file mode 100644
index 0000000..ac292c8
--- /dev/null
+++ b/um/libservice/include/libservice/device.hpp
@@ -0,0 +1,75 @@
+// 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.
+
+#pragma once
+
+#include "common.hpp"
+#include "handle.hpp"
+
+#include <Windows.h>
+
+#include <cstddef>
+
+#include <string>
+#include <utility>
+
+namespace libservice
+{
+ class Device
+ {
+ public:
+ typedef DWORD Code;
+
+ static Device open(const std::string& path);
+
+ Device(Device&& other) LIBSERVICE_NOEXCEPT
+ {
+ swap(other);
+ }
+
+ Device& operator=(Device other) LIBSERVICE_NOEXCEPT
+ {
+ swap(other);
+ return *this;
+ }
+
+ void swap(Device& other) LIBSERVICE_NOEXCEPT
+ {
+ using std::swap;
+ swap(handle, other.handle);
+ }
+
+ std::size_t get_required_output_size(
+ Code code,
+ const void* in_buf,
+ std::size_t in_buf_size) const;
+
+ std::size_t 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;
+
+ private:
+ Device(Handle handle)
+ : handle(std::move(handle))
+ { }
+
+ Handle handle;
+
+ Device(const Device&) = delete;
+ };
+
+ void swap(Device&, Device&) LIBSERVICE_NOEXCEPT;
+}
+
+namespace std
+{
+ template <>
+ void swap<libservice::Device>(
+ libservice::Device&,
+ libservice::Device&) LIBSERVICE_NOEXCEPT;
+}
diff --git a/um/libservice/include/libservice/handle.hpp b/um/libservice/include/libservice/handle.hpp
new file mode 100644
index 0000000..5e351d2
--- /dev/null
+++ b/um/libservice/include/libservice/handle.hpp
@@ -0,0 +1,77 @@
+// 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.
+
+#pragma once
+
+#include "common.hpp"
+
+#include <Windows.h>
+
+#include <memory>
+#include <type_traits>
+#include <utility>
+
+namespace libservice
+{
+ class Handle
+ {
+ public:
+ Handle() = default;
+
+ Handle(HANDLE raw)
+ : impl(raw)
+ { }
+
+ Handle(Handle&& other) LIBSERVICE_NOEXCEPT
+ {
+ swap(other);
+ }
+
+ Handle& operator=(Handle other) LIBSERVICE_NOEXCEPT
+ {
+ swap(other);
+ return *this;
+ }
+
+ operator bool() const
+ {
+ return static_cast<bool>(impl);
+ }
+
+ operator HANDLE() const
+ {
+ return impl.get();
+ }
+
+ void swap(Handle& other) LIBSERVICE_NOEXCEPT
+ {
+ using std::swap;
+ swap(impl, other.impl);
+ }
+
+ private:
+ struct Deleter
+ {
+ void operator()(HANDLE raw)
+ {
+ CloseHandle(raw);
+ }
+ };
+
+ std::unique_ptr<std::remove_pointer<HANDLE>::type, Deleter> impl;
+
+ Handle(const Handle&) = delete;
+ };
+
+ void swap(Handle& a, Handle& b) LIBSERVICE_NOEXCEPT;
+}
+
+namespace std
+{
+ template <>
+ void swap<libservice::Handle>(
+ libservice::Handle& a,
+ libservice::Handle& b) LIBSERVICE_NOEXCEPT;
+}
diff --git a/um/libservice/include/libservice/service.hpp b/um/libservice/include/libservice/service.hpp
new file mode 100644
index 0000000..089f790
--- /dev/null
+++ b/um/libservice/include/libservice/service.hpp
@@ -0,0 +1,73 @@
+// 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.
+
+#pragma once
+
+#include "common.hpp"
+#include "service_handle.hpp"
+#include "service_manager.hpp"
+
+#include <string>
+#include <utility>
+
+namespace libservice
+{
+ class Service
+ {
+ public:
+ static bool exists(
+ const ServiceManager&,
+ const std::string& name);
+
+ static Service open(
+ const ServiceManager&,
+ const std::string& name);
+
+ static Service install(
+ const ServiceManager&,
+ const std::string& name,
+ const std::string& bin_path);
+
+ void start() const;
+ void stop() const;
+ void uninstall() const;
+
+ Service(Service&& other) LIBSERVICE_NOEXCEPT
+ {
+ swap(other);
+ }
+
+ Service& operator=(Service other) LIBSERVICE_NOEXCEPT
+ {
+ swap(other);
+ return *this;
+ }
+
+ void swap(Service& other) LIBSERVICE_NOEXCEPT
+ {
+ using std::swap;
+ swap(handle, other.handle);
+ }
+
+ private:
+ Service(ServiceHandle handle)
+ : handle(std::move(handle))
+ { }
+
+ ServiceHandle handle;
+
+ Service(const Service&) = delete;
+ };
+
+ void swap(Service&, Service&) LIBSERVICE_NOEXCEPT;
+}
+
+namespace std
+{
+ template <>
+ void swap<libservice::Service>(
+ libservice::Service&,
+ libservice::Service&) LIBSERVICE_NOEXCEPT;
+}
diff --git a/um/libservice/include/libservice/service_handle.hpp b/um/libservice/include/libservice/service_handle.hpp
new file mode 100644
index 0000000..2883ff3
--- /dev/null
+++ b/um/libservice/include/libservice/service_handle.hpp
@@ -0,0 +1,76 @@
+// 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.
+
+#pragma once
+
+#include "common.hpp"
+
+#include <Windows.h>
+
+#include <memory>
+#include <utility>
+
+namespace libservice
+{
+ class ServiceHandle
+ {
+ public:
+ ServiceHandle() = default;
+
+ ServiceHandle(SC_HANDLE raw)
+ : impl(raw)
+ { }
+
+ ServiceHandle(ServiceHandle&& other) LIBSERVICE_NOEXCEPT
+ {
+ swap(other);
+ }
+
+ ServiceHandle& operator=(ServiceHandle other) LIBSERVICE_NOEXCEPT
+ {
+ swap(other);
+ return *this;
+ }
+
+ operator bool() const
+ {
+ return static_cast<bool>(impl);
+ }
+
+ operator SC_HANDLE() const
+ {
+ return impl.get();
+ }
+
+ void swap(ServiceHandle& other) LIBSERVICE_NOEXCEPT
+ {
+ using std::swap;
+ swap(impl, other.impl);
+ }
+
+ private:
+ struct Deleter
+ {
+ void operator()(SC_HANDLE raw)
+ {
+ CloseServiceHandle(raw);
+ }
+ };
+
+ std::unique_ptr<SC_HANDLE__, Deleter> impl;
+
+ ServiceHandle(const ServiceHandle&) = delete;
+ };
+
+ void swap(ServiceHandle&, ServiceHandle&) LIBSERVICE_NOEXCEPT;
+}
+
+namespace std
+{
+ template <>
+ void swap<libservice::ServiceHandle>(
+ libservice::ServiceHandle&,
+ libservice::ServiceHandle&) LIBSERVICE_NOEXCEPT;
+}
diff --git a/um/libservice/include/libservice/service_manager.hpp b/um/libservice/include/libservice/service_manager.hpp
new file mode 100644
index 0000000..80e6f12
--- /dev/null
+++ b/um/libservice/include/libservice/service_manager.hpp
@@ -0,0 +1,63 @@
+// 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.
+
+#pragma once
+
+#include "common.hpp"
+#include "service_handle.hpp"
+
+#include <Windows.h>
+
+#include <utility>
+
+namespace libservice
+{
+ class ServiceManager
+ {
+ public:
+ static ServiceManager open();
+
+ ServiceManager(ServiceManager&& other) LIBSERVICE_NOEXCEPT
+ {
+ swap(other);
+ }
+
+ ServiceManager& operator=(ServiceManager other) LIBSERVICE_NOEXCEPT
+ {
+ swap(other);
+ return *this;
+ }
+
+ void swap(ServiceManager& other) LIBSERVICE_NOEXCEPT
+ {
+ using std::swap;
+ swap(handle, other.handle);
+ }
+
+ operator SC_HANDLE() const
+ {
+ return handle;
+ }
+
+ private:
+ ServiceManager(ServiceHandle handle)
+ : handle(std::move(handle))
+ { }
+
+ ServiceHandle handle;
+
+ ServiceManager(const ServiceManager&) = delete;
+ };
+
+ void swap(ServiceManager& a, ServiceManager& b) LIBSERVICE_NOEXCEPT;
+}
+
+namespace std
+{
+ template <>
+ void swap<libservice::ServiceManager>(
+ libservice::ServiceManager&,
+ libservice::ServiceManager&) LIBSERVICE_NOEXCEPT;
+}
diff --git a/um/libservice/include/libservice/singleton.hpp b/um/libservice/include/libservice/singleton.hpp
new file mode 100644
index 0000000..1c7b1a7
--- /dev/null
+++ b/um/libservice/include/libservice/singleton.hpp
@@ -0,0 +1,43 @@
+// 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.
+
+#pragma once
+
+#include <mutex>
+
+namespace libservice
+{
+ template <typename DerivedT>
+ class Singleton
+ {
+ public:
+ static DerivedT& get()
+ {
+ std::call_once(initialized, initialize);
+ return get_unsafe();
+ }
+
+ protected:
+ Singleton() = default;
+ virtual ~Singleton() = default;
+
+ private:
+ static void initialize()
+ {
+ get_unsafe();
+ }
+
+ static DerivedT& get_unsafe()
+ {
+ static DerivedT instance;
+ return instance;
+ }
+
+ static std::once_flag initialized;
+ };
+
+ template <typename DerivedT>
+ std::once_flag Singleton<DerivedT>::initialized;
+}
diff --git a/um/libservice/include/libservice/windows_error.hpp b/um/libservice/include/libservice/windows_error.hpp
new file mode 100644
index 0000000..f7ac90e
--- /dev/null
+++ b/um/libservice/include/libservice/windows_error.hpp
@@ -0,0 +1,31 @@
+// 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.
+
+#pragma once
+
+#include "common.hpp"
+#include "singleton.hpp"
+
+#include <string>
+#include <system_error>
+
+namespace libservice
+{
+ class WindowsErrorCategory
+ : public std::error_category
+ , public Singleton<WindowsErrorCategory>
+ {
+ public:
+ const char* name() const LIBSERVICE_NOEXCEPT { return "Windows"; }
+
+ std::string message(int) const;
+
+ private:
+ friend class Singleton<WindowsErrorCategory>;
+ };
+}
+
+#define LIBSERVICE_ERROR_PREFIX \
+ "Error in function '" LIBSERVICE_FUNCTION_NAME "' at file '" LIBSERVICE_FILE_PATH "', line " LIBSERVICE_LINE_NUMBER_STRING
diff --git a/um/libservice/src/device.cpp b/um/libservice/src/device.cpp
new file mode 100644
index 0000000..5643106
--- /dev/null
+++ b/um/libservice/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/libservice/src/handle.cpp b/um/libservice/src/handle.cpp
new file mode 100644
index 0000000..7567781
--- /dev/null
+++ b/um/libservice/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/libservice/src/service.cpp b/um/libservice/src/service.cpp
new file mode 100644
index 0000000..8b5e043
--- /dev/null
+++ b/um/libservice/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/libservice/src/service_handle.cpp b/um/libservice/src/service_handle.cpp
new file mode 100644
index 0000000..adce7f0
--- /dev/null
+++ b/um/libservice/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/libservice/src/service_manager.cpp b/um/libservice/src/service_manager.cpp
new file mode 100644
index 0000000..61662de
--- /dev/null
+++ b/um/libservice/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/libservice/src/windows_error.cpp b/um/libservice/src/windows_error.cpp
new file mode 100644
index 0000000..f27018b
--- /dev/null
+++ b/um/libservice/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;
+ }
+}
diff --git a/um/libservice/test/CMakeLists.txt b/um/libservice/test/CMakeLists.txt
new file mode 100644
index 0000000..4780deb
--- /dev/null
+++ b/um/libservice/test/CMakeLists.txt
@@ -0,0 +1,4 @@
+add_executable(libservice_test_windows_error windows_error.cpp)
+target_link_libraries(libservice_test_windows_error libservice)
+set_target_properties(libservice_test_windows_error PROPERTIES
+ OUTPUT_NAME windows_error)
diff --git a/um/libservice/test/windows_error.cpp b/um/libservice/test/windows_error.cpp
new file mode 100644
index 0000000..b909670
--- /dev/null
+++ b/um/libservice/test/windows_error.cpp
@@ -0,0 +1,29 @@
+// 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 <exception>
+#include <iostream>
+#include <system_error>
+
+int main()
+{
+ try
+ {
+ throw std::system_error(
+ ERROR_FILE_NOT_FOUND,
+ libservice::WindowsErrorCategory::get(),
+ LIBSERVICE_ERROR_PREFIX);
+ }
+ catch (const std::exception& e)
+ {
+ std::cerr << e.what() << "\n";
+ return 1;
+ }
+ return 0;
+}
diff --git a/um/libservice/utils/CMakeLists.txt b/um/libservice/utils/CMakeLists.txt
new file mode 100644
index 0000000..061ab25
--- /dev/null
+++ b/um/libservice/utils/CMakeLists.txt
@@ -0,0 +1,11 @@
+add_executable(install_service install_service.cpp)
+target_link_libraries(install_service libservice)
+
+add_executable(start_service start_service.cpp)
+target_link_libraries(start_service libservice)
+
+add_executable(stop_service stop_service.cpp)
+target_link_libraries(stop_service libservice)
+
+add_executable(uninstall_service uninstall_service.cpp)
+target_link_libraries(uninstall_service libservice)
diff --git a/um/libservice/utils/install_service.cpp b/um/libservice/utils/install_service.cpp
new file mode 100644
index 0000000..f36af75
--- /dev/null
+++ b/um/libservice/utils/install_service.cpp
@@ -0,0 +1,29 @@
+// 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 <exception>
+#include <iostream>
+
+int main(int argc, char* argv[])
+{
+ if (argc != 3)
+ {
+ std::cout << "Usage: " << argv[0] << " NAME SYS_PATH\n";
+ return 1;
+ }
+
+ try
+ {
+ libservice::Service::install(libservice::ServiceManager::open(), argv[1], argv[2]);
+ }
+ catch (const std::exception& e)
+ {
+ std::cerr << e.what() << "\n";
+ return 1;
+ }
+ return 0;
+}
diff --git a/um/libservice/utils/start_service.cpp b/um/libservice/utils/start_service.cpp
new file mode 100644
index 0000000..fafee53
--- /dev/null
+++ b/um/libservice/utils/start_service.cpp
@@ -0,0 +1,29 @@
+// 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 <exception>
+#include <iostream>
+
+int main(int argc, char* argv[])
+{
+ if (argc != 2)
+ {
+ std::cout << "Usage: " << argv[0] << " NAME\n";
+ return 1;
+ }
+
+ try
+ {
+ libservice::Service::open(libservice::ServiceManager::open(), argv[1]).start();
+ }
+ catch (const std::exception& e)
+ {
+ std::cerr << e.what() << "\n";
+ return 1;
+ }
+ return 0;
+}
diff --git a/um/libservice/utils/stop_service.cpp b/um/libservice/utils/stop_service.cpp
new file mode 100644
index 0000000..800c7a9
--- /dev/null
+++ b/um/libservice/utils/stop_service.cpp
@@ -0,0 +1,29 @@
+// 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 <exception>
+#include <iostream>
+
+int main(int argc, char* argv[])
+{
+ if (argc != 2)
+ {
+ std::cout << "Usage: " << argv[0] << " NAME\n";
+ return 1;
+ }
+
+ try
+ {
+ libservice::Service::open(libservice::ServiceManager::open(), argv[1]).stop();
+ }
+ catch (const std::exception& e)
+ {
+ std::cerr << e.what() << "\n";
+ return 1;
+ }
+ return 0;
+}
diff --git a/um/libservice/utils/uninstall_service.cpp b/um/libservice/utils/uninstall_service.cpp
new file mode 100644
index 0000000..395bb51
--- /dev/null
+++ b/um/libservice/utils/uninstall_service.cpp
@@ -0,0 +1,29 @@
+// 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 <exception>
+#include <iostream>
+
+int main(int argc, char* argv[])
+{
+ if (argc != 2)
+ {
+ std::cout << "Usage: " << argv[0] << " NAME\n";
+ return 1;
+ }
+
+ try
+ {
+ libservice::Service::open(libservice::ServiceManager::open(), argv[1]).uninstall();
+ }
+ catch (const std::exception& e)
+ {
+ std::cerr << e.what() << "\n";
+ return 1;
+ }
+ return 0;
+}
diff --git a/um/libsimple/CMakeLists.txt b/um/libsimple/CMakeLists.txt
new file mode 100644
index 0000000..ff61bd7
--- /dev/null
+++ b/um/libsimple/CMakeLists.txt
@@ -0,0 +1,9 @@
+file(GLOB_RECURSE libsimple_headers "include/*.hpp")
+file(GLOB libsimple_sources "src/*.cpp")
+add_library(libsimple
+ ${libsimple_sources}
+ ${libsimple_headers})
+target_link_libraries(libsimple libservice)
+target_include_directories(libsimple PUBLIC include/)
+
+add_subdirectory(utils)
diff --git a/um/libsimple/README.md b/um/libsimple/README.md
new file mode 100644
index 0000000..ac00d63
--- /dev/null
+++ b/um/libsimple/README.md
@@ -0,0 +1,43 @@
+simple driver utilities
+=======================
+
+[simple] driver usage examples.
+
+[simple]: ../../km/src/simple
+
+Usage
+-----
+
+### exchange_ints.exe
+
+```
+Usage: exchange_ints.exe N
+```
+
+Parses its argument as an `unsigned int` and exchanges it with the one stored
+in [simple] driver's memory.
+For example:
+
+```
+> exchange_ints.exe 1
+42
+```
+
+```
+> exchange_ints.exe 32
+1
+```
+
+```
+> exchange_ints.exe 100500
+32
+```
+
+See also
+--------
+
+* [Building the utilities]
+* [License]
+
+[Building the utilities]: ../README.md#building-the-utilities
+[License]: ../../README.md#license
diff --git a/um/libsimple/include/libsimple/all.hpp b/um/libsimple/include/libsimple/all.hpp
new file mode 100644
index 0000000..474b802
--- /dev/null
+++ b/um/libsimple/include/libsimple/all.hpp
@@ -0,0 +1,8 @@
+// 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.
+
+#pragma once
+
+#include "device.hpp"
diff --git a/um/libsimple/include/libsimple/device.hpp b/um/libsimple/include/libsimple/device.hpp
new file mode 100644
index 0000000..3318818
--- /dev/null
+++ b/um/libsimple/include/libsimple/device.hpp
@@ -0,0 +1,19 @@
+// 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.
+
+#pragma once
+
+#include "libservice/all.hpp"
+
+namespace libsimple
+{
+ class Device : libservice::Device
+ {
+ public:
+ Device();
+
+ unsigned int exchange_ints(unsigned int) const;
+ };
+}
diff --git a/um/libsimple/src/device.cpp b/um/libsimple/src/device.cpp
new file mode 100644
index 0000000..57e6963
--- /dev/null
+++ b/um/libsimple/src/device.cpp
@@ -0,0 +1,37 @@
+// 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 "libsimple/all.hpp"
+
+#include "libservice/all.hpp"
+
+#include <Windows.h>
+
+namespace libsimple
+{
+ namespace
+ {
+ const char* const device_path = "\\\\.\\simple_device1";
+ const auto exchange_ints_ctl_code = CTL_CODE(0x8001, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS);
+ }
+
+ Device::Device()
+ : libservice::Device(libservice::Device::open(device_path))
+ { }
+
+ unsigned int Device::exchange_ints(unsigned int src) const
+ {
+ unsigned int dest;
+
+ send_control_code(
+ exchange_ints_ctl_code,
+ &src,
+ sizeof(src),
+ &dest,
+ sizeof(dest));
+
+ return dest;
+ }
+}
diff --git a/um/libsimple/utils/CMakeLists.txt b/um/libsimple/utils/CMakeLists.txt
new file mode 100644
index 0000000..8824e3e
--- /dev/null
+++ b/um/libsimple/utils/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_executable(exchange_ints exchange_ints.cpp)
+target_link_libraries(exchange_ints libsimple)
diff --git a/um/libsimple/utils/exchange_ints.cpp b/um/libsimple/utils/exchange_ints.cpp
new file mode 100644
index 0000000..2935b2f
--- /dev/null
+++ b/um/libsimple/utils/exchange_ints.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 "libsimple/all.hpp"
+
+#include <exception>
+#include <iostream>
+#include <sstream>
+#include <string>
+
+namespace
+{
+ bool parse_int(unsigned int& dest, const std::string& src)
+ {
+ std::istringstream iss(src);
+ char c;
+ return iss >> dest && !iss.get(c);
+ }
+}
+
+int main(int argc, char* argv[])
+{
+ try
+ {
+ unsigned int src;
+
+ if (argc != 2 || !parse_int(src, argv[1]))
+ {
+ std::cout << "Usage: " << argv[0] << " N\n";
+ return 1;
+ }
+
+ std::cout << libsimple::Device().exchange_ints(src) << "\n";
+ }
+ catch (const std::exception& e)
+ {
+ std::cerr << e.what() << "\n";
+ return 1;
+ }
+
+ return 0;
+}