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