[ADVAPI32] ScStartService(): Just start the thread straight ahead, and return a suita...
[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_service);
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(Size: %lu, Service: '%S') called\n",
436 ControlPacket->dwSize,
437 (PWSTR)((ULONG_PTR)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 0,
462 &ThreadId);
463 if (ThreadHandle == NULL)
464 {
465 if (ThreadParamsW->lpArgVector != NULL)
466 {
467 HeapFree(GetProcessHeap(), 0, ThreadParamsW->lpArgVector);
468 }
469 HeapFree(GetProcessHeap(), 0, ThreadParamsW);
470
471 return ERROR_SERVICE_NO_THREAD;
472 }
473
474 CloseHandle(ThreadHandle);
475 }
476 else
477 {
478 ThreadParamsA = HeapAlloc(GetProcessHeap(), 0, sizeof(*ThreadParamsA));
479 if (ThreadParamsA == NULL)
480 return ERROR_NOT_ENOUGH_MEMORY;
481 dwError = ScBuildAnsiArgsVector(ControlPacket,
482 &ThreadParamsA->dwArgCount,
483 &ThreadParamsA->lpArgVector);
484 if (dwError != ERROR_SUCCESS)
485 {
486 HeapFree(GetProcessHeap(), 0, ThreadParamsA);
487 return dwError;
488 }
489 ThreadParamsA->lpServiceMain = lpService->ServiceMain.A;
490 ThreadHandle = CreateThread(NULL,
491 0,
492 ScServiceMainStubA,
493 ThreadParamsA,
494 0,
495 &ThreadId);
496 if (ThreadHandle == NULL)
497 {
498 if (ThreadParamsA->lpArgVector != NULL)
499 {
500 HeapFree(GetProcessHeap(), 0, ThreadParamsA->lpArgVector);
501 }
502 HeapFree(GetProcessHeap(), 0, ThreadParamsA);
503
504 return ERROR_SERVICE_NO_THREAD;
505 }
506
507 CloseHandle(ThreadHandle);
508 }
509
510 return ERROR_SUCCESS;
511 }
512
513
514 static DWORD
515 ScControlService(PACTIVE_SERVICE lpService,
516 PSCM_CONTROL_PACKET ControlPacket)
517 {
518 DWORD dwError;
519
520 if (lpService == NULL || ControlPacket == NULL)
521 return ERROR_INVALID_PARAMETER;
522
523 TRACE("ScControlService(Size: %lu, Service: '%S') called\n",
524 ControlPacket->dwSize,
525 (PWSTR)((ULONG_PTR)ControlPacket + ControlPacket->dwServiceNameOffset));
526
527 if (lpService->HandlerFunction)
528 {
529 (lpService->HandlerFunction)(ControlPacket->dwControl);
530 dwError = ERROR_SUCCESS;
531 }
532 else if (lpService->HandlerFunctionEx)
533 {
534 /* FIXME: Send correct 2nd and 3rd parameters */
535 dwError = (lpService->HandlerFunctionEx)(ControlPacket->dwControl,
536 0, NULL,
537 lpService->HandlerContext);
538 }
539
540 TRACE("ScControlService() done (error %lu)\n", dwError);
541
542 return dwError;
543 }
544
545
546 static BOOL
547 ScServiceDispatcher(HANDLE hPipe,
548 PSCM_CONTROL_PACKET ControlPacket,
549 DWORD dwBufferSize)
550 {
551 DWORD Count;
552 BOOL bResult;
553 BOOL bRunning = TRUE;
554 LPWSTR lpServiceName;
555 PACTIVE_SERVICE lpService;
556 SCM_REPLY_PACKET ReplyPacket;
557 DWORD dwError;
558
559 TRACE("ScDispatcherLoop() called\n");
560
561 if (ControlPacket == NULL || dwBufferSize < sizeof(SCM_CONTROL_PACKET))
562 return FALSE;
563
564 while (bRunning)
565 {
566 /* Read command from the control pipe */
567 bResult = ReadFile(hPipe,
568 ControlPacket,
569 dwBufferSize,
570 &Count,
571 NULL);
572 if (bResult == FALSE)
573 {
574 ERR("Pipe read failed (Error: %lu)\n", GetLastError());
575 return FALSE;
576 }
577
578 lpServiceName = (LPWSTR)((PBYTE)ControlPacket + ControlPacket->dwServiceNameOffset);
579 TRACE("Service: %S\n", lpServiceName);
580
581 if (lpServiceName[0] == UNICODE_NULL)
582 {
583 ERR("Stop dispatcher thread\n");
584 bRunning = FALSE;
585 dwError = ERROR_SUCCESS;
586 }
587 else
588 {
589 if (ControlPacket->dwControl == SERVICE_CONTROL_START_OWN)
590 lpActiveServices[0].bOwnProcess = TRUE;
591
592 lpService = ScLookupServiceByServiceName(lpServiceName);
593 if (lpService != NULL)
594 {
595 /* Execute command */
596 switch (ControlPacket->dwControl)
597 {
598 case SERVICE_CONTROL_START_SHARE:
599 case SERVICE_CONTROL_START_OWN:
600 TRACE("Start command - received SERVICE_CONTROL_START\n");
601 dwError = ScStartService(lpService, ControlPacket);
602 break;
603
604 case SERVICE_CONTROL_STOP:
605 TRACE("Stop command - received SERVICE_CONTROL_STOP\n");
606 dwError = ScControlService(lpService, ControlPacket);
607 break;
608
609 default:
610 TRACE("Command %lu received", ControlPacket->dwControl);
611 dwError = ScControlService(lpService, ControlPacket);
612 break;
613 }
614 }
615 else
616 {
617 dwError = ERROR_SERVICE_DOES_NOT_EXIST;
618 }
619 }
620
621 ReplyPacket.dwError = dwError;
622
623 /* Send the reply packet */
624 bResult = WriteFile(hPipe,
625 &ReplyPacket,
626 sizeof(ReplyPacket),
627 &Count,
628 NULL);
629 if (bResult == FALSE)
630 {
631 ERR("Pipe write failed (Error: %lu)\n", GetLastError());
632 return FALSE;
633 }
634 }
635
636 return TRUE;
637 }
638
639
640 /**********************************************************************
641 * RegisterServiceCtrlHandlerA
642 *
643 * @implemented
644 */
645 SERVICE_STATUS_HANDLE WINAPI
646 RegisterServiceCtrlHandlerA(LPCSTR lpServiceName,
647 LPHANDLER_FUNCTION lpHandlerProc)
648 {
649 ANSI_STRING ServiceNameA;
650 UNICODE_STRING ServiceNameU;
651 SERVICE_STATUS_HANDLE SHandle;
652
653 RtlInitAnsiString(&ServiceNameA, (LPSTR)lpServiceName);
654 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ServiceNameU, &ServiceNameA, TRUE)))
655 {
656 SetLastError(ERROR_OUTOFMEMORY);
657 return (SERVICE_STATUS_HANDLE)0;
658 }
659
660 SHandle = RegisterServiceCtrlHandlerW(ServiceNameU.Buffer,
661 lpHandlerProc);
662
663 RtlFreeUnicodeString(&ServiceNameU);
664
665 return SHandle;
666 }
667
668
669 /**********************************************************************
670 * RegisterServiceCtrlHandlerW
671 *
672 * @implemented
673 */
674 SERVICE_STATUS_HANDLE WINAPI
675 RegisterServiceCtrlHandlerW(LPCWSTR lpServiceName,
676 LPHANDLER_FUNCTION lpHandlerProc)
677 {
678 PACTIVE_SERVICE Service;
679
680 Service = ScLookupServiceByServiceName((LPWSTR)lpServiceName);
681 if (Service == NULL)
682 {
683 return (SERVICE_STATUS_HANDLE)NULL;
684 }
685
686 Service->HandlerFunction = lpHandlerProc;
687 Service->HandlerFunctionEx = NULL;
688
689 TRACE("RegisterServiceCtrlHandler returning %lu\n", Service->hServiceStatus);
690
691 return Service->hServiceStatus;
692 }
693
694
695 /**********************************************************************
696 * RegisterServiceCtrlHandlerExA
697 *
698 * @implemented
699 */
700 SERVICE_STATUS_HANDLE WINAPI
701 RegisterServiceCtrlHandlerExA(LPCSTR lpServiceName,
702 LPHANDLER_FUNCTION_EX lpHandlerProc,
703 LPVOID lpContext)
704 {
705 ANSI_STRING ServiceNameA;
706 UNICODE_STRING ServiceNameU;
707 SERVICE_STATUS_HANDLE SHandle;
708
709 RtlInitAnsiString(&ServiceNameA, (LPSTR)lpServiceName);
710 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ServiceNameU, &ServiceNameA, TRUE)))
711 {
712 SetLastError(ERROR_OUTOFMEMORY);
713 return (SERVICE_STATUS_HANDLE)0;
714 }
715
716 SHandle = RegisterServiceCtrlHandlerExW(ServiceNameU.Buffer,
717 lpHandlerProc,
718 lpContext);
719
720 RtlFreeUnicodeString(&ServiceNameU);
721
722 return SHandle;
723 }
724
725
726 /**********************************************************************
727 * RegisterServiceCtrlHandlerExW
728 *
729 * @implemented
730 */
731 SERVICE_STATUS_HANDLE WINAPI
732 RegisterServiceCtrlHandlerExW(LPCWSTR lpServiceName,
733 LPHANDLER_FUNCTION_EX lpHandlerProc,
734 LPVOID lpContext)
735 {
736 PACTIVE_SERVICE Service;
737
738 Service = ScLookupServiceByServiceName(lpServiceName);
739 if (Service == NULL)
740 {
741 return (SERVICE_STATUS_HANDLE)NULL;
742 }
743
744 Service->HandlerFunction = NULL;
745 Service->HandlerFunctionEx = lpHandlerProc;
746 Service->HandlerContext = lpContext;
747
748 TRACE("RegisterServiceCtrlHandlerEx returning %lu\n", Service->hServiceStatus);
749
750 return Service->hServiceStatus;
751 }
752
753
754 /**********************************************************************
755 * I_ScIsSecurityProcess
756 *
757 * Undocumented
758 *
759 * @unimplemented
760 */
761 VOID
762 WINAPI
763 I_ScIsSecurityProcess(VOID)
764 {
765 }
766
767
768 /**********************************************************************
769 * I_ScPnPGetServiceName
770 *
771 * Undocumented
772 *
773 * @implemented
774 */
775 DWORD
776 WINAPI
777 I_ScPnPGetServiceName(IN SERVICE_STATUS_HANDLE hServiceStatus,
778 OUT LPWSTR lpServiceName,
779 IN DWORD cchServiceName)
780 {
781 DWORD i;
782
783 for (i = 0; i < dwActiveServiceCount; i++)
784 {
785 if (lpActiveServices[i].hServiceStatus == hServiceStatus)
786 {
787 wcscpy(lpServiceName, lpActiveServices[i].ServiceName.Buffer);
788 return ERROR_SUCCESS;
789 }
790 }
791
792 return ERROR_SERVICE_NOT_IN_EXE;
793 }
794
795
796 /**********************************************************************
797 * I_ScSetServiceBitsA
798 *
799 * Undocumented
800 *
801 * @implemented
802 */
803 BOOL WINAPI
804 I_ScSetServiceBitsA(SERVICE_STATUS_HANDLE hServiceStatus,
805 DWORD dwServiceBits,
806 BOOL bSetBitsOn,
807 BOOL bUpdateImmediately,
808 LPSTR lpString)
809 {
810 BOOL bResult;
811
812 RpcTryExcept
813 {
814 /* Call to services.exe using RPC */
815 bResult = RI_ScSetServiceBitsA((RPC_SERVICE_STATUS_HANDLE)hServiceStatus,
816 dwServiceBits,
817 bSetBitsOn,
818 bUpdateImmediately,
819 lpString);
820 }
821 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
822 {
823 SetLastError(ScmRpcStatusToWinError(RpcExceptionCode()));
824 bResult = FALSE;
825 }
826 RpcEndExcept;
827
828 return bResult;
829 }
830
831
832 /**********************************************************************
833 * I_ScSetServiceBitsW
834 *
835 * Undocumented
836 *
837 * @implemented
838 */
839 BOOL WINAPI
840 I_ScSetServiceBitsW(SERVICE_STATUS_HANDLE hServiceStatus,
841 DWORD dwServiceBits,
842 BOOL bSetBitsOn,
843 BOOL bUpdateImmediately,
844 LPWSTR lpString)
845 {
846 BOOL bResult;
847
848 RpcTryExcept
849 {
850 /* Call to services.exe using RPC */
851 bResult = RI_ScSetServiceBitsW((RPC_SERVICE_STATUS_HANDLE)hServiceStatus,
852 dwServiceBits,
853 bSetBitsOn,
854 bUpdateImmediately,
855 lpString);
856 }
857 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
858 {
859 SetLastError(ScmRpcStatusToWinError(RpcExceptionCode()));
860 bResult = FALSE;
861 }
862 RpcEndExcept;
863
864 return bResult;
865 }
866
867
868 /**********************************************************************
869 * SetServiceBits
870 *
871 * @implemented
872 */
873 BOOL WINAPI
874 SetServiceBits(SERVICE_STATUS_HANDLE hServiceStatus,
875 DWORD dwServiceBits,
876 BOOL bSetBitsOn,
877 BOOL bUpdateImmediately)
878 {
879 return I_ScSetServiceBitsW(hServiceStatus,
880 dwServiceBits,
881 bSetBitsOn,
882 bUpdateImmediately,
883 NULL);
884 }
885
886
887 /**********************************************************************
888 * SetServiceStatus
889 *
890 * @implemented
891 */
892 BOOL WINAPI
893 SetServiceStatus(SERVICE_STATUS_HANDLE hServiceStatus,
894 LPSERVICE_STATUS lpServiceStatus)
895 {
896 DWORD dwError;
897
898 TRACE("SetServiceStatus() called\n");
899 TRACE("hServiceStatus %lu\n", hServiceStatus);
900
901 RpcTryExcept
902 {
903 /* Call to services.exe using RPC */
904 dwError = RSetServiceStatus((RPC_SERVICE_STATUS_HANDLE)hServiceStatus,
905 lpServiceStatus);
906 }
907 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
908 {
909 dwError = ScmRpcStatusToWinError(RpcExceptionCode());
910 }
911 RpcEndExcept;
912
913 if (dwError != ERROR_SUCCESS)
914 {
915 ERR("ScmrSetServiceStatus() failed (Error %lu)\n", dwError);
916 SetLastError(dwError);
917 return FALSE;
918 }
919
920 TRACE("SetServiceStatus() done (ret %lu)\n", dwError);
921
922 return TRUE;
923 }
924
925
926 /**********************************************************************
927 * StartServiceCtrlDispatcherA
928 *
929 * @implemented
930 */
931 BOOL WINAPI
932 StartServiceCtrlDispatcherA(const SERVICE_TABLE_ENTRYA *lpServiceStartTable)
933 {
934 ULONG i;
935 HANDLE hPipe;
936 DWORD dwError;
937 PSCM_CONTROL_PACKET ControlPacket;
938 DWORD dwBufSize;
939 BOOL bRet = TRUE;
940
941 TRACE("StartServiceCtrlDispatcherA() called\n");
942
943 i = 0;
944 while (lpServiceStartTable[i].lpServiceProc != NULL)
945 {
946 i++;
947 }
948
949 dwActiveServiceCount = i;
950 lpActiveServices = RtlAllocateHeap(RtlGetProcessHeap(),
951 HEAP_ZERO_MEMORY,
952 dwActiveServiceCount * sizeof(ACTIVE_SERVICE));
953 if (lpActiveServices == NULL)
954 {
955 return FALSE;
956 }
957
958 /* Copy service names and start procedure */
959 for (i = 0; i < dwActiveServiceCount; i++)
960 {
961 RtlCreateUnicodeStringFromAsciiz(&lpActiveServices[i].ServiceName,
962 lpServiceStartTable[i].lpServiceName);
963 lpActiveServices[i].ServiceMain.A = lpServiceStartTable[i].lpServiceProc;
964 lpActiveServices[i].hServiceStatus = 0;
965 lpActiveServices[i].bUnicode = FALSE;
966 lpActiveServices[i].bOwnProcess = FALSE;
967 }
968
969 dwError = ScConnectControlPipe(&hPipe);
970 if (dwError != ERROR_SUCCESS)
971 {
972 bRet = FALSE;
973 goto done;
974 }
975
976 dwBufSize = sizeof(SCM_CONTROL_PACKET) +
977 (MAX_SERVICE_NAME_LENGTH + 1) * sizeof(WCHAR);
978
979 ControlPacket = RtlAllocateHeap(RtlGetProcessHeap(),
980 HEAP_ZERO_MEMORY,
981 dwBufSize);
982 if (ControlPacket == NULL)
983 {
984 bRet = FALSE;
985 goto done;
986 }
987
988 ScCreateStatusBinding();
989
990 ScServiceDispatcher(hPipe, ControlPacket, dwBufSize);
991
992 ScDestroyStatusBinding();
993
994 CloseHandle(hPipe);
995
996 /* Free the control packet */
997 RtlFreeHeap(RtlGetProcessHeap(), 0, ControlPacket);
998
999 done:
1000 /* Free the service table */
1001 for (i = 0; i < dwActiveServiceCount; i++)
1002 {
1003 RtlFreeUnicodeString(&lpActiveServices[i].ServiceName);
1004 }
1005 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
1006 lpActiveServices = NULL;
1007 dwActiveServiceCount = 0;
1008
1009 return bRet;
1010 }
1011
1012
1013 /**********************************************************************
1014 * StartServiceCtrlDispatcherW
1015 *
1016 * @implemented
1017 */
1018 BOOL WINAPI
1019 StartServiceCtrlDispatcherW(const SERVICE_TABLE_ENTRYW *lpServiceStartTable)
1020 {
1021 ULONG i;
1022 HANDLE hPipe;
1023 DWORD dwError;
1024 PSCM_CONTROL_PACKET ControlPacket;
1025 DWORD dwBufSize;
1026 BOOL bRet = TRUE;
1027
1028 TRACE("StartServiceCtrlDispatcherW() called\n");
1029
1030 i = 0;
1031 while (lpServiceStartTable[i].lpServiceProc != NULL)
1032 {
1033 i++;
1034 }
1035
1036 dwActiveServiceCount = i;
1037 lpActiveServices = RtlAllocateHeap(RtlGetProcessHeap(),
1038 HEAP_ZERO_MEMORY,
1039 dwActiveServiceCount * sizeof(ACTIVE_SERVICE));
1040 if (lpActiveServices == NULL)
1041 {
1042 return FALSE;
1043 }
1044
1045 /* Copy service names and start procedure */
1046 for (i = 0; i < dwActiveServiceCount; i++)
1047 {
1048 RtlCreateUnicodeString(&lpActiveServices[i].ServiceName,
1049 lpServiceStartTable[i].lpServiceName);
1050 lpActiveServices[i].ServiceMain.W = lpServiceStartTable[i].lpServiceProc;
1051 lpActiveServices[i].hServiceStatus = 0;
1052 lpActiveServices[i].bUnicode = TRUE;
1053 lpActiveServices[i].bOwnProcess = FALSE;
1054 }
1055
1056 dwError = ScConnectControlPipe(&hPipe);
1057 if (dwError != ERROR_SUCCESS)
1058 {
1059 bRet = FALSE;
1060 goto done;
1061 }
1062
1063 dwBufSize = sizeof(SCM_CONTROL_PACKET) +
1064 (MAX_SERVICE_NAME_LENGTH + 1) * sizeof(WCHAR);
1065
1066 ControlPacket = RtlAllocateHeap(RtlGetProcessHeap(),
1067 HEAP_ZERO_MEMORY,
1068 dwBufSize);
1069 if (ControlPacket == NULL)
1070 {
1071 bRet = FALSE;
1072 goto done;
1073 }
1074
1075 ScCreateStatusBinding();
1076
1077 ScServiceDispatcher(hPipe, ControlPacket, dwBufSize);
1078
1079 ScDestroyStatusBinding();
1080
1081 CloseHandle(hPipe);
1082
1083 /* Free the control packet */
1084 RtlFreeHeap(RtlGetProcessHeap(), 0, ControlPacket);
1085
1086 done:
1087 /* Free the service table */
1088 for (i = 0; i < dwActiveServiceCount; i++)
1089 {
1090 RtlFreeUnicodeString(&lpActiveServices[i].ServiceName);
1091 }
1092 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
1093 lpActiveServices = NULL;
1094 dwActiveServiceCount = 0;
1095
1096 return bRet;
1097 }
1098
1099 /* EOF */