-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathServiceUtils.h
233 lines (211 loc) · 9.04 KB
/
ServiceUtils.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
// ServiceUtils.h
//
// Author: Mikko Saarinki
// Copyright (c) 2016 Mikko Saarinki. All rights reserved.
//
#pragma once
#include <windows.h>
#include <tchar.h>
#include <iostream>
#include <string>
#include <functional>
namespace ServiceUtils
{
//why microsoft doesn't provide human readable and easy
//conversion from their silly macro world is beyond comprehension
std::string t_convert(const TCHAR*);
//convenience method for human readable GetLastError()
std::string win32Error(DWORD error);
/**
* Handler for service setup options given on process start.
* These operations are convenience wrappers and not required by a service to run.
* They can be also done using SC commands externally.
*/
struct Setup
{
/**
* Handle service setup options.
*
* @param serviceName This is a good idea to avoid confusion: executable == serviceName.
* @param displayName Name displayed in Windows Services.
* @param description Description or overview of the service shown in Windows Services.
* @param argv command line arguments given. Only the first one is used or needed.
*/
int options(LPCTSTR serviceName,
LPCTSTR displayName,
LPTSTR description,
TCHAR *argv[]) const
{
if (!lstrcmpi(argv[1], TEXT("install")))
return options(serviceName, displayName, description, Mode::Install);
else if (!lstrcmpi(argv[1], TEXT("uninstall")))
return options(serviceName, displayName, description, Mode::Uninstall);
else if (!lstrcmpi(argv[1], TEXT("create")))
return options(serviceName, displayName, description, Mode::Create);
else if (!lstrcmpi(argv[1], TEXT("delete")))
return options(serviceName, displayName, description, Mode::Delete);
else if (!lstrcmpi(argv[1], TEXT("start")))
return options(serviceName, displayName, description, Mode::Start);
else if (!lstrcmpi(argv[1], TEXT("stop")))
return options(serviceName, displayName, description, Mode::Stop);
else help(serviceName);
return EXIT_SUCCESS;
}
private:
enum class Mode
{
Install,
Uninstall,
Create,
Delete,
Start,
Stop
};
int options(LPCTSTR serviceName,
LPCTSTR displayName,
LPTSTR description,
Mode mode) const
{
// Get a handle to the SCM database.
auto manager = OpenSCManager(
NULL, // local computer
NULL, // ServicesActive database
SC_MANAGER_ALL_ACCESS); // full access rights
if (!manager)
{
std::cout << "OpenSCManager error: " << win32Error(GetLastError()) << std::endl;
return EXIT_FAILURE;
}
switch (mode)
{
case Mode::Install:
create(serviceName, displayName, description, manager);
start(serviceName, manager);
break;
case Mode::Uninstall:
stop(serviceName, manager);
tryDelete(serviceName, manager);
break;
case Mode::Create: create(serviceName, displayName, description, manager); break;
case Mode::Delete: tryDelete(serviceName, manager); break;
case Mode::Start: start(serviceName, manager); break;
case Mode::Stop: stop(serviceName, manager); break;
default: break;
}
CloseServiceHandle(manager);
return EXIT_SUCCESS;
}
void create(LPCTSTR serviceName,
LPCTSTR displayName,
LPTSTR description,
SC_HANDLE manager) const
{
TCHAR binaryPath[MAX_PATH];
if (!GetModuleFileName(NULL, binaryPath, MAX_PATH))
{
std::cout << "GetModuleFileName error: " << win32Error(GetLastError()) << std::endl;
return;
}
auto service = CreateService(
manager, // SCM database
serviceName, // name of service
displayName, // service name to display
SERVICE_ALL_ACCESS, // desired access
SERVICE_WIN32_OWN_PROCESS, // service type
SERVICE_AUTO_START, // start type
SERVICE_ERROR_NORMAL, // error control type
binaryPath, // path to service's binary
NULL, // no load ordering group
NULL, // no tag identifier
NULL, // no dependencies
NULL, // LocalSystem account
NULL); // no password
if (service)
{
std::cout << "Service created." << std::endl;
CloseServiceHandle(service);
setDescription(serviceName, manager, description);
}
else std::cout << "CreateService error: " << win32Error(GetLastError()) << std::endl;
}
void tryDelete(LPCTSTR serviceName, SC_HANDLE manager) const
{
openService(serviceName,
manager,
DELETE,
"DeleteService",
"Service deleted.",
[](auto service) { return DeleteService(service) != 0; });
}
void start(LPCTSTR serviceName, SC_HANDLE manager) const
{
openService(serviceName,
manager,
SERVICE_START,
"StartService",
"Service running.",
[](auto service) { return StartService(service, 0, NULL) != 0; });
}
void stop(LPCTSTR serviceName, SC_HANDLE manager) const
{
openService(serviceName,
manager,
SERVICE_STOP,
"ControlService",
"Service stopped.",
[](auto service) {
SERVICE_STATUS status;
return ControlService(service, SERVICE_CONTROL_STOP, &status) != 0;
});
}
void setDescription(LPCTSTR serviceName, SC_HANDLE manager, LPTSTR description) const
{
openService(serviceName,
manager,
SERVICE_CHANGE_CONFIG,
"ChangeServiceConfig2",
"Service description added.",
[description](auto service) {
SERVICE_DESCRIPTION sd{ description };
return ChangeServiceConfig2(service, SERVICE_CONFIG_DESCRIPTION, &sd) != 0;
});
}
void openService(LPCTSTR serviceName,
SC_HANDLE manager,
DWORD desiredAccess,
const std::string &handlerName,
const std::string &successMessage,
const std::function<bool(SC_HANDLE)> &handler) const
{
auto service = OpenService(manager, // SCM database
serviceName,
desiredAccess);
if (service)
{
if (!handler(service))
std::cout << handlerName << " error: " << win32Error(GetLastError()) << std::endl;
else std::cout << successMessage << std::endl;
CloseServiceHandle(service);
}
else std::cout << "Unable to run " << handlerName << " due to OpenService error: " << win32Error(GetLastError()) << std::endl;
}
void help(LPCTSTR serviceName) const
{
auto service = t_convert(serviceName);
std::cout
<< "DESCRIPTION:" << std::endl
<< " Command line program options for setting up this service with the Service Control Manager." << std::endl
<< "USAGE:" << std::endl
<< " " << service << " <Option>" << std::endl << std::endl
<< " Options:" << std::endl
<< " install---------Creates this service as an Automatic startup service and sets it Running." << std::endl
<< " uninstall-------Stops this service and deletes it." << std::endl
<< " create----------Creates this service as an Automatic startup service." << std::endl
<< " delete----------Deletes this service ie. completely removed from Service Control." << std::endl
<< " start-----------Sets this service Running if it exists." << std::endl
<< " stop------------Stops this service if its Running." << std::endl
<< "EXAMPLE:" << std::endl
<< " " << service << " install" << std::endl << std::endl;
}
};
}//namespace ServiceUtils