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