TrinityCore
Loading...
Searching...
No Matches
ServiceWin32.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "ServiceWin32.h"
19#include <array> // for std::size
20#include <cstdio>
21#include <cstdlib>
22#include <cstring>
23#include <Windows.h>
24#include <winsvc.h>
25
26namespace
27{
28_TCHAR* ServiceLongName;
29_TCHAR* ServiceName;
30_TCHAR* ServiceDescription;
31int(*ServiceEntryPoint)(int argc, char** argv);
32int* ServiceStatusPtr;
33
34SERVICE_STATUS ServiceStatus;
35SERVICE_STATUS_HANDLE ServiceStatusHandle = nullptr;
36}
37
38typedef BOOL (WINAPI *CSD_T)(SC_HANDLE, DWORD, LPCVOID);
39
40void Trinity::Service::Init(_TCHAR* serviceLongName, _TCHAR* serviceName, _TCHAR* serviceDescription, int(* entryPoint)(int argc, char** argv), int* status)
41{
42 ServiceLongName = serviceLongName;
43 ServiceName = serviceName;
44 ServiceDescription = serviceDescription;
45 ServiceEntryPoint = entryPoint;
46 ServiceStatusPtr = status;
47}
48
50{
51 SC_HANDLE serviceControlManager = OpenSCManager(nullptr, nullptr, SC_MANAGER_CREATE_SERVICE);
52
53 if (serviceControlManager)
54 {
55 TCHAR path[_MAX_PATH + 10];
56 if (GetModuleFileName(nullptr, path, std::size(path)) > 0)
57 {
58 _tcscat(path, _T(" --service run"));
59 SC_HANDLE service = CreateService(serviceControlManager,
60 ServiceName, // name of service
61 ServiceLongName, // service name to display
62 SERVICE_ALL_ACCESS, // desired access
63 // service type
64 SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
65 SERVICE_AUTO_START, // start type
66 SERVICE_ERROR_IGNORE, // error control type
67 path, // service's binary
68 nullptr, // no load ordering group
69 nullptr, // no tag identifier
70 nullptr, // no dependencies
71 nullptr, // LocalSystem account
72 nullptr); // no password
73 if (service)
74 {
75 SERVICE_DESCRIPTION sdBuf;
76 sdBuf.lpDescription = ServiceDescription;
77 ChangeServiceConfig2(
78 service, // handle to service
79 SERVICE_CONFIG_DESCRIPTION, // change: description
80 &sdBuf); // new data
81
82 SC_ACTION _action[1];
83 _action[0].Type = SC_ACTION_RESTART;
84 _action[0].Delay = 10000;
85 SERVICE_FAILURE_ACTIONS sfa;
86 ZeroMemory(&sfa, sizeof(SERVICE_FAILURE_ACTIONS));
87 sfa.lpsaActions = _action;
88 sfa.cActions = 1;
89 sfa.dwResetPeriod = INFINITE;
90 ChangeServiceConfig2(
91 service, // handle to service
92 SERVICE_CONFIG_FAILURE_ACTIONS, // information level
93 &sfa); // new data
94
95 CloseServiceHandle(service);
96
97 }
98 }
99 CloseServiceHandle(serviceControlManager);
100 }
101
102 printf("Service installed\n");
103 return 0;
104}
105
107{
108 SC_HANDLE serviceControlManager = OpenSCManager(nullptr, nullptr, SC_MANAGER_CONNECT);
109
110 if (serviceControlManager)
111 {
112 SC_HANDLE service = OpenService(serviceControlManager,
113 ServiceName, SERVICE_QUERY_STATUS | DELETE);
114 if (service)
115 {
116 SERVICE_STATUS serviceStatus2;
117 if (QueryServiceStatus(service, &serviceStatus2))
118 {
119 if (serviceStatus2.dwCurrentState == SERVICE_STOPPED)
120 DeleteService(service);
121 }
122 CloseServiceHandle(service);
123 }
124
125 CloseServiceHandle(serviceControlManager);
126 }
127
128 printf("Service uninstalled\n");
129 return 0;
130}
131
132void WINAPI ServiceControlHandler(DWORD controlCode)
133{
134 switch (controlCode)
135 {
136 case SERVICE_CONTROL_INTERROGATE:
137 break;
138
139 case SERVICE_CONTROL_SHUTDOWN:
140 case SERVICE_CONTROL_STOP:
141 ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
142 SetServiceStatus(ServiceStatusHandle, &ServiceStatus);
143
144 *ServiceStatusPtr = 0;
145 return;
146
147 case SERVICE_CONTROL_PAUSE:
148 *ServiceStatusPtr = 2;
149 ServiceStatus.dwCurrentState = SERVICE_PAUSED;
150 SetServiceStatus(ServiceStatusHandle, &ServiceStatus);
151 break;
152
153 case SERVICE_CONTROL_CONTINUE:
154 ServiceStatus.dwCurrentState = SERVICE_RUNNING;
155 SetServiceStatus(ServiceStatusHandle, &ServiceStatus);
156 *ServiceStatusPtr = 1;
157 break;
158
159 default:
160 if (controlCode >= 128 && controlCode <= 255)
161 // user defined control code
162 break;
163 else
164 // unrecognized control code
165 break;
166 }
167
168 SetServiceStatus(ServiceStatusHandle, &ServiceStatus);
169}
170
171template<size_t size>
172void TCharToChar(TCHAR const* src, char(&dst)[size])
173{
174 if constexpr (std::is_same_v<TCHAR, char>)
175 ::strcpy_s(dst, src);
176 else
177 ::wcstombs_s(nullptr, dst, src, _TRUNCATE);
178}
179
180void WINAPI ServiceMain(DWORD /*argc*/, TCHAR *argv[])
181{
182 // initialise service status
183 ServiceStatus.dwServiceType = SERVICE_WIN32;
184 ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
185 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE;
186 ServiceStatus.dwWin32ExitCode = NO_ERROR;
187 ServiceStatus.dwServiceSpecificExitCode = NO_ERROR;
188 ServiceStatus.dwCheckPoint = 0;
189 ServiceStatus.dwWaitHint = 0;
190
191 ServiceStatusHandle = RegisterServiceCtrlHandler(ServiceName, ServiceControlHandler);
192
193 if (ServiceStatusHandle)
194 {
195 TCHAR path[_MAX_PATH + 1];
196 size_t last_slash = 0;
197
198 size_t pathLen = GetModuleFileName(nullptr, path, std::size(path));
199 for (size_t i = 0; i < pathLen; i++)
200 if (path[i] == '\\')
201 last_slash = i;
202
203 path[last_slash] = 0;
204
205 // service is starting
206 ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
207 SetServiceStatus(ServiceStatusHandle, &ServiceStatus);
208
209 // do initialisation here
210 SetCurrentDirectory(path);
211
212 // running
213 ServiceStatus.dwControlsAccepted |= (SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN);
214 ServiceStatus.dwCurrentState = SERVICE_RUNNING;
215 SetServiceStatus(ServiceStatusHandle, &ServiceStatus);
216
218 // service main cycle //
220
221 *ServiceStatusPtr = 1;
222
223 char cArg[_MAX_PATH + 1];
224 TCharToChar(argv[0], cArg);
225 char* cArgv[] = { cArg };
226
227 ServiceEntryPoint(1, cArgv);
228
229 // service was stopped
230 ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
231 SetServiceStatus(ServiceStatusHandle, &ServiceStatus);
232
233 // do cleanup here
234
235 // service is now stopped
236 ServiceStatus.dwControlsAccepted &= ~(SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN);
237 ServiceStatus.dwCurrentState = SERVICE_STOPPED;
238 SetServiceStatus(ServiceStatusHandle, &ServiceStatus);
239 }
240}
241
243{
244 SERVICE_TABLE_ENTRY serviceTable[] =
245 {
246 { ServiceName, ServiceMain },
247 { nullptr, nullptr }
248 };
249
250 if (!StartServiceCtrlDispatcher(serviceTable))
251 {
252 printf("StartService Failed. Error [%u]", uint32(::GetLastError()));
253 return 1;
254 }
255 return 0;
256}
int32_t int32
Definition Define.h:150
uint32_t uint32
Definition Define.h:154
BOOL(WINAPI * CSD_T)(SC_HANDLE, DWORD, LPCVOID)
void WINAPI ServiceMain(DWORD, TCHAR *argv[])
void TCharToChar(TCHAR const *src, char(&dst)[size])
void WINAPI ServiceControlHandler(DWORD controlCode)
TCHAR serviceLongName[]
Definition Main.cpp:71
TCHAR serviceName[]
Definition Main.cpp:70
TCHAR serviceDescription[]
Definition Main.cpp:72
TC_COMMON_API void Init(_TCHAR *serviceLongName, _TCHAR *serviceName, _TCHAR *serviceDescription, int(*entryPoint)(int argc, char **argv), int *status)
TC_COMMON_API int32 Install()
TC_COMMON_API int32 Uninstall()
TC_COMMON_API int32 Run()