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