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