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