Fixed some minor things with (yet unused) svchost
[reactos.git] / reactos / base / services / svchost / svchost.c
1 /*
2 * PROJECT: ReactOS SvcHost
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: /base/services/svchost/svchost.c
5 * PURPOSE: Provide dll service loader
6 * PROGRAMMERS: Gregor Brunmar (gregor.brunmar@home.se)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include "svchost.h"
12 #include <debug.h>
13
14 #ifdef _MSC_VER
15 #undef DPRINT1
16 #define DPRINT1
17 #endif
18
19 /* DEFINES *******************************************************************/
20
21 static LPCTSTR SVCHOST_REG_KEY = _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\SvcHost");
22 static LPCTSTR SERVICE_KEY = _T("SYSTEM\\CurrentControlSet\\Services\\");
23 static LPCTSTR PARAMETERS_KEY = _T("\\Parameters");
24
25 #define SERVICE_KEY_LENGTH _tcslen(SERVICE_KEY);
26 #define REG_MAX_DATA_SIZE 2048
27
28 static PSERVICE FirstService = NULL;
29
30 /* FUNCTIONS *****************************************************************/
31
32 BOOL PrepareService(LPCTSTR ServiceName)
33 {
34 HKEY hServiceKey;
35 TCHAR ServiceKeyBuffer[MAX_PATH + 1];
36 DWORD LeftOfBuffer = sizeof(ServiceKeyBuffer) / sizeof(ServiceKeyBuffer[0]);
37 DWORD KeyType;
38 PTSTR Buffer = NULL;
39 DWORD BufferSize = MAX_PATH + 1;
40 LONG RetVal;
41 HINSTANCE hServiceDll;
42 TCHAR DllPath[MAX_PATH + 2]; /* See MSDN on ExpandEnvironmentStrings() for ANSI strings for more details on + 2 */
43 LPSERVICE_MAIN_FUNCTION ServiceMainFunc;
44 PSERVICE Service;
45
46 /* Compose the registry path to the service's "Parameter" key */
47 _tcsncpy(ServiceKeyBuffer, SERVICE_KEY, LeftOfBuffer);
48 LeftOfBuffer -= _tcslen(SERVICE_KEY);
49 _tcsncat(ServiceKeyBuffer, ServiceName, LeftOfBuffer);
50 LeftOfBuffer -= _tcslen(ServiceName);
51 _tcsncat(ServiceKeyBuffer, PARAMETERS_KEY, LeftOfBuffer);
52 LeftOfBuffer -= _tcslen(PARAMETERS_KEY);
53
54 if (LeftOfBuffer < 0)
55 {
56 DPRINT1("Buffer overflow for service name: '%s'\n", ServiceName);
57 return FALSE;
58 }
59
60 /* Open the service registry key to find the dll name */
61 if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, ServiceKeyBuffer, 0, KEY_READ, &hServiceKey))
62 {
63 DPRINT1("Could not open service key (%s)\n", ServiceKeyBuffer);
64 return FALSE;
65 }
66
67 do
68 {
69 if (Buffer)
70 HeapFree(GetProcessHeap(), 0, Buffer);
71
72 Buffer = HeapAlloc(GetProcessHeap(), 0, BufferSize);
73 if (NULL == Buffer)
74 {
75 DPRINT1("Not enough memory for service: %s\n", ServiceName);
76 return FALSE;
77 }
78
79 RetVal = RegQueryValueEx(hServiceKey, _T("ServiceDll"), NULL, &KeyType, (LPBYTE)Buffer, &BufferSize);
80
81 } while (ERROR_MORE_DATA == RetVal);
82
83
84 RegCloseKey(hServiceKey);
85
86 if (ERROR_SUCCESS != RetVal || 0 == BufferSize)
87 {
88 DPRINT1("Could not read 'ServiceDll' value from service: %s, ErrorCode: 0x%x\n", ServiceName, RetVal);
89 HeapFree(GetProcessHeap(), 0, Buffer);
90 return FALSE;
91 }
92
93 /* Convert possible %SystemRoot% to a real path */
94 BufferSize = ExpandEnvironmentStrings(Buffer, DllPath, sizeof(DllPath));
95 if (0 == BufferSize)
96 {
97 DPRINT1("Invalid ServiceDll path: %s\n", Buffer);
98 HeapFree(GetProcessHeap(), 0, Buffer);
99 return FALSE;
100 }
101
102 HeapFree(GetProcessHeap(), 0, Buffer);
103
104 /* Load the service dll */
105 DPRINT1("Trying to load dll\n");
106 hServiceDll = LoadLibrary(DllPath);
107
108 if (NULL == hServiceDll)
109 {
110 DPRINT1("Unable to load ServiceDll: %s, ErrorCode: %u\n", DllPath, GetLastError());
111 return FALSE;
112 }
113
114 ServiceMainFunc = (LPSERVICE_MAIN_FUNCTION)GetProcAddress(hServiceDll, "ServiceMain");
115
116 /* Allocate a service node in the linked list */
117 Service = HeapAlloc(GetProcessHeap(), 0, sizeof(SERVICE));
118 if (NULL == Service)
119 {
120 DPRINT1("Not enough memory for service: %s\n", ServiceName);
121 return FALSE;
122 }
123
124 memset(Service, 0, sizeof(SERVICE));
125 Service->Name = HeapAlloc(GetProcessHeap(), 0, _tcslen(ServiceName) + sizeof(TCHAR));
126 if (NULL == Service->Name)
127 {
128 DPRINT1("Not enough memory for service: %s\n", ServiceName);
129 HeapFree(GetProcessHeap(), 0, Service);
130 return FALSE;
131 }
132 _tcscpy(Service->Name, ServiceName);
133
134 Service->hServiceDll = hServiceDll;
135 Service->ServiceMainFunc = ServiceMainFunc;
136
137 Service->Next = FirstService;
138 FirstService = Service;
139
140 return TRUE;
141 }
142
143 VOID FreeServices()
144 {
145 while (FirstService)
146 {
147 PSERVICE Service = FirstService;
148 FirstService = Service->Next;
149
150 FreeLibrary(Service->hServiceDll);
151
152 HeapFree(GetProcessHeap(), 0, Service->Name);
153 HeapFree(GetProcessHeap(), 0, Service);
154 }
155 }
156
157 /*
158 * Returns the number of services successfully loaded from the category
159 */
160 DWORD LoadServiceCategory(LPCTSTR ServiceCategory)
161 {
162 HKEY hServicesKey;
163 DWORD KeyType;
164 DWORD BufferSize = REG_MAX_DATA_SIZE;
165 TCHAR Buffer[REG_MAX_DATA_SIZE];
166 LPCTSTR ServiceName;
167 DWORD BufferIndex = 0;
168 DWORD NrOfServices = 0;
169
170 /* Get all the services in this category */
171 if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, SVCHOST_REG_KEY, 0, KEY_READ, &hServicesKey))
172 {
173 DPRINT1("Could not open service category: %s\n", ServiceCategory);
174 return 0;
175 }
176
177 if (ERROR_SUCCESS != RegQueryValueEx(hServicesKey, ServiceCategory, NULL, &KeyType, (LPBYTE)Buffer, &BufferSize))
178 {
179 DPRINT1("Could not open service category (2): %s\n", ServiceCategory);
180 RegCloseKey(hServicesKey);
181 return 0;
182 }
183
184 /* Clean up */
185 RegCloseKey(hServicesKey);
186
187 /* Load services in the category */
188 ServiceName = Buffer;
189 while (_T('\0') != ServiceName[0])
190 {
191 size_t Length;
192
193 Length = _tcslen(ServiceName);
194 if (0 == Length)
195 break;
196
197 if (TRUE == PrepareService(ServiceName))
198 ++NrOfServices;
199
200 BufferIndex += (Length + 1) * sizeof(TCHAR);
201
202 ServiceName = &Buffer[BufferIndex];
203 }
204
205 return NrOfServices;
206 }
207
208 int _tmain (int argc, LPTSTR argv [])
209 {
210 DWORD NrOfServices;
211 LPSERVICE_TABLE_ENTRY ServiceTable;
212
213 if (argc < 3)
214 {
215 /* MS svchost.exe doesn't seem to print help, should we? */
216 return 0;
217 }
218
219 if (_tcscmp(argv[1], _T("-k")) != 0)
220 {
221 /* For now, we only handle "-k" */
222 return 0;
223 }
224
225 NrOfServices = LoadServiceCategory(argv[2]);
226
227 DPRINT1("NrOfServices: %lu\n", NrOfServices);
228 if (0 == NrOfServices)
229 return 0;
230
231 ServiceTable = HeapAlloc(GetProcessHeap(), 0, sizeof(SERVICE_TABLE_ENTRY) * (NrOfServices + 1));
232
233 if (NULL != ServiceTable)
234 {
235 DWORD i;
236 PSERVICE Service = FirstService;
237
238 /* Fill the service table */
239 for (i = 0; i < NrOfServices; ++i)
240 {
241 DPRINT1("Loading service: %s\n", Service->Name);
242 ServiceTable[i].lpServiceName = Service->Name;
243 ServiceTable[i].lpServiceProc = Service->ServiceMainFunc;
244 Service = Service->Next;
245 }
246
247 /* Set a NULL entry to end the service table */
248 ServiceTable[i].lpServiceName = NULL;
249 ServiceTable[i].lpServiceProc = NULL;
250
251 if (FALSE == StartServiceCtrlDispatcher(ServiceTable))
252 printf("Failed to start service control dispatcher, ErrorCode: %lu\n", GetLastError());
253
254 HeapFree(GetProcessHeap(), 0, ServiceTable);
255 }
256 else
257 {
258 DPRINT1("Not enough memory for the service table, trying to allocate %u bytes\n", sizeof(SERVICE_TABLE_ENTRY) * (NrOfServices + 1));
259 }
260
261 DPRINT1("Freeing services...\n");
262 FreeServices();
263
264 return 0;
265 }
266
267 /* EOF */