xref: /reactos/dll/win32/advapi32/service/sctrl.c (revision c2c66aff)
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     DWORD dwRunningServices = 0;
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 (TRUE)
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 (ControlPacket->dwControl == SERVICE_CONTROL_START_OWN)
576             lpActiveServices[0].bOwnProcess = TRUE;
577 
578         lpService = ScLookupServiceByServiceName(lpServiceName);
579         if (lpService != NULL)
580         {
581             /* Execute command */
582             switch (ControlPacket->dwControl)
583             {
584                 case SERVICE_CONTROL_START_SHARE:
585                 case SERVICE_CONTROL_START_OWN:
586                     TRACE("Start command - received SERVICE_CONTROL_START\n");
587                     dwError = ScStartService(lpService, ControlPacket);
588                     if (dwError == ERROR_SUCCESS)
589                         dwRunningServices++;
590                     break;
591 
592                 case SERVICE_CONTROL_STOP:
593                     TRACE("Stop command - received SERVICE_CONTROL_STOP\n");
594                     dwError = ScControlService(lpService, ControlPacket);
595                     if (dwError == ERROR_SUCCESS)
596                         dwRunningServices--;
597                     break;
598 
599                 default:
600                     TRACE("Command %lu received", ControlPacket->dwControl);
601                     dwError = ScControlService(lpService, ControlPacket);
602                     break;
603             }
604         }
605         else
606         {
607             dwError = ERROR_SERVICE_DOES_NOT_EXIST;
608         }
609 
610         ReplyPacket.dwError = dwError;
611 
612         /* Send the reply packet */
613         bResult = WriteFile(hPipe,
614                             &ReplyPacket,
615                             sizeof(ReplyPacket),
616                             &Count,
617                             NULL);
618         if (bResult == FALSE)
619         {
620             ERR("Pipe write failed (Error: %lu)\n", GetLastError());
621             return FALSE;
622         }
623 
624         if (dwRunningServices == 0)
625             break;
626     }
627 
628     return TRUE;
629 }
630 
631 
632 /**********************************************************************
633  *	RegisterServiceCtrlHandlerA
634  *
635  * @implemented
636  */
637 SERVICE_STATUS_HANDLE WINAPI
638 RegisterServiceCtrlHandlerA(LPCSTR lpServiceName,
639                             LPHANDLER_FUNCTION lpHandlerProc)
640 {
641     ANSI_STRING ServiceNameA;
642     UNICODE_STRING ServiceNameU;
643     SERVICE_STATUS_HANDLE SHandle;
644 
645     RtlInitAnsiString(&ServiceNameA, (LPSTR)lpServiceName);
646     if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ServiceNameU, &ServiceNameA, TRUE)))
647     {
648         SetLastError(ERROR_OUTOFMEMORY);
649         return (SERVICE_STATUS_HANDLE)0;
650     }
651 
652     SHandle = RegisterServiceCtrlHandlerW(ServiceNameU.Buffer,
653                                           lpHandlerProc);
654 
655     RtlFreeUnicodeString(&ServiceNameU);
656 
657     return SHandle;
658 }
659 
660 
661 /**********************************************************************
662  *	RegisterServiceCtrlHandlerW
663  *
664  * @implemented
665  */
666 SERVICE_STATUS_HANDLE WINAPI
667 RegisterServiceCtrlHandlerW(LPCWSTR lpServiceName,
668                             LPHANDLER_FUNCTION lpHandlerProc)
669 {
670     PACTIVE_SERVICE Service;
671 
672     Service = ScLookupServiceByServiceName((LPWSTR)lpServiceName);
673     if (Service == NULL)
674     {
675         return (SERVICE_STATUS_HANDLE)NULL;
676     }
677 
678     Service->HandlerFunction = lpHandlerProc;
679     Service->HandlerFunctionEx = NULL;
680 
681     TRACE("RegisterServiceCtrlHandler returning %lu\n", Service->hServiceStatus);
682 
683     return Service->hServiceStatus;
684 }
685 
686 
687 /**********************************************************************
688  *	RegisterServiceCtrlHandlerExA
689  *
690  * @implemented
691  */
692 SERVICE_STATUS_HANDLE WINAPI
693 RegisterServiceCtrlHandlerExA(LPCSTR lpServiceName,
694                               LPHANDLER_FUNCTION_EX lpHandlerProc,
695                               LPVOID lpContext)
696 {
697     ANSI_STRING ServiceNameA;
698     UNICODE_STRING ServiceNameU;
699     SERVICE_STATUS_HANDLE SHandle;
700 
701     RtlInitAnsiString(&ServiceNameA, (LPSTR)lpServiceName);
702     if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ServiceNameU, &ServiceNameA, TRUE)))
703     {
704         SetLastError(ERROR_OUTOFMEMORY);
705         return (SERVICE_STATUS_HANDLE)0;
706     }
707 
708     SHandle = RegisterServiceCtrlHandlerExW(ServiceNameU.Buffer,
709                                             lpHandlerProc,
710                                             lpContext);
711 
712     RtlFreeUnicodeString(&ServiceNameU);
713 
714     return SHandle;
715 }
716 
717 
718 /**********************************************************************
719  *	RegisterServiceCtrlHandlerExW
720  *
721  * @implemented
722  */
723 SERVICE_STATUS_HANDLE WINAPI
724 RegisterServiceCtrlHandlerExW(LPCWSTR lpServiceName,
725                               LPHANDLER_FUNCTION_EX lpHandlerProc,
726                               LPVOID lpContext)
727 {
728     PACTIVE_SERVICE Service;
729 
730     Service = ScLookupServiceByServiceName(lpServiceName);
731     if (Service == NULL)
732     {
733         return (SERVICE_STATUS_HANDLE)NULL;
734     }
735 
736     Service->HandlerFunction = NULL;
737     Service->HandlerFunctionEx = lpHandlerProc;
738     Service->HandlerContext = lpContext;
739 
740     TRACE("RegisterServiceCtrlHandlerEx returning %lu\n", Service->hServiceStatus);
741 
742     return Service->hServiceStatus;
743 }
744 
745 
746 /**********************************************************************
747  *	I_ScIsSecurityProcess
748  *
749  * Undocumented
750  *
751  * @unimplemented
752  */
753 VOID
754 WINAPI
755 I_ScIsSecurityProcess(VOID)
756 {
757 }
758 
759 
760 /**********************************************************************
761  *	I_ScPnPGetServiceName
762  *
763  * Undocumented
764  *
765  * @implemented
766  */
767 DWORD
768 WINAPI
769 I_ScPnPGetServiceName(IN SERVICE_STATUS_HANDLE hServiceStatus,
770                       OUT LPWSTR lpServiceName,
771                       IN DWORD cchServiceName)
772 {
773     DWORD i;
774 
775     for (i = 0; i < dwActiveServiceCount; i++)
776     {
777         if (lpActiveServices[i].hServiceStatus == hServiceStatus)
778         {
779             wcscpy(lpServiceName, lpActiveServices[i].ServiceName.Buffer);
780             return ERROR_SUCCESS;
781         }
782     }
783 
784     return ERROR_SERVICE_NOT_IN_EXE;
785 }
786 
787 
788 /**********************************************************************
789  *	I_ScSetServiceBitsA
790  *
791  * Undocumented
792  *
793  * @implemented
794  */
795 BOOL WINAPI
796 I_ScSetServiceBitsA(SERVICE_STATUS_HANDLE hServiceStatus,
797                     DWORD dwServiceBits,
798                     BOOL bSetBitsOn,
799                     BOOL bUpdateImmediately,
800                     LPSTR lpString)
801 {
802     BOOL bResult;
803 
804     RpcTryExcept
805     {
806         /* Call to services.exe using RPC */
807         bResult = RI_ScSetServiceBitsA((RPC_SERVICE_STATUS_HANDLE)hServiceStatus,
808                                        dwServiceBits,
809                                        bSetBitsOn,
810                                        bUpdateImmediately,
811                                        lpString);
812     }
813     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
814     {
815         SetLastError(ScmRpcStatusToWinError(RpcExceptionCode()));
816         bResult = FALSE;
817     }
818     RpcEndExcept;
819 
820     return bResult;
821 }
822 
823 
824 /**********************************************************************
825  *	I_ScSetServiceBitsW
826  *
827  * Undocumented
828  *
829  * @implemented
830  */
831 BOOL WINAPI
832 I_ScSetServiceBitsW(SERVICE_STATUS_HANDLE hServiceStatus,
833                     DWORD dwServiceBits,
834                     BOOL bSetBitsOn,
835                     BOOL bUpdateImmediately,
836                     LPWSTR lpString)
837 {
838     BOOL bResult;
839 
840     RpcTryExcept
841     {
842         /* Call to services.exe using RPC */
843         bResult = RI_ScSetServiceBitsW((RPC_SERVICE_STATUS_HANDLE)hServiceStatus,
844                                        dwServiceBits,
845                                        bSetBitsOn,
846                                        bUpdateImmediately,
847                                        lpString);
848     }
849     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
850     {
851         SetLastError(ScmRpcStatusToWinError(RpcExceptionCode()));
852         bResult = FALSE;
853     }
854     RpcEndExcept;
855 
856     return bResult;
857 }
858 
859 
860 /**********************************************************************
861  *	SetServiceBits
862  *
863  * @implemented
864  */
865 BOOL WINAPI
866 SetServiceBits(SERVICE_STATUS_HANDLE hServiceStatus,
867                DWORD dwServiceBits,
868                BOOL bSetBitsOn,
869                BOOL bUpdateImmediately)
870 {
871     return I_ScSetServiceBitsW(hServiceStatus,
872                                dwServiceBits,
873                                bSetBitsOn,
874                                bUpdateImmediately,
875                                NULL);
876 }
877 
878 
879 /**********************************************************************
880  *	SetServiceStatus
881  *
882  * @implemented
883  */
884 BOOL WINAPI
885 SetServiceStatus(SERVICE_STATUS_HANDLE hServiceStatus,
886                  LPSERVICE_STATUS lpServiceStatus)
887 {
888     DWORD dwError;
889 
890     TRACE("SetServiceStatus() called\n");
891     TRACE("hServiceStatus %lu\n", hServiceStatus);
892 
893     RpcTryExcept
894     {
895         /* Call to services.exe using RPC */
896         dwError = RSetServiceStatus((RPC_SERVICE_STATUS_HANDLE)hServiceStatus,
897                                     lpServiceStatus);
898     }
899     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
900     {
901         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
902     }
903     RpcEndExcept;
904 
905     if (dwError != ERROR_SUCCESS)
906     {
907         ERR("ScmrSetServiceStatus() failed (Error %lu)\n", dwError);
908         SetLastError(dwError);
909         return FALSE;
910     }
911 
912     TRACE("SetServiceStatus() done (ret %lu)\n", dwError);
913 
914     return TRUE;
915 }
916 
917 
918 /**********************************************************************
919  *	StartServiceCtrlDispatcherA
920  *
921  * @implemented
922  */
923 BOOL WINAPI
924 StartServiceCtrlDispatcherA(const SERVICE_TABLE_ENTRYA *lpServiceStartTable)
925 {
926     ULONG i;
927     HANDLE hPipe;
928     DWORD dwError;
929     PSCM_CONTROL_PACKET ControlPacket;
930     DWORD dwBufSize;
931     BOOL bRet = TRUE;
932 
933     TRACE("StartServiceCtrlDispatcherA() called\n");
934 
935     i = 0;
936     while (lpServiceStartTable[i].lpServiceProc != NULL)
937     {
938         i++;
939     }
940 
941     dwActiveServiceCount = i;
942     lpActiveServices = RtlAllocateHeap(RtlGetProcessHeap(),
943                                        HEAP_ZERO_MEMORY,
944                                        dwActiveServiceCount * sizeof(ACTIVE_SERVICE));
945     if (lpActiveServices == NULL)
946     {
947         return FALSE;
948     }
949 
950     /* Copy service names and start procedure */
951     for (i = 0; i < dwActiveServiceCount; i++)
952     {
953         RtlCreateUnicodeStringFromAsciiz(&lpActiveServices[i].ServiceName,
954                                          lpServiceStartTable[i].lpServiceName);
955         lpActiveServices[i].ServiceMain.A = lpServiceStartTable[i].lpServiceProc;
956         lpActiveServices[i].hServiceStatus = 0;
957         lpActiveServices[i].bUnicode = FALSE;
958         lpActiveServices[i].bOwnProcess = FALSE;
959     }
960 
961     dwError = ScConnectControlPipe(&hPipe);
962     if (dwError != ERROR_SUCCESS)
963     {
964         bRet = FALSE;
965         goto done;
966     }
967 
968     dwBufSize = sizeof(SCM_CONTROL_PACKET) +
969                 (MAX_SERVICE_NAME_LENGTH + 1) * sizeof(WCHAR);
970 
971     ControlPacket = RtlAllocateHeap(RtlGetProcessHeap(),
972                                     HEAP_ZERO_MEMORY,
973                                     dwBufSize);
974     if (ControlPacket == NULL)
975     {
976         bRet = FALSE;
977         goto done;
978     }
979 
980     ScCreateStatusBinding();
981 
982     ScServiceDispatcher(hPipe, ControlPacket, dwBufSize);
983 
984     ScDestroyStatusBinding();
985 
986     CloseHandle(hPipe);
987 
988     /* Free the control packet */
989     RtlFreeHeap(RtlGetProcessHeap(), 0, ControlPacket);
990 
991 done:
992     /* Free the service table */
993     for (i = 0; i < dwActiveServiceCount; i++)
994     {
995         RtlFreeUnicodeString(&lpActiveServices[i].ServiceName);
996     }
997     RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
998     lpActiveServices = NULL;
999     dwActiveServiceCount = 0;
1000 
1001     return bRet;
1002 }
1003 
1004 
1005 /**********************************************************************
1006  *	StartServiceCtrlDispatcherW
1007  *
1008  * @implemented
1009  */
1010 BOOL WINAPI
1011 StartServiceCtrlDispatcherW(const SERVICE_TABLE_ENTRYW *lpServiceStartTable)
1012 {
1013     ULONG i;
1014     HANDLE hPipe;
1015     DWORD dwError;
1016     PSCM_CONTROL_PACKET ControlPacket;
1017     DWORD dwBufSize;
1018     BOOL bRet = TRUE;
1019 
1020     TRACE("StartServiceCtrlDispatcherW() called\n");
1021 
1022     i = 0;
1023     while (lpServiceStartTable[i].lpServiceProc != NULL)
1024     {
1025         i++;
1026     }
1027 
1028     dwActiveServiceCount = i;
1029     lpActiveServices = RtlAllocateHeap(RtlGetProcessHeap(),
1030                                        HEAP_ZERO_MEMORY,
1031                                        dwActiveServiceCount * sizeof(ACTIVE_SERVICE));
1032     if (lpActiveServices == NULL)
1033     {
1034         return FALSE;
1035     }
1036 
1037     /* Copy service names and start procedure */
1038     for (i = 0; i < dwActiveServiceCount; i++)
1039     {
1040         RtlCreateUnicodeString(&lpActiveServices[i].ServiceName,
1041                                lpServiceStartTable[i].lpServiceName);
1042         lpActiveServices[i].ServiceMain.W = lpServiceStartTable[i].lpServiceProc;
1043         lpActiveServices[i].hServiceStatus = 0;
1044         lpActiveServices[i].bUnicode = TRUE;
1045         lpActiveServices[i].bOwnProcess = FALSE;
1046     }
1047 
1048     dwError = ScConnectControlPipe(&hPipe);
1049     if (dwError != ERROR_SUCCESS)
1050     {
1051         bRet = FALSE;
1052         goto done;
1053     }
1054 
1055     dwBufSize = sizeof(SCM_CONTROL_PACKET) +
1056                 (MAX_SERVICE_NAME_LENGTH + 1) * sizeof(WCHAR);
1057 
1058     ControlPacket = RtlAllocateHeap(RtlGetProcessHeap(),
1059                                     HEAP_ZERO_MEMORY,
1060                                     dwBufSize);
1061     if (ControlPacket == NULL)
1062     {
1063         bRet = FALSE;
1064         goto done;
1065     }
1066 
1067     ScCreateStatusBinding();
1068 
1069     ScServiceDispatcher(hPipe, ControlPacket, dwBufSize);
1070 
1071     ScDestroyStatusBinding();
1072 
1073     CloseHandle(hPipe);
1074 
1075     /* Free the control packet */
1076     RtlFreeHeap(RtlGetProcessHeap(), 0, ControlPacket);
1077 
1078 done:
1079     /* Free the service table */
1080     for (i = 0; i < dwActiveServiceCount; i++)
1081     {
1082         RtlFreeUnicodeString(&lpActiveServices[i].ServiceName);
1083     }
1084     RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
1085     lpActiveServices = NULL;
1086     dwActiveServiceCount = 0;
1087 
1088     return bRet;
1089 }
1090 
1091 /* EOF */
1092