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