- Move NCI generated files to arch-specific directories
[reactos.git] / reactos / dll / win32 / advapi32 / service / sctrl.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS system libraries
5 * FILE: lib/advapi32/service/sctrl.c
6 * PURPOSE: Service control manager functions
7 * PROGRAMMER: Emanuele Aliberti
8 * UPDATE HISTORY:
9 * 19990413 EA created
10 * 19990515 EA
11 */
12
13 /* INCLUDES ******************************************************************/
14
15 #include <advapi32.h>
16
17 #define NDEBUG
18 #include <debug.h>
19
20
21 /* TYPES *********************************************************************/
22
23 typedef struct _ACTIVE_SERVICE
24 {
25 DWORD ThreadId;
26 UNICODE_STRING ServiceName;
27 union
28 {
29 LPSERVICE_MAIN_FUNCTIONA lpFuncA;
30 LPSERVICE_MAIN_FUNCTIONW lpFuncW;
31 } Main;
32 LPHANDLER_FUNCTION HandlerFunction;
33 LPHANDLER_FUNCTION_EX HandlerFunctionEx;
34 LPVOID HandlerContext;
35 SERVICE_STATUS ServiceStatus;
36 BOOL bUnicode;
37 LPWSTR Arguments;
38 } ACTIVE_SERVICE, *PACTIVE_SERVICE;
39
40
41 /* GLOBALS *******************************************************************/
42
43 static DWORD dwActiveServiceCount = 0;
44 static PACTIVE_SERVICE lpActiveServices = NULL;
45
46
47 /* FUNCTIONS *****************************************************************/
48
49 static PACTIVE_SERVICE
50 ScLookupServiceByServiceName(LPCWSTR lpServiceName)
51 {
52 DWORD i;
53
54 for (i = 0; i < dwActiveServiceCount; i++)
55 {
56 if (_wcsicmp(lpActiveServices[i].ServiceName.Buffer, lpServiceName) == 0)
57 {
58 return &lpActiveServices[i];
59 }
60 }
61
62 SetLastError(ERROR_SERVICE_DOES_NOT_EXIST);
63
64 return NULL;
65 }
66
67
68 static PACTIVE_SERVICE
69 ScLookupServiceByThreadId(DWORD ThreadId)
70 {
71 DWORD i;
72
73 for (i = 0; i < dwActiveServiceCount; i++)
74 {
75 if (lpActiveServices[i].ThreadId == ThreadId)
76 {
77 return &lpActiveServices[i];
78 }
79 }
80
81 SetLastError(ERROR_SERVICE_DOES_NOT_EXIST);
82
83 return NULL;
84 }
85
86
87 static DWORD WINAPI
88 ScServiceMainStub(LPVOID Context)
89 {
90 PACTIVE_SERVICE lpService;
91 DWORD dwArgCount = 0;
92 DWORD dwLength = 0;
93 DWORD dwLen;
94 LPWSTR lpPtr;
95
96 lpService = (PACTIVE_SERVICE)Context;
97
98 DPRINT("ScServiceMainStub() called\n");
99
100 /* Count arguments */
101 lpPtr = lpService->Arguments;
102 while (*lpPtr)
103 {
104 DPRINT("arg: %S\n", *lpPtr);
105 dwLen = wcslen(lpPtr) + 1;
106 dwArgCount++;
107 dwLength += dwLen;
108 lpPtr += dwLen;
109 }
110 DPRINT("dwArgCount: %ld\ndwLength: %ld\n", dwArgCount, dwLength);
111
112 /* Build the argument vector and call the main service routine */
113 if (lpService->bUnicode)
114 {
115 LPWSTR *lpArgVector;
116 LPWSTR Ptr;
117
118 lpArgVector = HeapAlloc(GetProcessHeap(),
119 HEAP_ZERO_MEMORY,
120 (dwArgCount + 1) * sizeof(LPWSTR));
121 if (lpArgVector == NULL)
122 return ERROR_OUTOFMEMORY;
123
124 dwArgCount = 0;
125 Ptr = lpService->Arguments;
126 while (*Ptr)
127 {
128 lpArgVector[dwArgCount] = Ptr;
129
130 dwArgCount++;
131 Ptr += (wcslen(Ptr) + 1);
132 }
133 lpArgVector[dwArgCount] = NULL;
134
135 (lpService->Main.lpFuncW)(dwArgCount, lpArgVector);
136
137 HeapFree(GetProcessHeap(),
138 0,
139 lpArgVector);
140 }
141 else
142 {
143 LPSTR *lpArgVector;
144 LPSTR Ptr;
145 LPSTR AnsiString;
146 DWORD AnsiLength;
147
148 AnsiLength = WideCharToMultiByte(CP_ACP,
149 0,
150 lpService->Arguments,
151 dwLength,
152 NULL,
153 0,
154 NULL,
155 NULL);
156 AnsiString = HeapAlloc(GetProcessHeap(),
157 0,
158 AnsiLength);
159 WideCharToMultiByte(CP_ACP,
160 0,
161 lpService->Arguments,
162 dwLength,
163 AnsiString,
164 AnsiLength,
165 NULL,
166 NULL);
167
168 lpArgVector = HeapAlloc(GetProcessHeap(),
169 0,
170 (dwArgCount + 1) * sizeof(LPSTR));
171
172 dwArgCount = 0;
173 Ptr = AnsiString;
174 while (*Ptr)
175 {
176 lpArgVector[dwArgCount] = Ptr;
177
178 dwArgCount++;
179 Ptr += (strlen(Ptr) + 1);
180 }
181 lpArgVector[dwArgCount] = NULL;
182
183 (lpService->Main.lpFuncA)(dwArgCount, lpArgVector);
184
185 HeapFree(GetProcessHeap(),
186 0,
187 lpArgVector);
188 HeapFree(GetProcessHeap(),
189 0,
190 AnsiString);
191 }
192
193 return ERROR_SUCCESS;
194 }
195
196
197 static DWORD
198 ScConnectControlPipe(HANDLE *hPipe)
199 {
200 DWORD dwBytesWritten;
201 DWORD dwProcessId;
202 DWORD dwState;
203
204 if (!WaitNamedPipeW(L"\\\\.\\pipe\\net\\NtControlPipe", 15000))
205 {
206 DPRINT1("WaitNamedPipe() failed (Error %lu)\n", GetLastError());
207 return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT;
208 }
209
210 *hPipe = CreateFileW(L"\\\\.\\pipe\\net\\NtControlPipe",
211 GENERIC_READ | GENERIC_WRITE,
212 0,
213 NULL,
214 OPEN_EXISTING,
215 FILE_ATTRIBUTE_NORMAL,
216 NULL);
217 if (*hPipe == INVALID_HANDLE_VALUE)
218 {
219 DPRINT1("CreateFileW() failed (Error %lu)\n", GetLastError());
220 return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT;
221 }
222
223 dwState = PIPE_READMODE_MESSAGE;
224 if (!SetNamedPipeHandleState(*hPipe, &dwState, NULL, NULL))
225 {
226 CloseHandle(hPipe);
227 *hPipe = INVALID_HANDLE_VALUE;
228 return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT;
229 }
230
231 dwProcessId = GetCurrentProcessId();
232 WriteFile(*hPipe,
233 &dwProcessId,
234 sizeof(DWORD),
235 &dwBytesWritten,
236 NULL);
237
238 DPRINT("Sent process id %lu\n", dwProcessId);
239
240 return ERROR_SUCCESS;
241 }
242
243
244
245 static DWORD
246 ScStartService(PSCM_CONTROL_PACKET ControlPacket)
247 {
248 PACTIVE_SERVICE lpService;
249 HANDLE ThreadHandle;
250
251 DPRINT("ScStartService() called\n");
252 DPRINT("Size: %lu\n", ControlPacket->dwSize);
253 DPRINT("Service: %S\n", &ControlPacket->szArguments[0]);
254
255 lpService = ScLookupServiceByServiceName(&ControlPacket->szArguments[0]);
256 if (lpService == NULL)
257 return ERROR_SERVICE_DOES_NOT_EXIST;
258
259 lpService->Arguments = HeapAlloc(GetProcessHeap(),
260 HEAP_ZERO_MEMORY,
261 ControlPacket->dwSize * sizeof(WCHAR));
262 if (lpService->Arguments == NULL)
263 return ERROR_OUTOFMEMORY;
264
265 memcpy(lpService->Arguments,
266 ControlPacket->szArguments,
267 ControlPacket->dwSize * sizeof(WCHAR));
268
269 ThreadHandle = CreateThread(NULL,
270 0,
271 ScServiceMainStub,
272 lpService,
273 CREATE_SUSPENDED,
274 &lpService->ThreadId);
275 if (ThreadHandle == NULL)
276 return ERROR_SERVICE_NO_THREAD;
277
278 ResumeThread(ThreadHandle);
279 CloseHandle(ThreadHandle);
280
281 return ERROR_SUCCESS;
282 }
283
284
285 static BOOL
286 ScServiceDispatcher(HANDLE hPipe,
287 PUCHAR lpBuffer,
288 DWORD dwBufferSize)
289 {
290 PSCM_CONTROL_PACKET ControlPacket;
291 DWORD Count;
292 BOOL bResult;
293 DWORD dwRunningServices = 0;
294
295 DPRINT("ScDispatcherLoop() called\n");
296
297 ControlPacket = HeapAlloc(GetProcessHeap(),
298 HEAP_ZERO_MEMORY,
299 1024);
300 if (ControlPacket == NULL)
301 return FALSE;
302
303 while (TRUE)
304 {
305 /* Read command from the control pipe */
306 bResult = ReadFile(hPipe,
307 ControlPacket,
308 1024,
309 &Count,
310 NULL);
311 if (bResult == FALSE)
312 {
313 DPRINT1("Pipe read failed (Error: %lu)\n", GetLastError());
314 return FALSE;
315 }
316
317 /* Execute command */
318 switch (ControlPacket->dwControl)
319 {
320 case SERVICE_CONTROL_START:
321 DPRINT("Start command\n");
322 if (ScStartService(ControlPacket) == ERROR_SUCCESS)
323 dwRunningServices++;
324 break;
325
326 case SERVICE_CONTROL_STOP:
327 DPRINT("Stop command\n");
328 dwRunningServices--;
329 break;
330
331 default:
332 DPRINT1("Unknown command %lu", ControlPacket->dwControl);
333 break;
334 }
335
336 if (dwRunningServices == 0)
337 break;
338 }
339
340 HeapFree(GetProcessHeap(),
341 0,
342 ControlPacket);
343
344 return TRUE;
345 }
346
347
348 /**********************************************************************
349 * RegisterServiceCtrlHandlerA
350 *
351 * @implemented
352 */
353 SERVICE_STATUS_HANDLE STDCALL
354 RegisterServiceCtrlHandlerA(LPCSTR lpServiceName,
355 LPHANDLER_FUNCTION lpHandlerProc)
356 {
357 ANSI_STRING ServiceNameA;
358 UNICODE_STRING ServiceNameU;
359 SERVICE_STATUS_HANDLE SHandle;
360
361 RtlInitAnsiString(&ServiceNameA, (LPSTR)lpServiceName);
362 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ServiceNameU, &ServiceNameA, TRUE)))
363 {
364 SetLastError(ERROR_OUTOFMEMORY);
365 return (SERVICE_STATUS_HANDLE)0;
366 }
367
368 SHandle = RegisterServiceCtrlHandlerW(ServiceNameU.Buffer,
369 lpHandlerProc);
370
371 RtlFreeUnicodeString(&ServiceNameU);
372
373 return SHandle;
374 }
375
376
377 /**********************************************************************
378 * RegisterServiceCtrlHandlerW
379 *
380 * @implemented
381 */
382 SERVICE_STATUS_HANDLE STDCALL
383 RegisterServiceCtrlHandlerW(LPCWSTR lpServiceName,
384 LPHANDLER_FUNCTION lpHandlerProc)
385 {
386 PACTIVE_SERVICE Service;
387
388 Service = ScLookupServiceByServiceName((LPWSTR)lpServiceName);
389 if (Service == NULL)
390 {
391 return (SERVICE_STATUS_HANDLE)NULL;
392 }
393
394 Service->HandlerFunction = lpHandlerProc;
395 Service->HandlerFunctionEx = NULL;
396
397 return (SERVICE_STATUS_HANDLE)Service->ThreadId;
398 }
399
400
401 /**********************************************************************
402 * RegisterServiceCtrlHandlerExA
403 *
404 * @implemented
405 */
406 SERVICE_STATUS_HANDLE STDCALL
407 RegisterServiceCtrlHandlerExA(LPCSTR lpServiceName,
408 LPHANDLER_FUNCTION_EX lpHandlerProc,
409 LPVOID lpContext)
410 {
411 ANSI_STRING ServiceNameA;
412 UNICODE_STRING ServiceNameU;
413 SERVICE_STATUS_HANDLE SHandle;
414
415 RtlInitAnsiString(&ServiceNameA, (LPSTR)lpServiceName);
416 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ServiceNameU, &ServiceNameA, TRUE)))
417 {
418 SetLastError(ERROR_OUTOFMEMORY);
419 return (SERVICE_STATUS_HANDLE)0;
420 }
421
422 SHandle = RegisterServiceCtrlHandlerExW(ServiceNameU.Buffer,
423 lpHandlerProc,
424 lpContext);
425
426 RtlFreeUnicodeString(&ServiceNameU);
427
428 return SHandle;
429 }
430
431
432 /**********************************************************************
433 * RegisterServiceCtrlHandlerExW
434 *
435 * @implemented
436 */
437 SERVICE_STATUS_HANDLE STDCALL
438 RegisterServiceCtrlHandlerExW(LPCWSTR lpServiceName,
439 LPHANDLER_FUNCTION_EX lpHandlerProc,
440 LPVOID lpContext)
441 {
442 PACTIVE_SERVICE Service;
443
444 Service = ScLookupServiceByServiceName(lpServiceName);
445 if (Service == NULL)
446 {
447 return (SERVICE_STATUS_HANDLE)NULL;
448 }
449
450 Service->HandlerFunction = NULL;
451 Service->HandlerFunctionEx = lpHandlerProc;
452 Service->HandlerContext = lpContext;
453
454 return (SERVICE_STATUS_HANDLE)Service->ThreadId;
455 }
456
457
458 /**********************************************************************
459 * SetServiceBits
460 *
461 * @unimplemented
462 */
463 BOOL STDCALL
464 SetServiceBits(SERVICE_STATUS_HANDLE hServiceStatus,
465 DWORD dwServiceBits,
466 BOOL bSetBitsOn,
467 BOOL bUpdateImmediately)
468 {
469 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
470 return FALSE;
471 }
472
473
474 /**********************************************************************
475 * SetServiceStatus
476 *
477 * @implemented
478 */
479 BOOL STDCALL
480 SetServiceStatus(SERVICE_STATUS_HANDLE hServiceStatus,
481 LPSERVICE_STATUS lpServiceStatus)
482 {
483 PACTIVE_SERVICE Service;
484
485 Service = ScLookupServiceByThreadId((DWORD)hServiceStatus);
486 if (!Service)
487 {
488 SetLastError(ERROR_INVALID_HANDLE);
489 return FALSE;
490 }
491
492 RtlCopyMemory(&Service->ServiceStatus,
493 lpServiceStatus,
494 sizeof(SERVICE_STATUS));
495
496 return TRUE;
497 }
498
499
500 /**********************************************************************
501 * StartServiceCtrlDispatcherA
502 *
503 * @unimplemented
504 */
505 BOOL STDCALL
506 StartServiceCtrlDispatcherA(LPSERVICE_TABLE_ENTRYA lpServiceStartTable)
507 {
508 ULONG i;
509 HANDLE hPipe;
510 DWORD dwError;
511 PUCHAR lpMessageBuffer;
512
513 DPRINT("StartServiceCtrlDispatcherA() called\n");
514
515 i = 0;
516 while (lpServiceStartTable[i].lpServiceProc != NULL)
517 {
518 i++;
519 }
520
521 dwActiveServiceCount = i;
522 lpActiveServices = RtlAllocateHeap(RtlGetProcessHeap(),
523 HEAP_ZERO_MEMORY,
524 dwActiveServiceCount * sizeof(ACTIVE_SERVICE));
525 if (lpActiveServices == NULL)
526 {
527 return FALSE;
528 }
529
530 /* Copy service names and start procedure */
531 for (i = 0; i < dwActiveServiceCount; i++)
532 {
533 RtlCreateUnicodeStringFromAsciiz(&lpActiveServices[i].ServiceName,
534 lpServiceStartTable[i].lpServiceName);
535 lpActiveServices[i].Main.lpFuncA = lpServiceStartTable[i].lpServiceProc;
536 lpActiveServices[i].bUnicode = FALSE;
537 }
538
539 dwError = ScConnectControlPipe(&hPipe);
540 if (dwError != ERROR_SUCCESS)
541 {
542 /* Free the service table */
543 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
544 lpActiveServices = NULL;
545 dwActiveServiceCount = 0;
546 return FALSE;
547 }
548
549 lpMessageBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
550 HEAP_ZERO_MEMORY,
551 256);
552 if (lpMessageBuffer == NULL)
553 {
554 /* Free the service table */
555 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
556 lpActiveServices = NULL;
557 dwActiveServiceCount = 0;
558 CloseHandle(hPipe);
559 return FALSE;
560 }
561
562 ScServiceDispatcher(hPipe, lpMessageBuffer, 256);
563 CloseHandle(hPipe);
564
565 /* Free the message buffer */
566 RtlFreeHeap(RtlGetProcessHeap(), 0, lpMessageBuffer);
567
568 /* Free the service table */
569 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
570 lpActiveServices = NULL;
571 dwActiveServiceCount = 0;
572
573 return TRUE;
574 }
575
576
577 /**********************************************************************
578 * StartServiceCtrlDispatcherW
579 *
580 * @unimplemented
581 */
582 BOOL STDCALL
583 StartServiceCtrlDispatcherW(LPSERVICE_TABLE_ENTRYW lpServiceStartTable)
584 {
585 ULONG i;
586 HANDLE hPipe;
587 DWORD dwError;
588 PUCHAR lpMessageBuffer;
589
590 DPRINT("StartServiceCtrlDispatcherW() called\n");
591
592 i = 0;
593 while (lpServiceStartTable[i].lpServiceProc != NULL)
594 {
595 i++;
596 }
597
598 dwActiveServiceCount = i;
599 lpActiveServices = RtlAllocateHeap(RtlGetProcessHeap(),
600 HEAP_ZERO_MEMORY,
601 dwActiveServiceCount * sizeof(ACTIVE_SERVICE));
602 if (lpActiveServices == NULL)
603 {
604 return FALSE;
605 }
606
607 /* Copy service names and start procedure */
608 for (i = 0; i < dwActiveServiceCount; i++)
609 {
610 RtlCreateUnicodeString(&lpActiveServices[i].ServiceName,
611 lpServiceStartTable[i].lpServiceName);
612 lpActiveServices[i].Main.lpFuncW = lpServiceStartTable[i].lpServiceProc;
613 lpActiveServices[i].bUnicode = TRUE;
614 }
615
616 dwError = ScConnectControlPipe(&hPipe);
617 if (dwError != ERROR_SUCCESS)
618 {
619 /* Free the service table */
620 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
621 lpActiveServices = NULL;
622 dwActiveServiceCount = 0;
623 return FALSE;
624 }
625
626 lpMessageBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
627 HEAP_ZERO_MEMORY,
628 256);
629 if (lpMessageBuffer == NULL)
630 {
631 /* Free the service table */
632 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
633 lpActiveServices = NULL;
634 dwActiveServiceCount = 0;
635 CloseHandle(hPipe);
636 return FALSE;
637 }
638
639 ScServiceDispatcher(hPipe, lpMessageBuffer, 256);
640 CloseHandle(hPipe);
641
642 /* Free the message buffer */
643 RtlFreeHeap(RtlGetProcessHeap(), 0, lpMessageBuffer);
644
645 /* Free the service table */
646 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
647 lpActiveServices = NULL;
648 dwActiveServiceCount = 0;
649
650 return TRUE;
651 }
652
653 /* EOF */