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 SERVICE_STATUS_HANDLE hServiceStatus
;
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
;
37 } ACTIVE_SERVICE
, *PACTIVE_SERVICE
;
40 /* GLOBALS *******************************************************************/
42 static DWORD dwActiveServiceCount
= 0;
43 static PACTIVE_SERVICE lpActiveServices
= NULL
;
44 static handle_t hStatusBinding
= NULL
;
47 /* FUNCTIONS *****************************************************************/
50 RPC_SERVICE_STATUS_HANDLE_bind(RPC_SERVICE_STATUS_HANDLE hServiceStatus
)
52 return hStatusBinding
;
57 RPC_SERVICE_STATUS_HANDLE_unbind(RPC_SERVICE_STATUS_HANDLE hServiceStatus
,
64 ScCreateStatusBinding(VOID
)
66 LPWSTR pszStringBinding
;
69 TRACE("ScCreateStatusBinding() called\n");
71 status
= RpcStringBindingComposeW(NULL
,
77 if (status
!= RPC_S_OK
)
79 ERR("RpcStringBindingCompose returned 0x%x\n", status
);
83 /* Set the binding handle that will be used to bind to the server. */
84 status
= RpcBindingFromStringBindingW(pszStringBinding
,
86 if (status
!= RPC_S_OK
)
88 ERR("RpcBindingFromStringBinding returned 0x%x\n", status
);
91 status
= RpcStringFreeW(&pszStringBinding
);
92 if (status
!= RPC_S_OK
)
94 ERR("RpcStringFree returned 0x%x\n", status
);
102 ScDestroyStatusBinding(VOID
)
106 TRACE("ScDestroyStatusBinding() called\n");
108 if (hStatusBinding
== NULL
)
111 status
= RpcBindingFree(&hStatusBinding
);
112 if (status
!= RPC_S_OK
)
114 ERR("RpcBindingFree returned 0x%x\n", status
);
118 hStatusBinding
= NULL
;
125 static PACTIVE_SERVICE
126 ScLookupServiceByServiceName(LPCWSTR lpServiceName
)
130 for (i
= 0; i
< dwActiveServiceCount
; i
++)
132 if (_wcsicmp(lpActiveServices
[i
].ServiceName
.Buffer
, lpServiceName
) == 0)
134 return &lpActiveServices
[i
];
138 SetLastError(ERROR_SERVICE_DOES_NOT_EXIST
);
145 ScServiceMainStub(LPVOID Context
)
147 PACTIVE_SERVICE lpService
;
148 DWORD dwArgCount
= 0;
153 lpService
= (PACTIVE_SERVICE
)Context
;
155 TRACE("ScServiceMainStub() called\n");
157 /* Count arguments */
158 lpPtr
= lpService
->Arguments
;
161 TRACE("arg: %S\n", lpPtr
);
162 dwLen
= wcslen(lpPtr
) + 1;
167 TRACE("dwArgCount: %ld\ndwLength: %ld\n", dwArgCount
, dwLength
);
169 /* Build the argument vector and call the main service routine */
170 if (lpService
->bUnicode
)
175 lpArgVector
= HeapAlloc(GetProcessHeap(),
177 (dwArgCount
+ 1) * sizeof(LPWSTR
));
178 if (lpArgVector
== NULL
)
179 return ERROR_OUTOFMEMORY
;
182 Ptr
= lpService
->Arguments
;
185 lpArgVector
[dwArgCount
] = Ptr
;
188 Ptr
+= (wcslen(Ptr
) + 1);
190 lpArgVector
[dwArgCount
] = NULL
;
192 (lpService
->Main
.lpFuncW
)(dwArgCount
, lpArgVector
);
194 HeapFree(GetProcessHeap(),
205 AnsiLength
= WideCharToMultiByte(CP_ACP
,
207 lpService
->Arguments
,
214 return ERROR_INVALID_PARAMETER
; /* ? */
216 AnsiString
= HeapAlloc(GetProcessHeap(),
219 if (AnsiString
== NULL
)
220 return ERROR_OUTOFMEMORY
;
222 WideCharToMultiByte(CP_ACP
,
224 lpService
->Arguments
,
231 AnsiString
[AnsiLength
] = ANSI_NULL
;
233 lpArgVector
= HeapAlloc(GetProcessHeap(),
235 (dwArgCount
+ 1) * sizeof(LPSTR
));
236 if (lpArgVector
== NULL
)
238 HeapFree(GetProcessHeap(),
241 return ERROR_OUTOFMEMORY
;
248 lpArgVector
[dwArgCount
] = Ptr
;
251 Ptr
+= (strlen(Ptr
) + 1);
253 lpArgVector
[dwArgCount
] = NULL
;
255 (lpService
->Main
.lpFuncA
)(dwArgCount
, lpArgVector
);
257 HeapFree(GetProcessHeap(),
260 HeapFree(GetProcessHeap(),
265 return ERROR_SUCCESS
;
270 ScConnectControlPipe(HANDLE
*hPipe
)
272 DWORD dwBytesWritten
;
274 DWORD dwServiceCurrent
= 0;
276 WCHAR NtControlPipeName
[MAX_PATH
+ 1];
277 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
280 /* Get the service number and create the named pipe */
281 RtlZeroMemory(&QueryTable
,
284 QueryTable
[0].Name
= L
"";
285 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
286 QueryTable
[0].EntryContext
= &dwServiceCurrent
;
288 Status
= RtlQueryRegistryValues(RTL_REGISTRY_CONTROL
,
294 if (!NT_SUCCESS(Status
))
296 ERR("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
297 return RtlNtStatusToDosError(Status
);
300 swprintf(NtControlPipeName
, L
"\\\\.\\pipe\\net\\NtControlPipe%u", dwServiceCurrent
);
302 if (!WaitNamedPipeW(NtControlPipeName
, 15000))
304 ERR("WaitNamedPipe(%S) failed (Error %lu)\n", NtControlPipeName
, GetLastError());
305 return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT
;
308 *hPipe
= CreateFileW(NtControlPipeName
,
309 GENERIC_READ
| GENERIC_WRITE
,
313 FILE_ATTRIBUTE_NORMAL
,
315 if (*hPipe
== INVALID_HANDLE_VALUE
)
317 ERR("CreateFileW() failed for pipe %S (Error %lu)\n", NtControlPipeName
, GetLastError());
318 return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT
;
321 dwState
= PIPE_READMODE_MESSAGE
;
322 if (!SetNamedPipeHandleState(*hPipe
, &dwState
, NULL
, NULL
))
325 *hPipe
= INVALID_HANDLE_VALUE
;
326 return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT
;
329 /* Pass the ProcessId to the SCM */
330 dwProcessId
= GetCurrentProcessId();
337 TRACE("Sent Process ID %lu\n", dwProcessId
);
339 return ERROR_SUCCESS
;
344 ScStartService(PACTIVE_SERVICE lpService
,
345 PSCM_CONTROL_PACKET ControlPacket
)
350 TRACE("ScStartService() called\n");
351 TRACE("Size: %lu\n", ControlPacket
->dwSize
);
352 TRACE("Service: %S\n", &ControlPacket
->szArguments
[0]);
354 /* Set the service status handle */
355 lpService
->hServiceStatus
= ControlPacket
->hServiceStatus
;
357 lpService
->Arguments
= HeapAlloc(GetProcessHeap(),
359 (ControlPacket
->dwSize
+ 1) * sizeof(WCHAR
));
360 if (lpService
->Arguments
== NULL
)
361 return ERROR_OUTOFMEMORY
;
363 memcpy(lpService
->Arguments
,
364 ControlPacket
->szArguments
,
365 ControlPacket
->dwSize
* sizeof(WCHAR
));
367 /* invoke the services entry point and implement the command loop */
368 ThreadHandle
= CreateThread(NULL
,
374 if (ThreadHandle
== NULL
)
375 return ERROR_SERVICE_NO_THREAD
;
377 ResumeThread(ThreadHandle
);
378 CloseHandle(ThreadHandle
);
380 return ERROR_SUCCESS
;
385 ScControlService(PACTIVE_SERVICE lpService
,
386 PSCM_CONTROL_PACKET ControlPacket
)
388 TRACE("ScControlService() called\n");
389 TRACE("Size: %lu\n", ControlPacket
->dwSize
);
390 TRACE("Service: %S\n", &ControlPacket
->szArguments
[0]);
392 if (lpService
->HandlerFunction
)
394 (lpService
->HandlerFunction
)(ControlPacket
->dwControl
);
396 else if (lpService
->HandlerFunctionEx
)
398 /* FIXME: send correct params */
399 (lpService
->HandlerFunctionEx
)(ControlPacket
->dwControl
, 0, NULL
, NULL
);
402 if (ControlPacket
->dwControl
== SERVICE_CONTROL_STOP
)
404 HeapFree(GetProcessHeap(),
406 lpService
->Arguments
);
409 TRACE("ScControlService() done\n");
411 return ERROR_SUCCESS
;
416 ScServiceDispatcher(HANDLE hPipe
,
420 PSCM_CONTROL_PACKET ControlPacket
;
423 DWORD dwRunningServices
= 0;
424 LPWSTR lpServiceName
;
425 PACTIVE_SERVICE lpService
;
426 SCM_REPLY_PACKET ReplyPacket
;
429 TRACE("ScDispatcherLoop() called\n");
431 ControlPacket
= HeapAlloc(GetProcessHeap(),
434 if (ControlPacket
== NULL
)
439 /* Read command from the control pipe */
440 bResult
= ReadFile(hPipe
,
445 if (bResult
== FALSE
)
447 ERR("Pipe read failed (Error: %lu)\n", GetLastError());
451 lpServiceName
= &ControlPacket
->szArguments
[0];
452 TRACE("Service: %S\n", lpServiceName
);
454 lpService
= ScLookupServiceByServiceName(lpServiceName
);
455 if (lpService
!= NULL
)
457 /* Execute command */
458 switch (ControlPacket
->dwControl
)
460 case SERVICE_CONTROL_START
:
461 TRACE("Start command - recieved SERVICE_CONTROL_START\n");
462 dwError
= ScStartService(lpService
, ControlPacket
);
463 if (dwError
== ERROR_SUCCESS
)
467 case SERVICE_CONTROL_STOP
:
468 TRACE("Stop command - recieved SERVICE_CONTROL_STOP\n");
469 dwError
= ScControlService(lpService
, ControlPacket
);
470 if (dwError
== ERROR_SUCCESS
)
475 TRACE("Command %lu received", ControlPacket
->dwControl
);
476 dwError
= ScControlService(lpService
, ControlPacket
);
482 dwError
= ERROR_SERVICE_DOES_NOT_EXIST
;
485 ReplyPacket
.dwError
= dwError
;
487 /* Send the reply packet */
488 bResult
= WriteFile(hPipe
,
493 if (bResult
== FALSE
)
495 ERR("Pipe write failed (Error: %lu)\n", GetLastError());
499 if (dwRunningServices
== 0)
503 HeapFree(GetProcessHeap(),
511 /**********************************************************************
512 * RegisterServiceCtrlHandlerA
516 SERVICE_STATUS_HANDLE WINAPI
517 RegisterServiceCtrlHandlerA(LPCSTR lpServiceName
,
518 LPHANDLER_FUNCTION lpHandlerProc
)
520 ANSI_STRING ServiceNameA
;
521 UNICODE_STRING ServiceNameU
;
522 SERVICE_STATUS_HANDLE SHandle
;
524 RtlInitAnsiString(&ServiceNameA
, (LPSTR
)lpServiceName
);
525 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ServiceNameU
, &ServiceNameA
, TRUE
)))
527 SetLastError(ERROR_OUTOFMEMORY
);
528 return (SERVICE_STATUS_HANDLE
)0;
531 SHandle
= RegisterServiceCtrlHandlerW(ServiceNameU
.Buffer
,
534 RtlFreeUnicodeString(&ServiceNameU
);
540 /**********************************************************************
541 * RegisterServiceCtrlHandlerW
545 SERVICE_STATUS_HANDLE WINAPI
546 RegisterServiceCtrlHandlerW(LPCWSTR lpServiceName
,
547 LPHANDLER_FUNCTION lpHandlerProc
)
549 PACTIVE_SERVICE Service
;
551 Service
= ScLookupServiceByServiceName((LPWSTR
)lpServiceName
);
554 return (SERVICE_STATUS_HANDLE
)NULL
;
557 Service
->HandlerFunction
= lpHandlerProc
;
558 Service
->HandlerFunctionEx
= NULL
;
560 TRACE("RegisterServiceCtrlHandler returning %lu\n", Service
->hServiceStatus
);
562 return Service
->hServiceStatus
;
566 /**********************************************************************
567 * RegisterServiceCtrlHandlerExA
571 SERVICE_STATUS_HANDLE WINAPI
572 RegisterServiceCtrlHandlerExA(LPCSTR lpServiceName
,
573 LPHANDLER_FUNCTION_EX lpHandlerProc
,
576 ANSI_STRING ServiceNameA
;
577 UNICODE_STRING ServiceNameU
;
578 SERVICE_STATUS_HANDLE SHandle
;
580 RtlInitAnsiString(&ServiceNameA
, (LPSTR
)lpServiceName
);
581 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ServiceNameU
, &ServiceNameA
, TRUE
)))
583 SetLastError(ERROR_OUTOFMEMORY
);
584 return (SERVICE_STATUS_HANDLE
)0;
587 SHandle
= RegisterServiceCtrlHandlerExW(ServiceNameU
.Buffer
,
591 RtlFreeUnicodeString(&ServiceNameU
);
597 /**********************************************************************
598 * RegisterServiceCtrlHandlerExW
602 SERVICE_STATUS_HANDLE WINAPI
603 RegisterServiceCtrlHandlerExW(LPCWSTR lpServiceName
,
604 LPHANDLER_FUNCTION_EX lpHandlerProc
,
607 PACTIVE_SERVICE Service
;
609 Service
= ScLookupServiceByServiceName(lpServiceName
);
612 return (SERVICE_STATUS_HANDLE
)NULL
;
615 Service
->HandlerFunction
= NULL
;
616 Service
->HandlerFunctionEx
= lpHandlerProc
;
617 Service
->HandlerContext
= lpContext
;
619 TRACE("RegisterServiceCtrlHandlerEx returning %lu\n", Service
->hServiceStatus
);
621 return Service
->hServiceStatus
;
625 /**********************************************************************
626 * I_ScSetServiceBitsA
633 I_ScSetServiceBitsA(SERVICE_STATUS_HANDLE hServiceStatus
,
636 BOOL bUpdateImmediately
,
643 /* Call to services.exe using RPC */
644 bResult
= RI_ScSetServiceBitsA((RPC_SERVICE_STATUS_HANDLE
)hServiceStatus
,
650 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
652 SetLastError(ScmRpcStatusToWinError(RpcExceptionCode()));
661 /**********************************************************************
662 * I_ScSetServiceBitsW
669 I_ScSetServiceBitsW(SERVICE_STATUS_HANDLE hServiceStatus
,
672 BOOL bUpdateImmediately
,
679 /* Call to services.exe using RPC */
680 bResult
= RI_ScSetServiceBitsW((RPC_SERVICE_STATUS_HANDLE
)hServiceStatus
,
686 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
688 SetLastError(ScmRpcStatusToWinError(RpcExceptionCode()));
697 /**********************************************************************
703 SetServiceBits(SERVICE_STATUS_HANDLE hServiceStatus
,
706 BOOL bUpdateImmediately
)
708 return I_ScSetServiceBitsW(hServiceStatus
,
716 /**********************************************************************
722 SetServiceStatus(SERVICE_STATUS_HANDLE hServiceStatus
,
723 LPSERVICE_STATUS lpServiceStatus
)
727 TRACE("SetServiceStatus() called\n");
728 TRACE("hServiceStatus %lu\n", hServiceStatus
);
732 /* Call to services.exe using RPC */
733 dwError
= RSetServiceStatus((RPC_SERVICE_STATUS_HANDLE
)hServiceStatus
,
736 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
738 dwError
= ScmRpcStatusToWinError(RpcExceptionCode());
742 if (dwError
!= ERROR_SUCCESS
)
744 ERR("ScmrSetServiceStatus() failed (Error %lu)\n", dwError
);
745 SetLastError(dwError
);
749 TRACE("SetServiceStatus() done (ret %lu)\n", dwError
);
755 /**********************************************************************
756 * StartServiceCtrlDispatcherA
761 StartServiceCtrlDispatcherA(const SERVICE_TABLE_ENTRYA
* lpServiceStartTable
)
766 PUCHAR lpMessageBuffer
;
768 TRACE("StartServiceCtrlDispatcherA() called\n");
771 while (lpServiceStartTable
[i
].lpServiceProc
!= NULL
)
776 dwActiveServiceCount
= i
;
777 lpActiveServices
= RtlAllocateHeap(RtlGetProcessHeap(),
779 dwActiveServiceCount
* sizeof(ACTIVE_SERVICE
));
780 if (lpActiveServices
== NULL
)
785 /* Copy service names and start procedure */
786 for (i
= 0; i
< dwActiveServiceCount
; i
++)
788 RtlCreateUnicodeStringFromAsciiz(&lpActiveServices
[i
].ServiceName
,
789 lpServiceStartTable
[i
].lpServiceName
);
790 lpActiveServices
[i
].Main
.lpFuncA
= lpServiceStartTable
[i
].lpServiceProc
;
791 lpActiveServices
[i
].hServiceStatus
= 0;
792 lpActiveServices
[i
].bUnicode
= FALSE
;
795 dwError
= ScConnectControlPipe(&hPipe
);
796 if (dwError
!= ERROR_SUCCESS
)
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;
809 lpMessageBuffer
= RtlAllocateHeap(RtlGetProcessHeap(),
812 if (lpMessageBuffer
== NULL
)
814 /* Free the service table */
815 for (i
= 0; i
< dwActiveServiceCount
; i
++)
817 RtlFreeUnicodeString(&lpActiveServices
[i
].ServiceName
);
819 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices
);
820 lpActiveServices
= NULL
;
821 dwActiveServiceCount
= 0;
826 ScCreateStatusBinding();
828 ScServiceDispatcher(hPipe
, lpMessageBuffer
, 256);
830 ScDestroyStatusBinding();
834 /* Free the message buffer */
835 RtlFreeHeap(RtlGetProcessHeap(), 0, lpMessageBuffer
);
837 /* Free the service table */
838 for (i
= 0; i
< dwActiveServiceCount
; i
++)
840 RtlFreeUnicodeString(&lpActiveServices
[i
].ServiceName
);
842 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices
);
843 lpActiveServices
= NULL
;
844 dwActiveServiceCount
= 0;
850 /**********************************************************************
851 * StartServiceCtrlDispatcherW
856 StartServiceCtrlDispatcherW(const SERVICE_TABLE_ENTRYW
* lpServiceStartTable
)
861 PUCHAR lpMessageBuffer
;
863 TRACE("StartServiceCtrlDispatcherW() called\n");
866 while (lpServiceStartTable
[i
].lpServiceProc
!= NULL
)
871 dwActiveServiceCount
= i
;
872 lpActiveServices
= RtlAllocateHeap(RtlGetProcessHeap(),
874 dwActiveServiceCount
* sizeof(ACTIVE_SERVICE
));
875 if (lpActiveServices
== NULL
)
880 /* Copy service names and start procedure */
881 for (i
= 0; i
< dwActiveServiceCount
; i
++)
883 RtlCreateUnicodeString(&lpActiveServices
[i
].ServiceName
,
884 lpServiceStartTable
[i
].lpServiceName
);
885 lpActiveServices
[i
].Main
.lpFuncW
= lpServiceStartTable
[i
].lpServiceProc
;
886 lpActiveServices
[i
].hServiceStatus
= 0;
887 lpActiveServices
[i
].bUnicode
= TRUE
;
890 dwError
= ScConnectControlPipe(&hPipe
);
891 if (dwError
!= ERROR_SUCCESS
)
893 /* Free the service table */
894 for (i
= 0; i
< dwActiveServiceCount
; i
++)
896 RtlFreeUnicodeString(&lpActiveServices
[i
].ServiceName
);
898 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices
);
899 lpActiveServices
= NULL
;
900 dwActiveServiceCount
= 0;
904 lpMessageBuffer
= RtlAllocateHeap(RtlGetProcessHeap(),
907 if (lpMessageBuffer
== NULL
)
909 /* Free the service table */
910 for (i
= 0; i
< dwActiveServiceCount
; i
++)
912 RtlFreeUnicodeString(&lpActiveServices
[i
].ServiceName
);
914 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices
);
915 lpActiveServices
= NULL
;
916 dwActiveServiceCount
= 0;
921 ScCreateStatusBinding();
923 ScServiceDispatcher(hPipe
, lpMessageBuffer
, 256);
925 ScDestroyStatusBinding();
929 /* Free the message buffer */
930 RtlFreeHeap(RtlGetProcessHeap(), 0, lpMessageBuffer
);
932 /* Free the service table */
933 for (i
= 0; i
< dwActiveServiceCount
; i
++)
935 RtlFreeUnicodeString(&lpActiveServices
[i
].ServiceName
);
937 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices
);
938 lpActiveServices
= NULL
;
939 dwActiveServiceCount
= 0;