xref: /reactos/dll/win32/advapi32/service/sctrl.c (revision 7abc8be1)
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()\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()\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)\n",
144           lpServiceName);
145 
146     if (lpActiveServices[0].bOwnProcess)
147         return &lpActiveServices[0];
148 
149     for (i = 0; i < dwActiveServiceCount; i++)
150     {
151         TRACE("Checking %S\n", lpActiveServices[i].ServiceName.Buffer);
152         if (_wcsicmp(lpActiveServices[i].ServiceName.Buffer, lpServiceName) == 0)
153         {
154             TRACE("Found!\n");
155             return &lpActiveServices[i];
156         }
157     }
158 
159     TRACE("No service found!\n");
160     return NULL;
161 }
162 
163 
164 static DWORD WINAPI
165 ScServiceMainStubA(LPVOID Context)
166 {
167     PSERVICE_THREAD_PARAMSA ThreadParams = Context;
168 
169     TRACE("ScServiceMainStubA(%p)\n", Context);
170 
171     /* Call the main service routine and free the arguments vector */
172     (ThreadParams->lpServiceMain)(ThreadParams->dwArgCount,
173                                   ThreadParams->lpArgVector);
174 
175     if (ThreadParams->lpArgVector != NULL)
176     {
177         HeapFree(GetProcessHeap(), 0, ThreadParams->lpArgVector);
178     }
179     HeapFree(GetProcessHeap(), 0, ThreadParams);
180 
181     return ERROR_SUCCESS;
182 }
183 
184 
185 static DWORD WINAPI
186 ScServiceMainStubW(LPVOID Context)
187 {
188     PSERVICE_THREAD_PARAMSW ThreadParams = Context;
189 
190     TRACE("ScServiceMainStubW(%p)\n", Context);
191 
192     /* Call the main service routine and free the arguments vector */
193     (ThreadParams->lpServiceMain)(ThreadParams->dwArgCount,
194                                   ThreadParams->lpArgVector);
195 
196     if (ThreadParams->lpArgVector != NULL)
197     {
198         HeapFree(GetProcessHeap(), 0, ThreadParams->lpArgVector);
199     }
200     HeapFree(GetProcessHeap(), 0, ThreadParams);
201 
202     return ERROR_SUCCESS;
203 }
204 
205 
206 static DWORD
207 ScConnectControlPipe(HANDLE *hPipe)
208 {
209     DWORD dwBytesWritten;
210     DWORD dwState;
211     DWORD dwServiceCurrent = 0;
212     NTSTATUS Status;
213     WCHAR NtControlPipeName[MAX_PATH + 1];
214     RTL_QUERY_REGISTRY_TABLE QueryTable[2];
215     DWORD dwProcessId;
216 
217     TRACE("ScConnectControlPipe(%p)\n",
218           hPipe);
219 
220     /* Get the service number and create the named pipe */
221     RtlZeroMemory(&QueryTable,
222                   sizeof(QueryTable));
223 
224     QueryTable[0].Name = L"";
225     QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
226     QueryTable[0].EntryContext = &dwServiceCurrent;
227 
228     Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL,
229                                     L"ServiceCurrent",
230                                     QueryTable,
231                                     NULL,
232                                     NULL);
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(dwProcessId),
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     TRACE("ScStartService(%p %p)\n",
433           lpService, ControlPacket);
434 
435     if (lpService == NULL || ControlPacket == NULL)
436         return ERROR_INVALID_PARAMETER;
437 
438     TRACE("Size: %lu\n", ControlPacket->dwSize);
439     TRACE("Service: %S\n", (PWSTR)((ULONG_PTR)ControlPacket + ControlPacket->dwServiceNameOffset));
440 
441     /* Set the service status handle */
442     lpService->hServiceStatus = ControlPacket->hServiceStatus;
443 
444     /* Build the arguments vector */
445     if (lpService->bUnicode != FALSE)
446     {
447         ThreadParamsW = HeapAlloc(GetProcessHeap(), 0, sizeof(*ThreadParamsW));
448         if (ThreadParamsW == NULL)
449             return ERROR_NOT_ENOUGH_MEMORY;
450         dwError = ScBuildUnicodeArgsVector(ControlPacket,
451                                            &ThreadParamsW->dwArgCount,
452                                            &ThreadParamsW->lpArgVector);
453         if (dwError != ERROR_SUCCESS)
454         {
455             HeapFree(GetProcessHeap(), 0, ThreadParamsW);
456             return dwError;
457         }
458         ThreadParamsW->lpServiceMain = lpService->ServiceMain.W;
459         ThreadHandle = CreateThread(NULL,
460                                     0,
461                                     ScServiceMainStubW,
462                                     ThreadParamsW,
463                                     0,
464                                     &ThreadId);
465         if (ThreadHandle == NULL)
466         {
467             if (ThreadParamsW->lpArgVector != NULL)
468             {
469                 HeapFree(GetProcessHeap(), 0, ThreadParamsW->lpArgVector);
470             }
471             HeapFree(GetProcessHeap(), 0, ThreadParamsW);
472 
473             return ERROR_SERVICE_NO_THREAD;
474         }
475 
476         CloseHandle(ThreadHandle);
477     }
478     else
479     {
480         ThreadParamsA = HeapAlloc(GetProcessHeap(), 0, sizeof(*ThreadParamsA));
481         if (ThreadParamsA == NULL)
482             return ERROR_NOT_ENOUGH_MEMORY;
483         dwError = ScBuildAnsiArgsVector(ControlPacket,
484                                         &ThreadParamsA->dwArgCount,
485                                         &ThreadParamsA->lpArgVector);
486         if (dwError != ERROR_SUCCESS)
487         {
488             HeapFree(GetProcessHeap(), 0, ThreadParamsA);
489             return dwError;
490         }
491         ThreadParamsA->lpServiceMain = lpService->ServiceMain.A;
492         ThreadHandle = CreateThread(NULL,
493                                     0,
494                                     ScServiceMainStubA,
495                                     ThreadParamsA,
496                                     0,
497                                     &ThreadId);
498         if (ThreadHandle == NULL)
499         {
500             if (ThreadParamsA->lpArgVector != NULL)
501             {
502                 HeapFree(GetProcessHeap(), 0, ThreadParamsA->lpArgVector);
503             }
504             HeapFree(GetProcessHeap(), 0, ThreadParamsA);
505 
506             return ERROR_SERVICE_NO_THREAD;
507         }
508 
509         CloseHandle(ThreadHandle);
510     }
511 
512     return ERROR_SUCCESS;
513 }
514 
515 
516 static DWORD
517 ScControlService(PACTIVE_SERVICE lpService,
518                  PSCM_CONTROL_PACKET ControlPacket)
519 {
520     DWORD dwError = ERROR_SUCCESS;
521 
522     TRACE("ScControlService(%p %p)\n",
523           lpService, ControlPacket);
524 
525     if (lpService == NULL || ControlPacket == NULL)
526         return ERROR_INVALID_PARAMETER;
527 
528     TRACE("Size: %lu\n", ControlPacket->dwSize);
529     TRACE("Service: %S\n", (PWSTR)((ULONG_PTR)ControlPacket + ControlPacket->dwServiceNameOffset));
530 
531     if (lpService->HandlerFunction)
532     {
533         _SEH2_TRY
534         {
535             (lpService->HandlerFunction)(ControlPacket->dwControl);
536         }
537         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
538         {
539             dwError = ERROR_EXCEPTION_IN_SERVICE;
540         }
541         _SEH2_END;
542     }
543     else if (lpService->HandlerFunctionEx)
544     {
545         _SEH2_TRY
546         {
547             /* FIXME: Send correct 2nd and 3rd parameters */
548             (lpService->HandlerFunctionEx)(ControlPacket->dwControl,
549                                            0, NULL,
550                                            lpService->HandlerContext);
551         }
552         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
553         {
554             dwError = ERROR_EXCEPTION_IN_SERVICE;
555         }
556         _SEH2_END;
557     }
558     else
559     {
560         dwError = ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
561     }
562 
563     TRACE("ScControlService() done (Error %lu)\n", dwError);
564 
565     return dwError;
566 }
567 
568 
569 static BOOL
570 ScServiceDispatcher(HANDLE hPipe,
571                     PSCM_CONTROL_PACKET ControlPacket,
572                     DWORD dwBufferSize)
573 {
574     DWORD Count;
575     BOOL bResult;
576     BOOL bRunning = TRUE;
577     LPWSTR lpServiceName;
578     PACTIVE_SERVICE lpService;
579     SCM_REPLY_PACKET ReplyPacket;
580     DWORD dwError;
581 
582     TRACE("ScServiceDispatcher(%p %p %lu)\n",
583           hPipe, ControlPacket, dwBufferSize);
584 
585     if (ControlPacket == NULL || dwBufferSize < sizeof(SCM_CONTROL_PACKET))
586         return FALSE;
587 
588     while (bRunning)
589     {
590         /* Read command from the control pipe */
591         bResult = ReadFile(hPipe,
592                            ControlPacket,
593                            dwBufferSize,
594                            &Count,
595                            NULL);
596         if (bResult == FALSE)
597         {
598             ERR("Pipe read failed (Error: %lu)\n", GetLastError());
599             return FALSE;
600         }
601 
602         lpServiceName = (LPWSTR)((PBYTE)ControlPacket + ControlPacket->dwServiceNameOffset);
603         TRACE("Service: %S\n", lpServiceName);
604 
605         if ((ControlPacket->dwControl == SERVICE_CONTROL_STOP) &&
606             (lpServiceName[0] == UNICODE_NULL))
607         {
608             TRACE("Stop dispatcher thread\n");
609             bRunning = FALSE;
610             dwError = ERROR_SUCCESS;
611         }
612         else
613         {
614             if (ControlPacket->dwControl == SERVICE_CONTROL_START_OWN)
615                 lpActiveServices[0].bOwnProcess = TRUE;
616 
617             lpService = ScLookupServiceByServiceName(lpServiceName);
618             if (lpService != NULL)
619             {
620                 /* Execute command */
621                 switch (ControlPacket->dwControl)
622                 {
623                     case SERVICE_CONTROL_START_SHARE:
624                     case SERVICE_CONTROL_START_OWN:
625                         TRACE("Start command - received SERVICE_CONTROL_START\n");
626                         dwError = ScStartService(lpService, ControlPacket);
627                         break;
628 
629                     case SERVICE_CONTROL_STOP:
630                         TRACE("Stop command - received SERVICE_CONTROL_STOP\n");
631                         dwError = ScControlService(lpService, ControlPacket);
632                         break;
633 
634                     default:
635                         TRACE("Command %lu received", ControlPacket->dwControl);
636                         dwError = ScControlService(lpService, ControlPacket);
637                         break;
638                 }
639             }
640             else
641             {
642                 dwError = ERROR_SERVICE_NOT_IN_EXE;
643             }
644         }
645 
646         ReplyPacket.dwError = dwError;
647 
648         /* Send the reply packet */
649         bResult = WriteFile(hPipe,
650                             &ReplyPacket,
651                             sizeof(ReplyPacket),
652                             &Count,
653                             NULL);
654         if (bResult == FALSE)
655         {
656             ERR("Pipe write failed (Error: %lu)\n", GetLastError());
657             return FALSE;
658         }
659     }
660 
661     return TRUE;
662 }
663 
664 
665 /**********************************************************************
666  *  RegisterServiceCtrlHandlerA
667  *
668  * @implemented
669  */
670 SERVICE_STATUS_HANDLE WINAPI
671 RegisterServiceCtrlHandlerA(LPCSTR lpServiceName,
672                             LPHANDLER_FUNCTION lpHandlerProc)
673 {
674     ANSI_STRING ServiceNameA;
675     UNICODE_STRING ServiceNameU;
676     SERVICE_STATUS_HANDLE hServiceStatus;
677 
678     TRACE("RegisterServiceCtrlHandlerA(%s %p)\n",
679           debugstr_a(lpServiceName), lpHandlerProc);
680 
681     RtlInitAnsiString(&ServiceNameA, lpServiceName);
682     if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ServiceNameU, &ServiceNameA, TRUE)))
683     {
684         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
685         return NULL;
686     }
687 
688     hServiceStatus = RegisterServiceCtrlHandlerW(ServiceNameU.Buffer,
689                                                  lpHandlerProc);
690 
691     RtlFreeUnicodeString(&ServiceNameU);
692 
693     return hServiceStatus;
694 }
695 
696 
697 /**********************************************************************
698  *  RegisterServiceCtrlHandlerW
699  *
700  * @implemented
701  */
702 SERVICE_STATUS_HANDLE WINAPI
703 RegisterServiceCtrlHandlerW(LPCWSTR lpServiceName,
704                             LPHANDLER_FUNCTION lpHandlerProc)
705 {
706     PACTIVE_SERVICE Service;
707 
708     TRACE("RegisterServiceCtrlHandlerW(%s %p)\n",
709           debugstr_w(lpServiceName), lpHandlerProc);
710 
711     Service = ScLookupServiceByServiceName(lpServiceName);
712     if (Service == NULL)
713     {
714         SetLastError(ERROR_SERVICE_NOT_IN_EXE);
715         return NULL;
716     }
717 
718     if (!lpHandlerProc)
719     {
720         SetLastError(ERROR_INVALID_PARAMETER);
721         return NULL;
722     }
723 
724     Service->HandlerFunction = lpHandlerProc;
725     Service->HandlerFunctionEx = NULL;
726 
727     TRACE("RegisterServiceCtrlHandler returning %p\n", Service->hServiceStatus);
728 
729     return Service->hServiceStatus;
730 }
731 
732 
733 /**********************************************************************
734  *  RegisterServiceCtrlHandlerExA
735  *
736  * @implemented
737  */
738 SERVICE_STATUS_HANDLE WINAPI
739 RegisterServiceCtrlHandlerExA(LPCSTR lpServiceName,
740                               LPHANDLER_FUNCTION_EX lpHandlerProc,
741                               LPVOID lpContext)
742 {
743     ANSI_STRING ServiceNameA;
744     UNICODE_STRING ServiceNameU;
745     SERVICE_STATUS_HANDLE hServiceStatus;
746 
747     TRACE("RegisterServiceCtrlHandlerExA(%s %p %p)\n",
748           debugstr_a(lpServiceName), lpHandlerProc, lpContext);
749 
750     RtlInitAnsiString(&ServiceNameA, lpServiceName);
751     if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ServiceNameU, &ServiceNameA, TRUE)))
752     {
753         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
754         return NULL;
755     }
756 
757     hServiceStatus = RegisterServiceCtrlHandlerExW(ServiceNameU.Buffer,
758                                                    lpHandlerProc,
759                                                    lpContext);
760 
761     RtlFreeUnicodeString(&ServiceNameU);
762 
763     return hServiceStatus;
764 }
765 
766 
767 /**********************************************************************
768  *  RegisterServiceCtrlHandlerExW
769  *
770  * @implemented
771  */
772 SERVICE_STATUS_HANDLE WINAPI
773 RegisterServiceCtrlHandlerExW(LPCWSTR lpServiceName,
774                               LPHANDLER_FUNCTION_EX lpHandlerProc,
775                               LPVOID lpContext)
776 {
777     PACTIVE_SERVICE Service;
778 
779     TRACE("RegisterServiceCtrlHandlerExW(%s %p %p)\n",
780           debugstr_w(lpServiceName), lpHandlerProc, lpContext);
781 
782     Service = ScLookupServiceByServiceName(lpServiceName);
783     if (Service == NULL)
784     {
785         SetLastError(ERROR_SERVICE_NOT_IN_EXE);
786         return NULL;
787     }
788 
789     if (!lpHandlerProc)
790     {
791         SetLastError(ERROR_INVALID_PARAMETER);
792         return NULL;
793     }
794 
795     Service->HandlerFunction = NULL;
796     Service->HandlerFunctionEx = lpHandlerProc;
797     Service->HandlerContext = lpContext;
798 
799     TRACE("RegisterServiceCtrlHandlerEx returning %p\n", Service->hServiceStatus);
800 
801     return Service->hServiceStatus;
802 }
803 
804 
805 /**********************************************************************
806  *  I_ScIsSecurityProcess
807  *
808  * Undocumented
809  *
810  * @unimplemented
811  */
812 VOID
813 WINAPI
814 I_ScIsSecurityProcess(VOID)
815 {
816     FIXME("I_ScIsSecurityProcess()\n");
817 }
818 
819 
820 /**********************************************************************
821  *  I_ScPnPGetServiceName
822  *
823  * Undocumented
824  *
825  * @implemented
826  */
827 DWORD
828 WINAPI
829 I_ScPnPGetServiceName(IN SERVICE_STATUS_HANDLE hServiceStatus,
830                       OUT LPWSTR lpServiceName,
831                       IN DWORD cchServiceName)
832 {
833     DWORD i;
834 
835     TRACE("I_ScPnPGetServiceName(%lu %p %lu)\n",
836           hServiceStatus, lpServiceName, cchServiceName);
837 
838     for (i = 0; i < dwActiveServiceCount; i++)
839     {
840         if (lpActiveServices[i].hServiceStatus == hServiceStatus)
841         {
842             wcscpy(lpServiceName, lpActiveServices[i].ServiceName.Buffer);
843             return ERROR_SUCCESS;
844         }
845     }
846 
847     return ERROR_SERVICE_NOT_IN_EXE;
848 }
849 
850 
851 /**********************************************************************
852  *  I_ScSetServiceBitsA
853  *
854  * Undocumented
855  *
856  * @implemented
857  */
858 BOOL WINAPI
859 I_ScSetServiceBitsA(SERVICE_STATUS_HANDLE hServiceStatus,
860                     DWORD dwServiceBits,
861                     BOOL bSetBitsOn,
862                     BOOL bUpdateImmediately,
863                     LPSTR lpString)
864 {
865     BOOL bResult;
866 
867     TRACE("I_ScSetServiceBitsA(%lu %lx %u %u %s)\n",
868           hServiceStatus, dwServiceBits, bSetBitsOn, bUpdateImmediately,
869           debugstr_a(lpString));
870 
871     RpcTryExcept
872     {
873         bResult = RI_ScSetServiceBitsA((RPC_SERVICE_STATUS_HANDLE)hServiceStatus,
874                                        dwServiceBits,
875                                        bSetBitsOn,
876                                        bUpdateImmediately,
877                                        lpString);
878     }
879     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
880     {
881         SetLastError(ScmRpcStatusToWinError(RpcExceptionCode()));
882         bResult = FALSE;
883     }
884     RpcEndExcept;
885 
886     return bResult;
887 }
888 
889 
890 /**********************************************************************
891  *  I_ScSetServiceBitsW
892  *
893  * Undocumented
894  *
895  * @implemented
896  */
897 BOOL WINAPI
898 I_ScSetServiceBitsW(SERVICE_STATUS_HANDLE hServiceStatus,
899                     DWORD dwServiceBits,
900                     BOOL bSetBitsOn,
901                     BOOL bUpdateImmediately,
902                     LPWSTR lpString)
903 {
904     BOOL bResult;
905 
906     TRACE("I_ScSetServiceBitsW(%lu %lx %u %u %s)\n",
907           hServiceStatus, dwServiceBits, bSetBitsOn, bUpdateImmediately,
908           debugstr_w(lpString));
909 
910     RpcTryExcept
911     {
912         bResult = RI_ScSetServiceBitsW((RPC_SERVICE_STATUS_HANDLE)hServiceStatus,
913                                        dwServiceBits,
914                                        bSetBitsOn,
915                                        bUpdateImmediately,
916                                        lpString);
917     }
918     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
919     {
920         SetLastError(ScmRpcStatusToWinError(RpcExceptionCode()));
921         bResult = FALSE;
922     }
923     RpcEndExcept;
924 
925     return bResult;
926 }
927 
928 
929 /**********************************************************************
930  *  SetServiceBits
931  *
932  * @implemented
933  */
934 BOOL WINAPI
935 SetServiceBits(SERVICE_STATUS_HANDLE hServiceStatus,
936                DWORD dwServiceBits,
937                BOOL bSetBitsOn,
938                BOOL bUpdateImmediately)
939 {
940     TRACE("SetServiceBits(%lu %lx %u %u)\n",
941           hServiceStatus, dwServiceBits, bSetBitsOn, bUpdateImmediately);
942 
943     return I_ScSetServiceBitsW(hServiceStatus,
944                                dwServiceBits,
945                                bSetBitsOn,
946                                bUpdateImmediately,
947                                NULL);
948 }
949 
950 
951 /**********************************************************************
952  *  SetServiceStatus
953  *
954  * @implemented
955  */
956 BOOL WINAPI
957 SetServiceStatus(SERVICE_STATUS_HANDLE hServiceStatus,
958                  LPSERVICE_STATUS lpServiceStatus)
959 {
960     DWORD dwError;
961 
962     TRACE("SetServiceStatus(%lu %p)\n",
963           hServiceStatus, lpServiceStatus);
964 
965     RpcTryExcept
966     {
967         dwError = RSetServiceStatus((RPC_SERVICE_STATUS_HANDLE)hServiceStatus,
968                                     lpServiceStatus);
969     }
970     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
971     {
972         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
973     }
974     RpcEndExcept;
975 
976     if (dwError != ERROR_SUCCESS)
977     {
978         ERR("RSetServiceStatus() failed (Error %lu)\n", dwError);
979         SetLastError(dwError);
980         return FALSE;
981     }
982 
983     TRACE("SetServiceStatus() done\n");
984 
985     return TRUE;
986 }
987 
988 
989 /**********************************************************************
990  *  StartServiceCtrlDispatcherA
991  *
992  * @implemented
993  */
994 BOOL WINAPI
995 StartServiceCtrlDispatcherA(const SERVICE_TABLE_ENTRYA *lpServiceStartTable)
996 {
997     ULONG i;
998     HANDLE hPipe;
999     DWORD dwError;
1000     PSCM_CONTROL_PACKET ControlPacket;
1001     DWORD dwBufSize;
1002     BOOL bRet = TRUE;
1003 
1004     TRACE("StartServiceCtrlDispatcherA(%p)\n",
1005           lpServiceStartTable);
1006 
1007     i = 0;
1008     while (lpServiceStartTable[i].lpServiceProc != NULL)
1009     {
1010         i++;
1011     }
1012 
1013     dwActiveServiceCount = i;
1014 
1015     /* Allocate the service table */
1016     lpActiveServices = RtlAllocateHeap(RtlGetProcessHeap(),
1017                                        HEAP_ZERO_MEMORY,
1018                                        dwActiveServiceCount * sizeof(ACTIVE_SERVICE));
1019     if (lpActiveServices == NULL)
1020     {
1021         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1022         return FALSE;
1023     }
1024 
1025     /* Copy service names and start procedure */
1026     for (i = 0; i < dwActiveServiceCount; i++)
1027     {
1028         RtlCreateUnicodeStringFromAsciiz(&lpActiveServices[i].ServiceName,
1029                                          lpServiceStartTable[i].lpServiceName);
1030         lpActiveServices[i].ServiceMain.A = lpServiceStartTable[i].lpServiceProc;
1031         lpActiveServices[i].hServiceStatus = NULL;
1032         lpActiveServices[i].bUnicode = FALSE;
1033         lpActiveServices[i].bOwnProcess = FALSE;
1034     }
1035 
1036     /* Connect to the SCM */
1037     dwError = ScConnectControlPipe(&hPipe);
1038     if (dwError != ERROR_SUCCESS)
1039     {
1040         bRet = FALSE;
1041         goto done;
1042     }
1043 
1044     dwBufSize = sizeof(SCM_CONTROL_PACKET) +
1045                 (MAX_SERVICE_NAME_LENGTH + 1) * sizeof(WCHAR);
1046 
1047     ControlPacket = RtlAllocateHeap(RtlGetProcessHeap(),
1048                                     HEAP_ZERO_MEMORY,
1049                                     dwBufSize);
1050     if (ControlPacket == NULL)
1051     {
1052         dwError = ERROR_NOT_ENOUGH_MEMORY;
1053         bRet = FALSE;
1054         goto done;
1055     }
1056 
1057     ScCreateStatusBinding();
1058 
1059     /* Call the dispatcher loop */
1060     ScServiceDispatcher(hPipe, ControlPacket, dwBufSize);
1061 
1062 
1063     ScDestroyStatusBinding();
1064 
1065     /* Close the connection */
1066     CloseHandle(hPipe);
1067 
1068     /* Free the control packet */
1069     RtlFreeHeap(RtlGetProcessHeap(), 0, ControlPacket);
1070 
1071 done:
1072     /* Free the service table */
1073     for (i = 0; i < dwActiveServiceCount; i++)
1074     {
1075         RtlFreeUnicodeString(&lpActiveServices[i].ServiceName);
1076     }
1077     RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
1078     lpActiveServices = NULL;
1079     dwActiveServiceCount = 0;
1080 
1081     if (!bRet)
1082         SetLastError(dwError);
1083 
1084     return bRet;
1085 }
1086 
1087 
1088 /**********************************************************************
1089  *  StartServiceCtrlDispatcherW
1090  *
1091  * @implemented
1092  */
1093 BOOL WINAPI
1094 StartServiceCtrlDispatcherW(const SERVICE_TABLE_ENTRYW *lpServiceStartTable)
1095 {
1096     ULONG i;
1097     HANDLE hPipe;
1098     DWORD dwError;
1099     PSCM_CONTROL_PACKET ControlPacket;
1100     DWORD dwBufSize;
1101     BOOL bRet = TRUE;
1102 
1103     TRACE("StartServiceCtrlDispatcherW(%p)\n",
1104           lpServiceStartTable);
1105 
1106     i = 0;
1107     while (lpServiceStartTable[i].lpServiceProc != NULL)
1108     {
1109         i++;
1110     }
1111 
1112     dwActiveServiceCount = i;
1113 
1114     /* Allocate the service table */
1115     lpActiveServices = RtlAllocateHeap(RtlGetProcessHeap(),
1116                                        HEAP_ZERO_MEMORY,
1117                                        dwActiveServiceCount * sizeof(ACTIVE_SERVICE));
1118     if (lpActiveServices == NULL)
1119     {
1120         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1121         return FALSE;
1122     }
1123 
1124     /* Copy service names and start procedure */
1125     for (i = 0; i < dwActiveServiceCount; i++)
1126     {
1127         RtlCreateUnicodeString(&lpActiveServices[i].ServiceName,
1128                                lpServiceStartTable[i].lpServiceName);
1129         lpActiveServices[i].ServiceMain.W = lpServiceStartTable[i].lpServiceProc;
1130         lpActiveServices[i].hServiceStatus = NULL;
1131         lpActiveServices[i].bUnicode = TRUE;
1132         lpActiveServices[i].bOwnProcess = FALSE;
1133     }
1134 
1135     /* Connect to the SCM */
1136     dwError = ScConnectControlPipe(&hPipe);
1137     if (dwError != ERROR_SUCCESS)
1138     {
1139         bRet = FALSE;
1140         goto done;
1141     }
1142 
1143     dwBufSize = sizeof(SCM_CONTROL_PACKET) +
1144                 (MAX_SERVICE_NAME_LENGTH + 1) * sizeof(WCHAR);
1145 
1146     ControlPacket = RtlAllocateHeap(RtlGetProcessHeap(),
1147                                     HEAP_ZERO_MEMORY,
1148                                     dwBufSize);
1149     if (ControlPacket == NULL)
1150     {
1151         dwError = ERROR_NOT_ENOUGH_MEMORY;
1152         bRet = FALSE;
1153         goto done;
1154     }
1155 
1156     ScCreateStatusBinding();
1157 
1158     /* Call the dispatcher loop */
1159     ScServiceDispatcher(hPipe, ControlPacket, dwBufSize);
1160 
1161     ScDestroyStatusBinding();
1162 
1163     /* Close the connection */
1164     CloseHandle(hPipe);
1165 
1166     /* Free the control packet */
1167     RtlFreeHeap(RtlGetProcessHeap(), 0, ControlPacket);
1168 
1169 done:
1170     /* Free the service table */
1171     for (i = 0; i < dwActiveServiceCount; i++)
1172     {
1173         RtlFreeUnicodeString(&lpActiveServices[i].ServiceName);
1174     }
1175     RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
1176     lpActiveServices = NULL;
1177     dwActiveServiceCount = 0;
1178 
1179     if (!bRet)
1180         SetLastError(dwError);
1181 
1182     return bRet;
1183 }
1184 
1185 /* EOF */
1186