[ADVAPI32] Code formatting + improve two traces.
[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 if (!NT_SUCCESS(Status))
233 {
234 ERR("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
235 return RtlNtStatusToDosError(Status);
236 }
237
238 swprintf(NtControlPipeName, L"\\\\.\\pipe\\net\\NtControlPipe%u", dwServiceCurrent);
239
240 if (!WaitNamedPipeW(NtControlPipeName, 30000))
241 {
242 ERR("WaitNamedPipe(%S) failed (Error %lu)\n", NtControlPipeName, GetLastError());
243 return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT;
244 }
245
246 *hPipe = CreateFileW(NtControlPipeName,
247 GENERIC_READ | GENERIC_WRITE,
248 FILE_SHARE_READ | FILE_SHARE_WRITE,
249 NULL,
250 OPEN_EXISTING,
251 FILE_ATTRIBUTE_NORMAL,
252 NULL);
253 if (*hPipe == INVALID_HANDLE_VALUE)
254 {
255 ERR("CreateFileW() failed for pipe %S (Error %lu)\n", NtControlPipeName, GetLastError());
256 return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT;
257 }
258
259 dwState = PIPE_READMODE_MESSAGE;
260 if (!SetNamedPipeHandleState(*hPipe, &dwState, NULL, NULL))
261 {
262 CloseHandle(*hPipe);
263 *hPipe = INVALID_HANDLE_VALUE;
264 return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT;
265 }
266
267 /* Pass the ProcessId to the SCM */
268 dwProcessId = GetCurrentProcessId();
269 WriteFile(*hPipe,
270 &dwProcessId,
271 sizeof(DWORD),
272 &dwBytesWritten,
273 NULL);
274
275 TRACE("Sent Process ID %lu\n", dwProcessId);
276
277 return ERROR_SUCCESS;
278 }
279
280
281 /*
282 * Ansi/Unicode argument layout of the vector passed to a service at startup,
283 * depending on the different versions of Windows considered:
284 *
285 * - XP/2003:
286 * [argv array of pointers][parameter 1][parameter 2]...[service name]
287 *
288 * - Vista:
289 * [argv array of pointers][align to 8 bytes]
290 * [parameter 1][parameter 2]...[service name]
291 *
292 * - Win7/8:
293 * [argv array of pointers][service name]
294 * [parameter 1][align to 4 bytes][parameter 2][align to 4 bytes]...
295 *
296 * Space for parameters and service name is always enough to store
297 * both the Ansi and the Unicode versions including NULL terminator.
298 */
299
300 static DWORD
301 ScBuildUnicodeArgsVector(PSCM_CONTROL_PACKET ControlPacket,
302 LPDWORD lpArgCount,
303 LPWSTR **lpArgVector)
304 {
305 PWSTR *lpVector;
306 PWSTR pszServiceName;
307 DWORD cbServiceName;
308 DWORD cbArguments;
309 DWORD cbTotal;
310 DWORD i;
311
312 if (ControlPacket == NULL || lpArgCount == NULL || lpArgVector == NULL)
313 return ERROR_INVALID_PARAMETER;
314
315 *lpArgCount = 0;
316 *lpArgVector = NULL;
317
318 /* Retrieve and count the start command line (NULL-terminated) */
319 pszServiceName = (PWSTR)((ULONG_PTR)ControlPacket + ControlPacket->dwServiceNameOffset);
320 cbServiceName = lstrlenW(pszServiceName) * sizeof(WCHAR) + sizeof(UNICODE_NULL);
321
322 /*
323 * The total size of the argument vector is equal to the entry for
324 * the service name, plus the size of the original argument vector.
325 */
326 cbTotal = sizeof(PWSTR) + cbServiceName;
327 if (ControlPacket->dwArgumentsCount > 0)
328 cbArguments = ControlPacket->dwSize - ControlPacket->dwArgumentsOffset;
329 else
330 cbArguments = 0;
331 cbTotal += cbArguments;
332
333 /* Allocate the new argument vector */
334 lpVector = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbTotal);
335 if (lpVector == NULL)
336 return ERROR_NOT_ENOUGH_MEMORY;
337
338 /*
339 * The first argument is reserved for the service name, which
340 * will be appended to the end of the argument string list.
341 */
342
343 /* Copy the remaining arguments */
344 if (ControlPacket->dwArgumentsCount > 0)
345 {
346 memcpy(&lpVector[1],
347 (PWSTR)((ULONG_PTR)ControlPacket + ControlPacket->dwArgumentsOffset),
348 cbArguments);
349
350 for (i = 0; i < ControlPacket->dwArgumentsCount; i++)
351 {
352 lpVector[i + 1] = (PWSTR)((ULONG_PTR)&lpVector[1] + (ULONG_PTR)lpVector[i + 1]);
353 TRACE("Unicode lpVector[%lu] = '%ls'\n", i + 1, lpVector[i + 1]);
354 }
355 }
356
357 /* Now copy the service name */
358 lpVector[0] = (PWSTR)((ULONG_PTR)&lpVector[1] + cbArguments);
359 memcpy(lpVector[0], pszServiceName, cbServiceName);
360 TRACE("Unicode lpVector[%lu] = '%ls'\n", 0, lpVector[0]);
361
362 *lpArgCount = ControlPacket->dwArgumentsCount + 1;
363 *lpArgVector = lpVector;
364
365 return ERROR_SUCCESS;
366 }
367
368
369 static DWORD
370 ScBuildAnsiArgsVector(PSCM_CONTROL_PACKET ControlPacket,
371 LPDWORD lpArgCount,
372 LPSTR **lpArgVector)
373 {
374 DWORD dwError;
375 NTSTATUS Status;
376 DWORD ArgCount, i;
377 PWSTR *lpVectorW;
378 PSTR *lpVectorA;
379 UNICODE_STRING UnicodeString;
380 ANSI_STRING AnsiString;
381
382 if (ControlPacket == NULL || lpArgCount == NULL || lpArgVector == NULL)
383 return ERROR_INVALID_PARAMETER;
384
385 *lpArgCount = 0;
386 *lpArgVector = NULL;
387
388 /* Build the UNICODE arguments vector */
389 dwError = ScBuildUnicodeArgsVector(ControlPacket, &ArgCount, &lpVectorW);
390 if (dwError != ERROR_SUCCESS)
391 return dwError;
392
393 /* Convert the vector to ANSI in place */
394 lpVectorA = (PSTR*)lpVectorW;
395 for (i = 0; i < ArgCount; i++)
396 {
397 RtlInitUnicodeString(&UnicodeString, lpVectorW[i]);
398 RtlInitEmptyAnsiString(&AnsiString, lpVectorA[i], UnicodeString.MaximumLength);
399 Status = RtlUnicodeStringToAnsiString(&AnsiString, &UnicodeString, FALSE);
400 if (!NT_SUCCESS(Status))
401 {
402 /* Failed to convert to ANSI; free the allocated vector and return */
403 dwError = RtlNtStatusToDosError(Status);
404 HeapFree(GetProcessHeap(), 0, lpVectorW);
405 return dwError;
406 }
407
408 /* NULL-terminate the string */
409 AnsiString.Buffer[AnsiString.Length / sizeof(CHAR)] = ANSI_NULL;
410
411 TRACE("Ansi lpVector[%lu] = '%s'\n", i, lpVectorA[i]);
412 }
413
414 *lpArgCount = ArgCount;
415 *lpArgVector = lpVectorA;
416
417 return ERROR_SUCCESS;
418 }
419
420
421 static DWORD
422 ScStartService(PACTIVE_SERVICE lpService,
423 PSCM_CONTROL_PACKET ControlPacket)
424 {
425 HANDLE ThreadHandle;
426 DWORD ThreadId;
427 DWORD dwError;
428 PSERVICE_THREAD_PARAMSA ThreadParamsA;
429 PSERVICE_THREAD_PARAMSW ThreadParamsW;
430
431 if (lpService == NULL || ControlPacket == NULL)
432 return ERROR_INVALID_PARAMETER;
433
434 TRACE("ScStartService(Size: %lu, Service: '%S') called\n",
435 ControlPacket->dwSize,
436 (PWSTR)((ULONG_PTR)ControlPacket + ControlPacket->dwServiceNameOffset));
437
438 /* Set the service status handle */
439 lpService->hServiceStatus = ControlPacket->hServiceStatus;
440
441 /* Build the arguments vector */
442 if (lpService->bUnicode != FALSE)
443 {
444 ThreadParamsW = HeapAlloc(GetProcessHeap(), 0, sizeof(*ThreadParamsW));
445 if (ThreadParamsW == NULL)
446 return ERROR_NOT_ENOUGH_MEMORY;
447 dwError = ScBuildUnicodeArgsVector(ControlPacket,
448 &ThreadParamsW->dwArgCount,
449 &ThreadParamsW->lpArgVector);
450 if (dwError != ERROR_SUCCESS)
451 {
452 HeapFree(GetProcessHeap(), 0, ThreadParamsW);
453 return dwError;
454 }
455 ThreadParamsW->lpServiceMain = lpService->ServiceMain.W;
456 ThreadHandle = CreateThread(NULL,
457 0,
458 ScServiceMainStubW,
459 ThreadParamsW,
460 0,
461 &ThreadId);
462 if (ThreadHandle == NULL)
463 {
464 if (ThreadParamsW->lpArgVector != NULL)
465 {
466 HeapFree(GetProcessHeap(), 0, ThreadParamsW->lpArgVector);
467 }
468 HeapFree(GetProcessHeap(), 0, ThreadParamsW);
469
470 return ERROR_SERVICE_NO_THREAD;
471 }
472
473 CloseHandle(ThreadHandle);
474 }
475 else
476 {
477 ThreadParamsA = HeapAlloc(GetProcessHeap(), 0, sizeof(*ThreadParamsA));
478 if (ThreadParamsA == NULL)
479 return ERROR_NOT_ENOUGH_MEMORY;
480 dwError = ScBuildAnsiArgsVector(ControlPacket,
481 &ThreadParamsA->dwArgCount,
482 &ThreadParamsA->lpArgVector);
483 if (dwError != ERROR_SUCCESS)
484 {
485 HeapFree(GetProcessHeap(), 0, ThreadParamsA);
486 return dwError;
487 }
488 ThreadParamsA->lpServiceMain = lpService->ServiceMain.A;
489 ThreadHandle = CreateThread(NULL,
490 0,
491 ScServiceMainStubA,
492 ThreadParamsA,
493 0,
494 &ThreadId);
495 if (ThreadHandle == NULL)
496 {
497 if (ThreadParamsA->lpArgVector != NULL)
498 {
499 HeapFree(GetProcessHeap(), 0, ThreadParamsA->lpArgVector);
500 }
501 HeapFree(GetProcessHeap(), 0, ThreadParamsA);
502
503 return ERROR_SERVICE_NO_THREAD;
504 }
505
506 CloseHandle(ThreadHandle);
507 }
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 bResult = RI_ScSetServiceBitsA((RPC_SERVICE_STATUS_HANDLE)hServiceStatus,
814 dwServiceBits,
815 bSetBitsOn,
816 bUpdateImmediately,
817 lpString);
818 }
819 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
820 {
821 SetLastError(ScmRpcStatusToWinError(RpcExceptionCode()));
822 bResult = FALSE;
823 }
824 RpcEndExcept;
825
826 return bResult;
827 }
828
829
830 /**********************************************************************
831 * I_ScSetServiceBitsW
832 *
833 * Undocumented
834 *
835 * @implemented
836 */
837 BOOL WINAPI
838 I_ScSetServiceBitsW(SERVICE_STATUS_HANDLE hServiceStatus,
839 DWORD dwServiceBits,
840 BOOL bSetBitsOn,
841 BOOL bUpdateImmediately,
842 LPWSTR lpString)
843 {
844 BOOL bResult;
845
846 RpcTryExcept
847 {
848 bResult = RI_ScSetServiceBitsW((RPC_SERVICE_STATUS_HANDLE)hServiceStatus,
849 dwServiceBits,
850 bSetBitsOn,
851 bUpdateImmediately,
852 lpString);
853 }
854 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
855 {
856 SetLastError(ScmRpcStatusToWinError(RpcExceptionCode()));
857 bResult = FALSE;
858 }
859 RpcEndExcept;
860
861 return bResult;
862 }
863
864
865 /**********************************************************************
866 * SetServiceBits
867 *
868 * @implemented
869 */
870 BOOL WINAPI
871 SetServiceBits(SERVICE_STATUS_HANDLE hServiceStatus,
872 DWORD dwServiceBits,
873 BOOL bSetBitsOn,
874 BOOL bUpdateImmediately)
875 {
876 return I_ScSetServiceBitsW(hServiceStatus,
877 dwServiceBits,
878 bSetBitsOn,
879 bUpdateImmediately,
880 NULL);
881 }
882
883
884 /**********************************************************************
885 * SetServiceStatus
886 *
887 * @implemented
888 */
889 BOOL WINAPI
890 SetServiceStatus(SERVICE_STATUS_HANDLE hServiceStatus,
891 LPSERVICE_STATUS lpServiceStatus)
892 {
893 DWORD dwError;
894
895 TRACE("SetServiceStatus(hServiceStatus %lu) called\n", hServiceStatus);
896
897 RpcTryExcept
898 {
899 dwError = RSetServiceStatus((RPC_SERVICE_STATUS_HANDLE)hServiceStatus,
900 lpServiceStatus);
901 }
902 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
903 {
904 dwError = ScmRpcStatusToWinError(RpcExceptionCode());
905 }
906 RpcEndExcept;
907
908 if (dwError != ERROR_SUCCESS)
909 {
910 ERR("RSetServiceStatus() failed (Error %lu)\n", dwError);
911 SetLastError(dwError);
912 return FALSE;
913 }
914
915 TRACE("SetServiceStatus() done (ret %lu)\n", dwError);
916
917 return TRUE;
918 }
919
920
921 /**********************************************************************
922 * StartServiceCtrlDispatcherA
923 *
924 * @implemented
925 */
926 BOOL WINAPI
927 StartServiceCtrlDispatcherA(const SERVICE_TABLE_ENTRYA *lpServiceStartTable)
928 {
929 ULONG i;
930 HANDLE hPipe;
931 DWORD dwError;
932 PSCM_CONTROL_PACKET ControlPacket;
933 DWORD dwBufSize;
934 BOOL bRet = TRUE;
935
936 TRACE("StartServiceCtrlDispatcherA() called\n");
937
938 i = 0;
939 while (lpServiceStartTable[i].lpServiceProc != NULL)
940 {
941 i++;
942 }
943
944 dwActiveServiceCount = i;
945 lpActiveServices = RtlAllocateHeap(RtlGetProcessHeap(),
946 HEAP_ZERO_MEMORY,
947 dwActiveServiceCount * sizeof(ACTIVE_SERVICE));
948 if (lpActiveServices == NULL)
949 {
950 return FALSE;
951 }
952
953 /* Copy service names and start procedure */
954 for (i = 0; i < dwActiveServiceCount; i++)
955 {
956 RtlCreateUnicodeStringFromAsciiz(&lpActiveServices[i].ServiceName,
957 lpServiceStartTable[i].lpServiceName);
958 lpActiveServices[i].ServiceMain.A = lpServiceStartTable[i].lpServiceProc;
959 lpActiveServices[i].hServiceStatus = 0;
960 lpActiveServices[i].bUnicode = FALSE;
961 lpActiveServices[i].bOwnProcess = FALSE;
962 }
963
964 dwError = ScConnectControlPipe(&hPipe);
965 if (dwError != ERROR_SUCCESS)
966 {
967 bRet = FALSE;
968 goto done;
969 }
970
971 dwBufSize = sizeof(SCM_CONTROL_PACKET) +
972 (MAX_SERVICE_NAME_LENGTH + 1) * sizeof(WCHAR);
973
974 ControlPacket = RtlAllocateHeap(RtlGetProcessHeap(),
975 HEAP_ZERO_MEMORY,
976 dwBufSize);
977 if (ControlPacket == NULL)
978 {
979 bRet = FALSE;
980 goto done;
981 }
982
983 ScCreateStatusBinding();
984
985 ScServiceDispatcher(hPipe, ControlPacket, dwBufSize);
986
987 ScDestroyStatusBinding();
988
989 CloseHandle(hPipe);
990
991 /* Free the control packet */
992 RtlFreeHeap(RtlGetProcessHeap(), 0, ControlPacket);
993
994 done:
995 /* Free the service table */
996 for (i = 0; i < dwActiveServiceCount; i++)
997 {
998 RtlFreeUnicodeString(&lpActiveServices[i].ServiceName);
999 }
1000 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
1001 lpActiveServices = NULL;
1002 dwActiveServiceCount = 0;
1003
1004 return bRet;
1005 }
1006
1007
1008 /**********************************************************************
1009 * StartServiceCtrlDispatcherW
1010 *
1011 * @implemented
1012 */
1013 BOOL WINAPI
1014 StartServiceCtrlDispatcherW(const SERVICE_TABLE_ENTRYW *lpServiceStartTable)
1015 {
1016 ULONG i;
1017 HANDLE hPipe;
1018 DWORD dwError;
1019 PSCM_CONTROL_PACKET ControlPacket;
1020 DWORD dwBufSize;
1021 BOOL bRet = TRUE;
1022
1023 TRACE("StartServiceCtrlDispatcherW() called\n");
1024
1025 i = 0;
1026 while (lpServiceStartTable[i].lpServiceProc != NULL)
1027 {
1028 i++;
1029 }
1030
1031 dwActiveServiceCount = i;
1032 lpActiveServices = RtlAllocateHeap(RtlGetProcessHeap(),
1033 HEAP_ZERO_MEMORY,
1034 dwActiveServiceCount * sizeof(ACTIVE_SERVICE));
1035 if (lpActiveServices == NULL)
1036 {
1037 return FALSE;
1038 }
1039
1040 /* Copy service names and start procedure */
1041 for (i = 0; i < dwActiveServiceCount; i++)
1042 {
1043 RtlCreateUnicodeString(&lpActiveServices[i].ServiceName,
1044 lpServiceStartTable[i].lpServiceName);
1045 lpActiveServices[i].ServiceMain.W = lpServiceStartTable[i].lpServiceProc;
1046 lpActiveServices[i].hServiceStatus = 0;
1047 lpActiveServices[i].bUnicode = TRUE;
1048 lpActiveServices[i].bOwnProcess = FALSE;
1049 }
1050
1051 dwError = ScConnectControlPipe(&hPipe);
1052 if (dwError != ERROR_SUCCESS)
1053 {
1054 bRet = FALSE;
1055 goto done;
1056 }
1057
1058 dwBufSize = sizeof(SCM_CONTROL_PACKET) +
1059 (MAX_SERVICE_NAME_LENGTH + 1) * sizeof(WCHAR);
1060
1061 ControlPacket = RtlAllocateHeap(RtlGetProcessHeap(),
1062 HEAP_ZERO_MEMORY,
1063 dwBufSize);
1064 if (ControlPacket == NULL)
1065 {
1066 bRet = FALSE;
1067 goto done;
1068 }
1069
1070 ScCreateStatusBinding();
1071
1072 ScServiceDispatcher(hPipe, ControlPacket, dwBufSize);
1073
1074 ScDestroyStatusBinding();
1075
1076 CloseHandle(hPipe);
1077
1078 /* Free the control packet */
1079 RtlFreeHeap(RtlGetProcessHeap(), 0, ControlPacket);
1080
1081 done:
1082 /* Free the service table */
1083 for (i = 0; i < dwActiveServiceCount; i++)
1084 {
1085 RtlFreeUnicodeString(&lpActiveServices[i].ServiceName);
1086 }
1087 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
1088 lpActiveServices = NULL;
1089 dwActiveServiceCount = 0;
1090
1091 return bRet;
1092 }
1093
1094 /* EOF */