[SERVICES][ADVAPI32] Fix the broken service stop sequence
[reactos.git] / dll / win32 / advapi32 / service / sctrl.c
1 /*
2 * PROJECT: ReactOS advapi32
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: dll/win32/advapi32/service/sctrl.c
5 * PURPOSE: Service control manager functions
6 * COPYRIGHT: Copyright 1999 Emanuele Aliberti
7 * Copyright 2007 Ged Murphy <gedmurphy@reactos.org>
8 * Gregor Brunmar <gregor.brunmar@home.se>
9 */
10
11
12 /* INCLUDES ******************************************************************/
13
14 #include <advapi32.h>
15 WINE_DEFAULT_DEBUG_CHANNEL(advapi);
16
17
18 /* TYPES *********************************************************************/
19
20 typedef struct _SERVICE_THREAD_PARAMSA
21 {
22 LPSERVICE_MAIN_FUNCTIONA lpServiceMain;
23 DWORD dwArgCount;
24 LPSTR *lpArgVector;
25 } SERVICE_THREAD_PARAMSA, *PSERVICE_THREAD_PARAMSA;
26
27
28 typedef struct _SERVICE_THREAD_PARAMSW
29 {
30 LPSERVICE_MAIN_FUNCTIONW lpServiceMain;
31 DWORD dwArgCount;
32 LPWSTR *lpArgVector;
33 } SERVICE_THREAD_PARAMSW, *PSERVICE_THREAD_PARAMSW;
34
35
36 typedef struct _ACTIVE_SERVICE
37 {
38 SERVICE_STATUS_HANDLE hServiceStatus;
39 UNICODE_STRING ServiceName;
40 union
41 {
42 LPSERVICE_MAIN_FUNCTIONA A;
43 LPSERVICE_MAIN_FUNCTIONW W;
44 } ServiceMain;
45 LPHANDLER_FUNCTION HandlerFunction;
46 LPHANDLER_FUNCTION_EX HandlerFunctionEx;
47 LPVOID HandlerContext;
48 BOOL bUnicode;
49 BOOL bOwnProcess;
50 } ACTIVE_SERVICE, *PACTIVE_SERVICE;
51
52
53 /* GLOBALS *******************************************************************/
54
55 static DWORD dwActiveServiceCount = 0;
56 static PACTIVE_SERVICE lpActiveServices = NULL;
57 static handle_t hStatusBinding = NULL;
58
59
60 /* FUNCTIONS *****************************************************************/
61
62 handle_t __RPC_USER
63 RPC_SERVICE_STATUS_HANDLE_bind(RPC_SERVICE_STATUS_HANDLE hServiceStatus)
64 {
65 return hStatusBinding;
66 }
67
68
69 void __RPC_USER
70 RPC_SERVICE_STATUS_HANDLE_unbind(RPC_SERVICE_STATUS_HANDLE hServiceStatus,
71 handle_t hBinding)
72 {
73 }
74
75
76 static RPC_STATUS
77 ScCreateStatusBinding(VOID)
78 {
79 LPWSTR pszStringBinding;
80 RPC_STATUS status;
81
82 TRACE("ScCreateStatusBinding() called\n");
83
84 status = RpcStringBindingComposeW(NULL,
85 L"ncacn_np",
86 NULL,
87 L"\\pipe\\ntsvcs",
88 NULL,
89 &pszStringBinding);
90 if (status != RPC_S_OK)
91 {
92 ERR("RpcStringBindingCompose returned 0x%x\n", status);
93 return status;
94 }
95
96 /* Set the binding handle that will be used to bind to the server. */
97 status = RpcBindingFromStringBindingW(pszStringBinding,
98 &hStatusBinding);
99 if (status != RPC_S_OK)
100 {
101 ERR("RpcBindingFromStringBinding returned 0x%x\n", status);
102 }
103
104 status = RpcStringFreeW(&pszStringBinding);
105 if (status != RPC_S_OK)
106 {
107 ERR("RpcStringFree returned 0x%x\n", status);
108 }
109
110 return status;
111 }
112
113
114 static RPC_STATUS
115 ScDestroyStatusBinding(VOID)
116 {
117 RPC_STATUS status;
118
119 TRACE("ScDestroyStatusBinding() called\n");
120
121 if (hStatusBinding == NULL)
122 return RPC_S_OK;
123
124 status = RpcBindingFree(&hStatusBinding);
125 if (status != RPC_S_OK)
126 {
127 ERR("RpcBindingFree returned 0x%x\n", status);
128 }
129 else
130 {
131 hStatusBinding = NULL;
132 }
133
134 return status;
135 }
136
137
138 static PACTIVE_SERVICE
139 ScLookupServiceByServiceName(LPCWSTR lpServiceName)
140 {
141 DWORD i;
142
143 TRACE("ScLookupServiceByServiceName(%S) called\n", lpServiceName);
144
145 if (lpActiveServices[0].bOwnProcess)
146 return &lpActiveServices[0];
147
148 for (i = 0; i < dwActiveServiceCount; i++)
149 {
150 TRACE("Checking %S\n", lpActiveServices[i].ServiceName.Buffer);
151 if (_wcsicmp(lpActiveServices[i].ServiceName.Buffer, lpServiceName) == 0)
152 {
153 TRACE("Found!\n");
154 return &lpActiveServices[i];
155 }
156 }
157
158 TRACE("No service found!\n");
159
160 SetLastError(ERROR_SERVICE_DOES_NOT_EXIST);
161
162 return NULL;
163 }
164
165
166 static DWORD WINAPI
167 ScServiceMainStubA(LPVOID Context)
168 {
169 PSERVICE_THREAD_PARAMSA ThreadParams = Context;
170
171 TRACE("ScServiceMainStubA() called\n");
172
173 /* Call the main service routine and free the arguments vector */
174 (ThreadParams->lpServiceMain)(ThreadParams->dwArgCount,
175 ThreadParams->lpArgVector);
176
177 if (ThreadParams->lpArgVector != NULL)
178 {
179 HeapFree(GetProcessHeap(), 0, ThreadParams->lpArgVector);
180 }
181 HeapFree(GetProcessHeap(), 0, ThreadParams);
182
183 return ERROR_SUCCESS;
184 }
185
186
187 static DWORD WINAPI
188 ScServiceMainStubW(LPVOID Context)
189 {
190 PSERVICE_THREAD_PARAMSW ThreadParams = Context;
191
192 TRACE("ScServiceMainStubW() called\n");
193
194 /* Call the main service routine and free the arguments vector */
195 (ThreadParams->lpServiceMain)(ThreadParams->dwArgCount,
196 ThreadParams->lpArgVector);
197
198 if (ThreadParams->lpArgVector != NULL)
199 {
200 HeapFree(GetProcessHeap(), 0, ThreadParams->lpArgVector);
201 }
202 HeapFree(GetProcessHeap(), 0, ThreadParams);
203
204 return ERROR_SUCCESS;
205 }
206
207
208 static DWORD
209 ScConnectControlPipe(HANDLE *hPipe)
210 {
211 DWORD dwBytesWritten;
212 DWORD dwState;
213 DWORD dwServiceCurrent = 0;
214 NTSTATUS Status;
215 WCHAR NtControlPipeName[MAX_PATH + 1];
216 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
217 DWORD dwProcessId;
218
219 /* Get the service number and create the named pipe */
220 RtlZeroMemory(&QueryTable,
221 sizeof(QueryTable));
222
223 QueryTable[0].Name = L"";
224 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
225 QueryTable[0].EntryContext = &dwServiceCurrent;
226
227 Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL,
228 L"ServiceCurrent",
229 QueryTable,
230 NULL,
231 NULL);
232
233 if (!NT_SUCCESS(Status))
234 {
235 ERR("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
236 return RtlNtStatusToDosError(Status);
237 }
238
239 swprintf(NtControlPipeName, L"\\\\.\\pipe\\net\\NtControlPipe%u", dwServiceCurrent);
240
241 if (!WaitNamedPipeW(NtControlPipeName, 30000))
242 {
243 ERR("WaitNamedPipe(%S) failed (Error %lu)\n", NtControlPipeName, GetLastError());
244 return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT;
245 }
246
247 *hPipe = CreateFileW(NtControlPipeName,
248 GENERIC_READ | GENERIC_WRITE,
249 FILE_SHARE_READ | FILE_SHARE_WRITE,
250 NULL,
251 OPEN_EXISTING,
252 FILE_ATTRIBUTE_NORMAL,
253 NULL);
254 if (*hPipe == INVALID_HANDLE_VALUE)
255 {
256 ERR("CreateFileW() failed for pipe %S (Error %lu)\n", NtControlPipeName, GetLastError());
257 return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT;
258 }
259
260 dwState = PIPE_READMODE_MESSAGE;
261 if (!SetNamedPipeHandleState(*hPipe, &dwState, NULL, NULL))
262 {
263 CloseHandle(*hPipe);
264 *hPipe = INVALID_HANDLE_VALUE;
265 return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT;
266 }
267
268 /* Pass the ProcessId to the SCM */
269 dwProcessId = GetCurrentProcessId();
270 WriteFile(*hPipe,
271 &dwProcessId,
272 sizeof(DWORD),
273 &dwBytesWritten,
274 NULL);
275
276 TRACE("Sent Process ID %lu\n", dwProcessId);
277
278 return ERROR_SUCCESS;
279 }
280
281
282 /*
283 * Ansi/Unicode argument layout of the vector passed to a service at startup,
284 * depending on the different versions of Windows considered:
285 *
286 * - XP/2003:
287 * [argv array of pointers][parameter 1][parameter 2]...[service name]
288 *
289 * - Vista:
290 * [argv array of pointers][align to 8 bytes]
291 * [parameter 1][parameter 2]...[service name]
292 *
293 * - Win7/8:
294 * [argv array of pointers][service name]
295 * [parameter 1][align to 4 bytes][parameter 2][align to 4 bytes]...
296 *
297 * Space for parameters and service name is always enough to store
298 * both the Ansi and the Unicode versions including NULL terminator.
299 */
300
301 static DWORD
302 ScBuildUnicodeArgsVector(PSCM_CONTROL_PACKET ControlPacket,
303 LPDWORD lpArgCount,
304 LPWSTR **lpArgVector)
305 {
306 PWSTR *lpVector;
307 PWSTR pszServiceName;
308 DWORD cbServiceName;
309 DWORD cbArguments;
310 DWORD cbTotal;
311 DWORD i;
312
313 if (ControlPacket == NULL || lpArgCount == NULL || lpArgVector == NULL)
314 return ERROR_INVALID_PARAMETER;
315
316 *lpArgCount = 0;
317 *lpArgVector = NULL;
318
319 /* Retrieve and count the start command line (NULL-terminated) */
320 pszServiceName = (PWSTR)((ULONG_PTR)ControlPacket + ControlPacket->dwServiceNameOffset);
321 cbServiceName = lstrlenW(pszServiceName) * sizeof(WCHAR) + sizeof(UNICODE_NULL);
322
323 /*
324 * The total size of the argument vector is equal to the entry for
325 * the service name, plus the size of the original argument vector.
326 */
327 cbTotal = sizeof(PWSTR) + cbServiceName;
328 if (ControlPacket->dwArgumentsCount > 0)
329 cbArguments = ControlPacket->dwSize - ControlPacket->dwArgumentsOffset;
330 else
331 cbArguments = 0;
332 cbTotal += cbArguments;
333
334 /* Allocate the new argument vector */
335 lpVector = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbTotal);
336 if (lpVector == NULL)
337 return ERROR_NOT_ENOUGH_MEMORY;
338
339 /*
340 * The first argument is reserved for the service name, which
341 * will be appended to the end of the argument string list.
342 */
343
344 /* Copy the remaining arguments */
345 if (ControlPacket->dwArgumentsCount > 0)
346 {
347 memcpy(&lpVector[1],
348 (PWSTR)((ULONG_PTR)ControlPacket + ControlPacket->dwArgumentsOffset),
349 cbArguments);
350
351 for (i = 0; i < ControlPacket->dwArgumentsCount; i++)
352 {
353 lpVector[i + 1] = (PWSTR)((ULONG_PTR)&lpVector[1] + (ULONG_PTR)lpVector[i + 1]);
354 TRACE("Unicode lpVector[%lu] = '%ls'\n", i + 1, lpVector[i + 1]);
355 }
356 }
357
358 /* Now copy the service name */
359 lpVector[0] = (PWSTR)((ULONG_PTR)&lpVector[1] + cbArguments);
360 memcpy(lpVector[0], pszServiceName, cbServiceName);
361 TRACE("Unicode lpVector[%lu] = '%ls'\n", 0, lpVector[0]);
362
363 *lpArgCount = ControlPacket->dwArgumentsCount + 1;
364 *lpArgVector = lpVector;
365
366 return ERROR_SUCCESS;
367 }
368
369
370 static DWORD
371 ScBuildAnsiArgsVector(PSCM_CONTROL_PACKET ControlPacket,
372 LPDWORD lpArgCount,
373 LPSTR **lpArgVector)
374 {
375 DWORD dwError;
376 NTSTATUS Status;
377 DWORD ArgCount, i;
378 PWSTR *lpVectorW;
379 PSTR *lpVectorA;
380 UNICODE_STRING UnicodeString;
381 ANSI_STRING AnsiString;
382
383 if (ControlPacket == NULL || lpArgCount == NULL || lpArgVector == NULL)
384 return ERROR_INVALID_PARAMETER;
385
386 *lpArgCount = 0;
387 *lpArgVector = NULL;
388
389 /* Build the UNICODE arguments vector */
390 dwError = ScBuildUnicodeArgsVector(ControlPacket, &ArgCount, &lpVectorW);
391 if (dwError != ERROR_SUCCESS)
392 return dwError;
393
394 /* Convert the vector to ANSI in place */
395 lpVectorA = (PSTR*)lpVectorW;
396 for (i = 0; i < ArgCount; i++)
397 {
398 RtlInitUnicodeString(&UnicodeString, lpVectorW[i]);
399 RtlInitEmptyAnsiString(&AnsiString, lpVectorA[i], UnicodeString.MaximumLength);
400 Status = RtlUnicodeStringToAnsiString(&AnsiString, &UnicodeString, FALSE);
401 if (!NT_SUCCESS(Status))
402 {
403 /* Failed to convert to ANSI; free the allocated vector and return */
404 dwError = RtlNtStatusToDosError(Status);
405 HeapFree(GetProcessHeap(), 0, lpVectorW);
406 return dwError;
407 }
408
409 /* NULL-terminate the string */
410 AnsiString.Buffer[AnsiString.Length / sizeof(CHAR)] = ANSI_NULL;
411
412 TRACE("Ansi lpVector[%lu] = '%s'\n", i, lpVectorA[i]);
413 }
414
415 *lpArgCount = ArgCount;
416 *lpArgVector = lpVectorA;
417
418 return ERROR_SUCCESS;
419 }
420
421
422 static DWORD
423 ScStartService(PACTIVE_SERVICE lpService,
424 PSCM_CONTROL_PACKET ControlPacket)
425 {
426 HANDLE ThreadHandle;
427 DWORD ThreadId;
428 DWORD dwError;
429 PSERVICE_THREAD_PARAMSA ThreadParamsA;
430 PSERVICE_THREAD_PARAMSW ThreadParamsW;
431
432 if (lpService == NULL || ControlPacket == NULL)
433 return ERROR_INVALID_PARAMETER;
434
435 TRACE("ScStartService() called\n");
436 TRACE("Size: %lu\n", ControlPacket->dwSize);
437 TRACE("Service: %S\n", (PWSTR)((PBYTE)ControlPacket + ControlPacket->dwServiceNameOffset));
438
439 /* Set the service status handle */
440 lpService->hServiceStatus = ControlPacket->hServiceStatus;
441
442 /* Build the arguments vector */
443 if (lpService->bUnicode != FALSE)
444 {
445 ThreadParamsW = HeapAlloc(GetProcessHeap(), 0, sizeof(*ThreadParamsW));
446 if (ThreadParamsW == NULL)
447 return ERROR_NOT_ENOUGH_MEMORY;
448 dwError = ScBuildUnicodeArgsVector(ControlPacket,
449 &ThreadParamsW->dwArgCount,
450 &ThreadParamsW->lpArgVector);
451 if (dwError != ERROR_SUCCESS)
452 {
453 HeapFree(GetProcessHeap(), 0, ThreadParamsW);
454 return dwError;
455 }
456 ThreadParamsW->lpServiceMain = lpService->ServiceMain.W;
457 ThreadHandle = CreateThread(NULL,
458 0,
459 ScServiceMainStubW,
460 ThreadParamsW,
461 CREATE_SUSPENDED,
462 &ThreadId);
463 if (ThreadHandle == NULL)
464 {
465 if (ThreadParamsW->lpArgVector != NULL)
466 {
467 HeapFree(GetProcessHeap(),
468 0,
469 ThreadParamsW->lpArgVector);
470 }
471 HeapFree(GetProcessHeap(), 0, ThreadParamsW);
472 }
473 }
474 else
475 {
476 ThreadParamsA = HeapAlloc(GetProcessHeap(), 0, sizeof(*ThreadParamsA));
477 if (ThreadParamsA == NULL)
478 return ERROR_NOT_ENOUGH_MEMORY;
479 dwError = ScBuildAnsiArgsVector(ControlPacket,
480 &ThreadParamsA->dwArgCount,
481 &ThreadParamsA->lpArgVector);
482 if (dwError != ERROR_SUCCESS)
483 {
484 HeapFree(GetProcessHeap(), 0, ThreadParamsA);
485 return dwError;
486 }
487 ThreadParamsA->lpServiceMain = lpService->ServiceMain.A;
488 ThreadHandle = CreateThread(NULL,
489 0,
490 ScServiceMainStubA,
491 ThreadParamsA,
492 CREATE_SUSPENDED,
493 &ThreadId);
494 if (ThreadHandle == NULL)
495 {
496 if (ThreadParamsA->lpArgVector != NULL)
497 {
498 HeapFree(GetProcessHeap(),
499 0,
500 ThreadParamsA->lpArgVector);
501 }
502 HeapFree(GetProcessHeap(), 0, ThreadParamsA);
503 }
504 }
505
506 ResumeThread(ThreadHandle);
507 CloseHandle(ThreadHandle);
508
509 return ERROR_SUCCESS;
510 }
511
512
513 static DWORD
514 ScControlService(PACTIVE_SERVICE lpService,
515 PSCM_CONTROL_PACKET ControlPacket)
516 {
517 if (lpService == NULL || ControlPacket == NULL)
518 return ERROR_INVALID_PARAMETER;
519
520 TRACE("ScControlService() called\n");
521 TRACE("Size: %lu\n", ControlPacket->dwSize);
522 TRACE("Service: %S\n", (PWSTR)((PBYTE)ControlPacket + ControlPacket->dwServiceNameOffset));
523
524 if (lpService->HandlerFunction)
525 {
526 (lpService->HandlerFunction)(ControlPacket->dwControl);
527 }
528 else if (lpService->HandlerFunctionEx)
529 {
530 /* FIXME: send correct params */
531 (lpService->HandlerFunctionEx)(ControlPacket->dwControl, 0, NULL, NULL);
532 }
533
534 TRACE("ScControlService() done\n");
535
536 return ERROR_SUCCESS;
537 }
538
539
540 static BOOL
541 ScServiceDispatcher(HANDLE hPipe,
542 PSCM_CONTROL_PACKET ControlPacket,
543 DWORD dwBufferSize)
544 {
545 DWORD Count;
546 BOOL bResult;
547 BOOL bRunning = TRUE;
548 LPWSTR lpServiceName;
549 PACTIVE_SERVICE lpService;
550 SCM_REPLY_PACKET ReplyPacket;
551 DWORD dwError;
552
553 TRACE("ScDispatcherLoop() called\n");
554
555 if (ControlPacket == NULL || dwBufferSize < sizeof(SCM_CONTROL_PACKET))
556 return FALSE;
557
558 while (bRunning)
559 {
560 /* Read command from the control pipe */
561 bResult = ReadFile(hPipe,
562 ControlPacket,
563 dwBufferSize,
564 &Count,
565 NULL);
566 if (bResult == FALSE)
567 {
568 ERR("Pipe read failed (Error: %lu)\n", GetLastError());
569 return FALSE;
570 }
571
572 lpServiceName = (LPWSTR)((PBYTE)ControlPacket + ControlPacket->dwServiceNameOffset);
573 TRACE("Service: %S\n", lpServiceName);
574
575 if (lpServiceName[0] == UNICODE_NULL)
576 {
577 ERR("Stop dispatcher thread\n");
578 bRunning = FALSE;
579 dwError = ERROR_SUCCESS;
580 }
581 else
582 {
583 if (ControlPacket->dwControl == SERVICE_CONTROL_START_OWN)
584 lpActiveServices[0].bOwnProcess = TRUE;
585
586 lpService = ScLookupServiceByServiceName(lpServiceName);
587 if (lpService != NULL)
588 {
589 /* Execute command */
590 switch (ControlPacket->dwControl)
591 {
592 case SERVICE_CONTROL_START_SHARE:
593 case SERVICE_CONTROL_START_OWN:
594 TRACE("Start command - received SERVICE_CONTROL_START\n");
595 dwError = ScStartService(lpService, ControlPacket);
596 break;
597
598 case SERVICE_CONTROL_STOP:
599 TRACE("Stop command - received SERVICE_CONTROL_STOP\n");
600 dwError = ScControlService(lpService, ControlPacket);
601 break;
602
603 default:
604 TRACE("Command %lu received", ControlPacket->dwControl);
605 dwError = ScControlService(lpService, ControlPacket);
606 break;
607 }
608 }
609 else
610 {
611 dwError = ERROR_SERVICE_DOES_NOT_EXIST;
612 }
613 }
614
615 ReplyPacket.dwError = dwError;
616
617 /* Send the reply packet */
618 bResult = WriteFile(hPipe,
619 &ReplyPacket,
620 sizeof(ReplyPacket),
621 &Count,
622 NULL);
623 if (bResult == FALSE)
624 {
625 ERR("Pipe write failed (Error: %lu)\n", GetLastError());
626 return FALSE;
627 }
628 }
629
630 return TRUE;
631 }
632
633
634 /**********************************************************************
635 * RegisterServiceCtrlHandlerA
636 *
637 * @implemented
638 */
639 SERVICE_STATUS_HANDLE WINAPI
640 RegisterServiceCtrlHandlerA(LPCSTR lpServiceName,
641 LPHANDLER_FUNCTION lpHandlerProc)
642 {
643 ANSI_STRING ServiceNameA;
644 UNICODE_STRING ServiceNameU;
645 SERVICE_STATUS_HANDLE SHandle;
646
647 RtlInitAnsiString(&ServiceNameA, (LPSTR)lpServiceName);
648 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ServiceNameU, &ServiceNameA, TRUE)))
649 {
650 SetLastError(ERROR_OUTOFMEMORY);
651 return (SERVICE_STATUS_HANDLE)0;
652 }
653
654 SHandle = RegisterServiceCtrlHandlerW(ServiceNameU.Buffer,
655 lpHandlerProc);
656
657 RtlFreeUnicodeString(&ServiceNameU);
658
659 return SHandle;
660 }
661
662
663 /**********************************************************************
664 * RegisterServiceCtrlHandlerW
665 *
666 * @implemented
667 */
668 SERVICE_STATUS_HANDLE WINAPI
669 RegisterServiceCtrlHandlerW(LPCWSTR lpServiceName,
670 LPHANDLER_FUNCTION lpHandlerProc)
671 {
672 PACTIVE_SERVICE Service;
673
674 Service = ScLookupServiceByServiceName((LPWSTR)lpServiceName);
675 if (Service == NULL)
676 {
677 return (SERVICE_STATUS_HANDLE)NULL;
678 }
679
680 Service->HandlerFunction = lpHandlerProc;
681 Service->HandlerFunctionEx = NULL;
682
683 TRACE("RegisterServiceCtrlHandler returning %lu\n", Service->hServiceStatus);
684
685 return Service->hServiceStatus;
686 }
687
688
689 /**********************************************************************
690 * RegisterServiceCtrlHandlerExA
691 *
692 * @implemented
693 */
694 SERVICE_STATUS_HANDLE WINAPI
695 RegisterServiceCtrlHandlerExA(LPCSTR lpServiceName,
696 LPHANDLER_FUNCTION_EX lpHandlerProc,
697 LPVOID lpContext)
698 {
699 ANSI_STRING ServiceNameA;
700 UNICODE_STRING ServiceNameU;
701 SERVICE_STATUS_HANDLE SHandle;
702
703 RtlInitAnsiString(&ServiceNameA, (LPSTR)lpServiceName);
704 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ServiceNameU, &ServiceNameA, TRUE)))
705 {
706 SetLastError(ERROR_OUTOFMEMORY);
707 return (SERVICE_STATUS_HANDLE)0;
708 }
709
710 SHandle = RegisterServiceCtrlHandlerExW(ServiceNameU.Buffer,
711 lpHandlerProc,
712 lpContext);
713
714 RtlFreeUnicodeString(&ServiceNameU);
715
716 return SHandle;
717 }
718
719
720 /**********************************************************************
721 * RegisterServiceCtrlHandlerExW
722 *
723 * @implemented
724 */
725 SERVICE_STATUS_HANDLE WINAPI
726 RegisterServiceCtrlHandlerExW(LPCWSTR lpServiceName,
727 LPHANDLER_FUNCTION_EX lpHandlerProc,
728 LPVOID lpContext)
729 {
730 PACTIVE_SERVICE Service;
731
732 Service = ScLookupServiceByServiceName(lpServiceName);
733 if (Service == NULL)
734 {
735 return (SERVICE_STATUS_HANDLE)NULL;
736 }
737
738 Service->HandlerFunction = NULL;
739 Service->HandlerFunctionEx = lpHandlerProc;
740 Service->HandlerContext = lpContext;
741
742 TRACE("RegisterServiceCtrlHandlerEx returning %lu\n", Service->hServiceStatus);
743
744 return Service->hServiceStatus;
745 }
746
747
748 /**********************************************************************
749 * I_ScIsSecurityProcess
750 *
751 * Undocumented
752 *
753 * @unimplemented
754 */
755 VOID
756 WINAPI
757 I_ScIsSecurityProcess(VOID)
758 {
759 }
760
761
762 /**********************************************************************
763 * I_ScPnPGetServiceName
764 *
765 * Undocumented
766 *
767 * @implemented
768 */
769 DWORD
770 WINAPI
771 I_ScPnPGetServiceName(IN SERVICE_STATUS_HANDLE hServiceStatus,
772 OUT LPWSTR lpServiceName,
773 IN DWORD cchServiceName)
774 {
775 DWORD i;
776
777 for (i = 0; i < dwActiveServiceCount; i++)
778 {
779 if (lpActiveServices[i].hServiceStatus == hServiceStatus)
780 {
781 wcscpy(lpServiceName, lpActiveServices[i].ServiceName.Buffer);
782 return ERROR_SUCCESS;
783 }
784 }
785
786 return ERROR_SERVICE_NOT_IN_EXE;
787 }
788
789
790 /**********************************************************************
791 * I_ScSetServiceBitsA
792 *
793 * Undocumented
794 *
795 * @implemented
796 */
797 BOOL WINAPI
798 I_ScSetServiceBitsA(SERVICE_STATUS_HANDLE hServiceStatus,
799 DWORD dwServiceBits,
800 BOOL bSetBitsOn,
801 BOOL bUpdateImmediately,
802 LPSTR lpString)
803 {
804 BOOL bResult;
805
806 RpcTryExcept
807 {
808 /* Call to services.exe using RPC */
809 bResult = RI_ScSetServiceBitsA((RPC_SERVICE_STATUS_HANDLE)hServiceStatus,
810 dwServiceBits,
811 bSetBitsOn,
812 bUpdateImmediately,
813 lpString);
814 }
815 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
816 {
817 SetLastError(ScmRpcStatusToWinError(RpcExceptionCode()));
818 bResult = FALSE;
819 }
820 RpcEndExcept;
821
822 return bResult;
823 }
824
825
826 /**********************************************************************
827 * I_ScSetServiceBitsW
828 *
829 * Undocumented
830 *
831 * @implemented
832 */
833 BOOL WINAPI
834 I_ScSetServiceBitsW(SERVICE_STATUS_HANDLE hServiceStatus,
835 DWORD dwServiceBits,
836 BOOL bSetBitsOn,
837 BOOL bUpdateImmediately,
838 LPWSTR lpString)
839 {
840 BOOL bResult;
841
842 RpcTryExcept
843 {
844 /* Call to services.exe using RPC */
845 bResult = RI_ScSetServiceBitsW((RPC_SERVICE_STATUS_HANDLE)hServiceStatus,
846 dwServiceBits,
847 bSetBitsOn,
848 bUpdateImmediately,
849 lpString);
850 }
851 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
852 {
853 SetLastError(ScmRpcStatusToWinError(RpcExceptionCode()));
854 bResult = FALSE;
855 }
856 RpcEndExcept;
857
858 return bResult;
859 }
860
861
862 /**********************************************************************
863 * SetServiceBits
864 *
865 * @implemented
866 */
867 BOOL WINAPI
868 SetServiceBits(SERVICE_STATUS_HANDLE hServiceStatus,
869 DWORD dwServiceBits,
870 BOOL bSetBitsOn,
871 BOOL bUpdateImmediately)
872 {
873 return I_ScSetServiceBitsW(hServiceStatus,
874 dwServiceBits,
875 bSetBitsOn,
876 bUpdateImmediately,
877 NULL);
878 }
879
880
881 /**********************************************************************
882 * SetServiceStatus
883 *
884 * @implemented
885 */
886 BOOL WINAPI
887 SetServiceStatus(SERVICE_STATUS_HANDLE hServiceStatus,
888 LPSERVICE_STATUS lpServiceStatus)
889 {
890 DWORD dwError;
891
892 TRACE("SetServiceStatus() called\n");
893 TRACE("hServiceStatus %lu\n", hServiceStatus);
894
895 RpcTryExcept
896 {
897 /* Call to services.exe using RPC */
898 dwError = RSetServiceStatus((RPC_SERVICE_STATUS_HANDLE)hServiceStatus,
899 lpServiceStatus);
900 }
901 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
902 {
903 dwError = ScmRpcStatusToWinError(RpcExceptionCode());
904 }
905 RpcEndExcept;
906
907 if (dwError != ERROR_SUCCESS)
908 {
909 ERR("ScmrSetServiceStatus() failed (Error %lu)\n", dwError);
910 SetLastError(dwError);
911 return FALSE;
912 }
913
914 TRACE("SetServiceStatus() done (ret %lu)\n", dwError);
915
916 return TRUE;
917 }
918
919
920 /**********************************************************************
921 * StartServiceCtrlDispatcherA
922 *
923 * @implemented
924 */
925 BOOL WINAPI
926 StartServiceCtrlDispatcherA(const SERVICE_TABLE_ENTRYA *lpServiceStartTable)
927 {
928 ULONG i;
929 HANDLE hPipe;
930 DWORD dwError;
931 PSCM_CONTROL_PACKET ControlPacket;
932 DWORD dwBufSize;
933 BOOL bRet = TRUE;
934
935 TRACE("StartServiceCtrlDispatcherA() called\n");
936
937 i = 0;
938 while (lpServiceStartTable[i].lpServiceProc != NULL)
939 {
940 i++;
941 }
942
943 dwActiveServiceCount = i;
944 lpActiveServices = RtlAllocateHeap(RtlGetProcessHeap(),
945 HEAP_ZERO_MEMORY,
946 dwActiveServiceCount * sizeof(ACTIVE_SERVICE));
947 if (lpActiveServices == NULL)
948 {
949 return FALSE;
950 }
951
952 /* Copy service names and start procedure */
953 for (i = 0; i < dwActiveServiceCount; i++)
954 {
955 RtlCreateUnicodeStringFromAsciiz(&lpActiveServices[i].ServiceName,
956 lpServiceStartTable[i].lpServiceName);
957 lpActiveServices[i].ServiceMain.A = lpServiceStartTable[i].lpServiceProc;
958 lpActiveServices[i].hServiceStatus = 0;
959 lpActiveServices[i].bUnicode = FALSE;
960 lpActiveServices[i].bOwnProcess = FALSE;
961 }
962
963 dwError = ScConnectControlPipe(&hPipe);
964 if (dwError != ERROR_SUCCESS)
965 {
966 bRet = FALSE;
967 goto done;
968 }
969
970 dwBufSize = sizeof(SCM_CONTROL_PACKET) +
971 (MAX_SERVICE_NAME_LENGTH + 1) * sizeof(WCHAR);
972
973 ControlPacket = RtlAllocateHeap(RtlGetProcessHeap(),
974 HEAP_ZERO_MEMORY,
975 dwBufSize);
976 if (ControlPacket == NULL)
977 {
978 bRet = FALSE;
979 goto done;
980 }
981
982 ScCreateStatusBinding();
983
984 ScServiceDispatcher(hPipe, ControlPacket, dwBufSize);
985
986 ScDestroyStatusBinding();
987
988 CloseHandle(hPipe);
989
990 /* Free the control packet */
991 RtlFreeHeap(RtlGetProcessHeap(), 0, ControlPacket);
992
993 done:
994 /* Free the service table */
995 for (i = 0; i < dwActiveServiceCount; i++)
996 {
997 RtlFreeUnicodeString(&lpActiveServices[i].ServiceName);
998 }
999 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
1000 lpActiveServices = NULL;
1001 dwActiveServiceCount = 0;
1002
1003 return bRet;
1004 }
1005
1006
1007 /**********************************************************************
1008 * StartServiceCtrlDispatcherW
1009 *
1010 * @implemented
1011 */
1012 BOOL WINAPI
1013 StartServiceCtrlDispatcherW(const SERVICE_TABLE_ENTRYW *lpServiceStartTable)
1014 {
1015 ULONG i;
1016 HANDLE hPipe;
1017 DWORD dwError;
1018 PSCM_CONTROL_PACKET ControlPacket;
1019 DWORD dwBufSize;
1020 BOOL bRet = TRUE;
1021
1022 TRACE("StartServiceCtrlDispatcherW() called\n");
1023
1024 i = 0;
1025 while (lpServiceStartTable[i].lpServiceProc != NULL)
1026 {
1027 i++;
1028 }
1029
1030 dwActiveServiceCount = i;
1031 lpActiveServices = RtlAllocateHeap(RtlGetProcessHeap(),
1032 HEAP_ZERO_MEMORY,
1033 dwActiveServiceCount * sizeof(ACTIVE_SERVICE));
1034 if (lpActiveServices == NULL)
1035 {
1036 return FALSE;
1037 }
1038
1039 /* Copy service names and start procedure */
1040 for (i = 0; i < dwActiveServiceCount; i++)
1041 {
1042 RtlCreateUnicodeString(&lpActiveServices[i].ServiceName,
1043 lpServiceStartTable[i].lpServiceName);
1044 lpActiveServices[i].ServiceMain.W = lpServiceStartTable[i].lpServiceProc;
1045 lpActiveServices[i].hServiceStatus = 0;
1046 lpActiveServices[i].bUnicode = TRUE;
1047 lpActiveServices[i].bOwnProcess = FALSE;
1048 }
1049
1050 dwError = ScConnectControlPipe(&hPipe);
1051 if (dwError != ERROR_SUCCESS)
1052 {
1053 bRet = FALSE;
1054 goto done;
1055 }
1056
1057 dwBufSize = sizeof(SCM_CONTROL_PACKET) +
1058 (MAX_SERVICE_NAME_LENGTH + 1) * sizeof(WCHAR);
1059
1060 ControlPacket = RtlAllocateHeap(RtlGetProcessHeap(),
1061 HEAP_ZERO_MEMORY,
1062 dwBufSize);
1063 if (ControlPacket == NULL)
1064 {
1065 bRet = FALSE;
1066 goto done;
1067 }
1068
1069 ScCreateStatusBinding();
1070
1071 ScServiceDispatcher(hPipe, ControlPacket, dwBufSize);
1072
1073 ScDestroyStatusBinding();
1074
1075 CloseHandle(hPipe);
1076
1077 /* Free the control packet */
1078 RtlFreeHeap(RtlGetProcessHeap(), 0, ControlPacket);
1079
1080 done:
1081 /* Free the service table */
1082 for (i = 0; i < dwActiveServiceCount; i++)
1083 {
1084 RtlFreeUnicodeString(&lpActiveServices[i].ServiceName);
1085 }
1086 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
1087 lpActiveServices = NULL;
1088 dwActiveServiceCount = 0;
1089
1090 return bRet;
1091 }
1092
1093 /* EOF */