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>
13 /* INCLUDES ******************************************************************/
16 #include "wine/debug.h"
18 WINE_DEFAULT_DEBUG_CHANNEL(advapi
);
21 /* TYPES *********************************************************************/
23 typedef struct _ACTIVE_SERVICE
25 CLIENT_HANDLE hService
;
26 UNICODE_STRING ServiceName
;
29 LPSERVICE_MAIN_FUNCTIONA lpFuncA
;
30 LPSERVICE_MAIN_FUNCTIONW lpFuncW
;
32 LPHANDLER_FUNCTION HandlerFunction
;
33 LPHANDLER_FUNCTION_EX HandlerFunctionEx
;
34 LPVOID HandlerContext
;
35 SERVICE_STATUS ServiceStatus
;
38 } ACTIVE_SERVICE
, *PACTIVE_SERVICE
;
41 /* GLOBALS *******************************************************************/
43 static DWORD dwActiveServiceCount
= 0;
44 static PACTIVE_SERVICE lpActiveServices
= NULL
;
47 /* FUNCTIONS *****************************************************************/
49 static PACTIVE_SERVICE
50 ScLookupServiceByServiceName(LPCWSTR lpServiceName
)
54 for (i
= 0; i
< dwActiveServiceCount
; i
++)
56 if (_wcsicmp(lpActiveServices
[i
].ServiceName
.Buffer
, lpServiceName
) == 0)
58 return &lpActiveServices
[i
];
62 SetLastError(ERROR_SERVICE_DOES_NOT_EXIST
);
69 ScServiceMainStub(LPVOID Context
)
71 PACTIVE_SERVICE lpService
;
77 lpService
= (PACTIVE_SERVICE
)Context
;
79 TRACE("ScServiceMainStub() called\n");
82 lpPtr
= lpService
->Arguments
;
85 TRACE("arg: %S\n", lpPtr
);
86 dwLen
= wcslen(lpPtr
) + 1;
91 TRACE("dwArgCount: %ld\ndwLength: %ld\n", dwArgCount
, dwLength
);
93 /* Build the argument vector and call the main service routine */
94 if (lpService
->bUnicode
)
99 lpArgVector
= HeapAlloc(GetProcessHeap(),
101 (dwArgCount
+ 1) * sizeof(LPWSTR
));
102 if (lpArgVector
== NULL
)
103 return ERROR_OUTOFMEMORY
;
106 Ptr
= lpService
->Arguments
;
109 lpArgVector
[dwArgCount
] = Ptr
;
112 Ptr
+= (wcslen(Ptr
) + 1);
114 lpArgVector
[dwArgCount
] = NULL
;
116 (lpService
->Main
.lpFuncW
)(dwArgCount
, lpArgVector
);
118 HeapFree(GetProcessHeap(),
129 AnsiLength
= WideCharToMultiByte(CP_ACP
,
131 lpService
->Arguments
,
138 return ERROR_INVALID_PARAMETER
; /* ? */
140 AnsiString
= HeapAlloc(GetProcessHeap(),
143 if (AnsiString
== NULL
)
144 return ERROR_OUTOFMEMORY
;
146 WideCharToMultiByte(CP_ACP
,
148 lpService
->Arguments
,
155 AnsiString
[AnsiLength
] = ANSI_NULL
;
157 lpArgVector
= HeapAlloc(GetProcessHeap(),
159 (dwArgCount
+ 1) * sizeof(LPSTR
));
160 if (lpArgVector
== NULL
)
162 HeapFree(GetProcessHeap(),
165 return ERROR_OUTOFMEMORY
;
172 lpArgVector
[dwArgCount
] = Ptr
;
175 Ptr
+= (strlen(Ptr
) + 1);
177 lpArgVector
[dwArgCount
] = NULL
;
179 (lpService
->Main
.lpFuncA
)(dwArgCount
, lpArgVector
);
181 HeapFree(GetProcessHeap(),
184 HeapFree(GetProcessHeap(),
189 return ERROR_SUCCESS
;
194 ScConnectControlPipe(HANDLE
*hPipe
)
196 DWORD dwBytesWritten
;
198 DWORD dwServiceCurrent
= 0;
200 WCHAR NtControlPipeName
[MAX_PATH
+ 1];
201 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
203 /* Get the service number and create the named pipe */
204 RtlZeroMemory(&QueryTable
,
207 QueryTable
[0].Name
= L
"";
208 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
209 QueryTable
[0].EntryContext
= &dwServiceCurrent
;
211 Status
= RtlQueryRegistryValues(RTL_REGISTRY_CONTROL
,
217 if (!NT_SUCCESS(Status
))
219 ERR("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
220 return RtlNtStatusToDosError(Status
);
223 swprintf(NtControlPipeName
, L
"\\\\.\\pipe\\net\\NtControlPipe%u", dwServiceCurrent
);
225 if (!WaitNamedPipeW(NtControlPipeName
, 15000))
227 ERR("WaitNamedPipe(%S) failed (Error %lu)\n", NtControlPipeName
, GetLastError());
228 return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT
;
231 *hPipe
= CreateFileW(NtControlPipeName
,
232 GENERIC_READ
| GENERIC_WRITE
,
236 FILE_ATTRIBUTE_NORMAL
,
238 if (*hPipe
== INVALID_HANDLE_VALUE
)
240 ERR("CreateFileW() failed (Error %lu)\n", GetLastError());
241 return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT
;
244 dwState
= PIPE_READMODE_MESSAGE
;
245 if (!SetNamedPipeHandleState(*hPipe
, &dwState
, NULL
, NULL
))
248 *hPipe
= INVALID_HANDLE_VALUE
;
249 return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT
;
252 /* Share the SERVICE_HANDLE handle with the SCM */
254 (DWORD
*)&lpActiveServices
->hService
,
255 sizeof(CLIENT_HANDLE
),
259 TRACE("Sent SERVICE_HANDLE %lu\n", lpActiveServices
->hService
);
261 return ERROR_SUCCESS
;
266 ScStartService(PSCM_CONTROL_PACKET ControlPacket
)
268 PACTIVE_SERVICE lpService
;
272 TRACE("ScStartService() called\n");
273 TRACE("client handle: %lu\n", ControlPacket
->hClient
);
274 TRACE("Size: %lu\n", ControlPacket
->dwSize
);
275 TRACE("Service: %S\n", &ControlPacket
->szArguments
[0]);
277 lpService
= (PACTIVE_SERVICE
)ControlPacket
->hClient
;
278 if (lpService
== NULL
)
280 TRACE("Service not found\n");
281 return ERROR_SERVICE_DOES_NOT_EXIST
;
284 lpService
->Arguments
= HeapAlloc(GetProcessHeap(),
286 (ControlPacket
->dwSize
+ 1) * sizeof(WCHAR
));
287 if (lpService
->Arguments
== NULL
)
288 return ERROR_OUTOFMEMORY
;
290 memcpy(lpService
->Arguments
,
291 ControlPacket
->szArguments
,
292 ControlPacket
->dwSize
* sizeof(WCHAR
));
294 /* invoke the services entry point and implement the command loop */
295 ThreadHandle
= CreateThread(NULL
,
301 if (ThreadHandle
== NULL
)
302 return ERROR_SERVICE_NO_THREAD
;
304 ResumeThread(ThreadHandle
);
305 CloseHandle(ThreadHandle
);
307 return ERROR_SUCCESS
;
312 ScControlService(PSCM_CONTROL_PACKET ControlPacket
)
314 PACTIVE_SERVICE lpService
;
316 TRACE("ScControlService() called\n");
317 TRACE("Size: %lu\n", ControlPacket
->dwSize
);
318 TRACE("Service: %S\n", &ControlPacket
->szArguments
[0]);
320 lpService
= (PACTIVE_SERVICE
)ControlPacket
->hClient
;
321 if (lpService
== NULL
)
323 TRACE("Service not found\n");
324 return ERROR_SERVICE_DOES_NOT_EXIST
;
327 if (lpService
->HandlerFunction
)
329 (lpService
->HandlerFunction
)(ControlPacket
->dwControl
);
331 else if (lpService
->HandlerFunctionEx
)
333 /* FIXME: send correct params */
334 (lpService
->HandlerFunctionEx
)(ControlPacket
->dwControl
, 0, NULL
, NULL
);
337 if (ControlPacket
->dwControl
== SERVICE_CONTROL_STOP
)
339 HeapFree(GetProcessHeap(),
341 lpService
->Arguments
);
344 TRACE("ScControlService() done\n");
346 return ERROR_SUCCESS
;
351 ScServiceDispatcher(HANDLE hPipe
,
355 PSCM_CONTROL_PACKET ControlPacket
;
358 DWORD dwRunningServices
= 0;
360 TRACE("ScDispatcherLoop() called\n");
362 ControlPacket
= HeapAlloc(GetProcessHeap(),
365 if (ControlPacket
== NULL
)
370 /* Read command from the control pipe */
371 bResult
= ReadFile(hPipe
,
376 if (bResult
== FALSE
)
378 ERR("Pipe read failed (Error: %lu)\n", GetLastError());
382 /* Execute command */
383 switch (ControlPacket
->dwControl
)
385 case SERVICE_CONTROL_START
:
386 TRACE("Start command - recieved SERVICE_CONTROL_START\n");
387 if (ScStartService(ControlPacket
) == ERROR_SUCCESS
)
391 case SERVICE_CONTROL_STOP
:
392 TRACE("Stop command - recieved SERVICE_CONTROL_STOP\n");
393 if (ScControlService(ControlPacket
) == ERROR_SUCCESS
)
398 TRACE("Unknown command %lu", ControlPacket
->dwControl
);
402 if (dwRunningServices
== 0)
406 HeapFree(GetProcessHeap(),
414 /**********************************************************************
415 * RegisterServiceCtrlHandlerA
419 SERVICE_STATUS_HANDLE WINAPI
420 RegisterServiceCtrlHandlerA(LPCSTR lpServiceName
,
421 LPHANDLER_FUNCTION lpHandlerProc
)
423 ANSI_STRING ServiceNameA
;
424 UNICODE_STRING ServiceNameU
;
425 SERVICE_STATUS_HANDLE SHandle
;
427 RtlInitAnsiString(&ServiceNameA
, (LPSTR
)lpServiceName
);
428 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ServiceNameU
, &ServiceNameA
, TRUE
)))
430 SetLastError(ERROR_OUTOFMEMORY
);
431 return (SERVICE_STATUS_HANDLE
)0;
434 SHandle
= RegisterServiceCtrlHandlerW(ServiceNameU
.Buffer
,
437 RtlFreeUnicodeString(&ServiceNameU
);
443 /**********************************************************************
444 * RegisterServiceCtrlHandlerW
448 SERVICE_STATUS_HANDLE WINAPI
449 RegisterServiceCtrlHandlerW(LPCWSTR lpServiceName
,
450 LPHANDLER_FUNCTION lpHandlerProc
)
452 PACTIVE_SERVICE Service
;
454 Service
= ScLookupServiceByServiceName((LPWSTR
)lpServiceName
);
457 return (SERVICE_STATUS_HANDLE
)NULL
;
460 Service
->HandlerFunction
= lpHandlerProc
;
461 Service
->HandlerFunctionEx
= NULL
;
463 TRACE("RegisterServiceCtrlHandler returning %lu\n", Service
->hService
);
465 return (SERVICE_STATUS_HANDLE
)Service
->hService
;
469 /**********************************************************************
470 * RegisterServiceCtrlHandlerExA
474 SERVICE_STATUS_HANDLE WINAPI
475 RegisterServiceCtrlHandlerExA(LPCSTR lpServiceName
,
476 LPHANDLER_FUNCTION_EX lpHandlerProc
,
479 ANSI_STRING ServiceNameA
;
480 UNICODE_STRING ServiceNameU
;
481 SERVICE_STATUS_HANDLE SHandle
;
483 RtlInitAnsiString(&ServiceNameA
, (LPSTR
)lpServiceName
);
484 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ServiceNameU
, &ServiceNameA
, TRUE
)))
486 SetLastError(ERROR_OUTOFMEMORY
);
487 return (SERVICE_STATUS_HANDLE
)0;
490 SHandle
= RegisterServiceCtrlHandlerExW(ServiceNameU
.Buffer
,
494 RtlFreeUnicodeString(&ServiceNameU
);
500 /**********************************************************************
501 * RegisterServiceCtrlHandlerExW
505 SERVICE_STATUS_HANDLE WINAPI
506 RegisterServiceCtrlHandlerExW(LPCWSTR lpServiceName
,
507 LPHANDLER_FUNCTION_EX lpHandlerProc
,
510 PACTIVE_SERVICE Service
;
512 Service
= ScLookupServiceByServiceName(lpServiceName
);
515 return (SERVICE_STATUS_HANDLE
)NULL
;
518 Service
->HandlerFunction
= NULL
;
519 Service
->HandlerFunctionEx
= lpHandlerProc
;
520 Service
->HandlerContext
= lpContext
;
522 TRACE("RegisterServiceCtrlHandlerEx returning %lu", Service
->hService
);
524 return (SERVICE_STATUS_HANDLE
)Service
->hService
;
528 /**********************************************************************
529 * I_ScSetServiceBitsA
536 I_ScSetServiceBitsA(SERVICE_STATUS_HANDLE hServiceStatus
,
539 BOOL bUpdateImmediately
,
546 /* Call to services.exe using RPC */
547 bResult
= RI_ScSetServiceBitsA((RPC_SERVICE_STATUS_HANDLE
)hServiceStatus
,
553 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
555 SetLastError(ScmRpcStatusToWinError(RpcExceptionCode()));
564 /**********************************************************************
565 * I_ScSetServiceBitsW
572 I_ScSetServiceBitsW(SERVICE_STATUS_HANDLE hServiceStatus
,
575 BOOL bUpdateImmediately
,
582 /* Call to services.exe using RPC */
583 bResult
= RI_ScSetServiceBitsW((RPC_SERVICE_STATUS_HANDLE
)hServiceStatus
,
589 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
591 SetLastError(ScmRpcStatusToWinError(RpcExceptionCode()));
600 /**********************************************************************
606 SetServiceBits(SERVICE_STATUS_HANDLE hServiceStatus
,
609 BOOL bUpdateImmediately
)
611 return I_ScSetServiceBitsW(hServiceStatus
,
619 /**********************************************************************
625 SetServiceStatus(SERVICE_STATUS_HANDLE hServiceStatus
,
626 LPSERVICE_STATUS lpServiceStatus
)
630 TRACE("SetServiceStatus() called\n");
631 TRACE("hServiceStatus %lu\n", hServiceStatus
);
633 /* Call to services.exe using RPC */
634 dwError
= RSetServiceStatus((RPC_SERVICE_STATUS_HANDLE
)hServiceStatus
,
636 if (dwError
!= ERROR_SUCCESS
)
638 ERR("ScmrSetServiceStatus() failed (Error %lu)\n", dwError
);
639 SetLastError(dwError
);
643 TRACE("SetServiceStatus() done (ret %lu)\n", dwError
);
649 /**********************************************************************
650 * StartServiceCtrlDispatcherA
655 StartServiceCtrlDispatcherA(LPSERVICE_TABLE_ENTRYA lpServiceStartTable
)
660 PUCHAR lpMessageBuffer
;
662 TRACE("StartServiceCtrlDispatcherA() called\n");
665 while (lpServiceStartTable
[i
].lpServiceProc
!= NULL
)
670 dwActiveServiceCount
= i
;
671 lpActiveServices
= RtlAllocateHeap(RtlGetProcessHeap(),
673 dwActiveServiceCount
* sizeof(ACTIVE_SERVICE
));
674 if (lpActiveServices
== NULL
)
679 /* Copy service names and start procedure */
680 for (i
= 0; i
< dwActiveServiceCount
; i
++)
682 RtlCreateUnicodeStringFromAsciiz(&lpActiveServices
[i
].ServiceName
,
683 lpServiceStartTable
[i
].lpServiceName
);
684 lpActiveServices
[i
].Main
.lpFuncA
= lpServiceStartTable
[i
].lpServiceProc
;
685 lpActiveServices
[i
].hService
= (CLIENT_HANDLE
)&lpActiveServices
[i
];
686 lpActiveServices
[i
].bUnicode
= FALSE
;
689 dwError
= ScConnectControlPipe(&hPipe
);
690 if (dwError
!= ERROR_SUCCESS
)
692 /* Free the service table */
693 for (i
= 0; i
< dwActiveServiceCount
; i
++)
695 RtlFreeUnicodeString(&lpActiveServices
[i
].ServiceName
);
697 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices
);
698 lpActiveServices
= NULL
;
699 dwActiveServiceCount
= 0;
703 lpMessageBuffer
= RtlAllocateHeap(RtlGetProcessHeap(),
706 if (lpMessageBuffer
== NULL
)
708 /* Free the service table */
709 for (i
= 0; i
< dwActiveServiceCount
; i
++)
711 RtlFreeUnicodeString(&lpActiveServices
[i
].ServiceName
);
713 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices
);
714 lpActiveServices
= NULL
;
715 dwActiveServiceCount
= 0;
720 ScServiceDispatcher(hPipe
, lpMessageBuffer
, 256);
723 /* Free the message buffer */
724 RtlFreeHeap(RtlGetProcessHeap(), 0, lpMessageBuffer
);
726 /* Free the service table */
727 for (i
= 0; i
< dwActiveServiceCount
; i
++)
729 RtlFreeUnicodeString(&lpActiveServices
[i
].ServiceName
);
731 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices
);
732 lpActiveServices
= NULL
;
733 dwActiveServiceCount
= 0;
739 /**********************************************************************
740 * StartServiceCtrlDispatcherW
745 StartServiceCtrlDispatcherW(LPSERVICE_TABLE_ENTRYW lpServiceStartTable
)
750 PUCHAR lpMessageBuffer
;
752 TRACE("StartServiceCtrlDispatcherW() called\n");
755 while (lpServiceStartTable
[i
].lpServiceProc
!= NULL
)
760 dwActiveServiceCount
= i
;
761 lpActiveServices
= RtlAllocateHeap(RtlGetProcessHeap(),
763 dwActiveServiceCount
* sizeof(ACTIVE_SERVICE
));
764 if (lpActiveServices
== NULL
)
769 /* Copy service names and start procedure */
770 for (i
= 0; i
< dwActiveServiceCount
; i
++)
772 RtlCreateUnicodeString(&lpActiveServices
[i
].ServiceName
,
773 lpServiceStartTable
[i
].lpServiceName
);
774 lpActiveServices
[i
].Main
.lpFuncW
= lpServiceStartTable
[i
].lpServiceProc
;
775 lpActiveServices
[i
].hService
= (CLIENT_HANDLE
)&lpActiveServices
[i
];
776 lpActiveServices
[i
].bUnicode
= TRUE
;
779 dwError
= ScConnectControlPipe(&hPipe
);
780 if (dwError
!= ERROR_SUCCESS
)
782 /* Free the service table */
783 for (i
= 0; i
< dwActiveServiceCount
; i
++)
785 RtlFreeUnicodeString(&lpActiveServices
[i
].ServiceName
);
787 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices
);
788 lpActiveServices
= NULL
;
789 dwActiveServiceCount
= 0;
793 lpMessageBuffer
= RtlAllocateHeap(RtlGetProcessHeap(),
796 if (lpMessageBuffer
== NULL
)
798 /* Free the service table */
799 for (i
= 0; i
< dwActiveServiceCount
; i
++)
801 RtlFreeUnicodeString(&lpActiveServices
[i
].ServiceName
);
803 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices
);
804 lpActiveServices
= NULL
;
805 dwActiveServiceCount
= 0;
810 ScServiceDispatcher(hPipe
, lpMessageBuffer
, 256);
813 /* Free the message buffer */
814 RtlFreeHeap(RtlGetProcessHeap(), 0, lpMessageBuffer
);
816 /* Free the service table */
817 for (i
= 0; i
< dwActiveServiceCount
; i
++)
819 RtlFreeUnicodeString(&lpActiveServices
[i
].ServiceName
);
821 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices
);
822 lpActiveServices
= NULL
;
823 dwActiveServiceCount
= 0;