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
;
46 /* FUNCTIONS *****************************************************************/
48 static PACTIVE_SERVICE
49 ScLookupServiceByServiceName(LPCWSTR lpServiceName
)
53 for (i
= 0; i
< dwActiveServiceCount
; i
++)
55 if (_wcsicmp(lpActiveServices
[i
].ServiceName
.Buffer
, lpServiceName
) == 0)
57 return &lpActiveServices
[i
];
61 SetLastError(ERROR_SERVICE_DOES_NOT_EXIST
);
68 ScServiceMainStub(LPVOID Context
)
70 PACTIVE_SERVICE lpService
;
76 lpService
= (PACTIVE_SERVICE
)Context
;
78 TRACE("ScServiceMainStub() called\n");
81 lpPtr
= lpService
->Arguments
;
84 TRACE("arg: %S\n", lpPtr
);
85 dwLen
= wcslen(lpPtr
) + 1;
90 TRACE("dwArgCount: %ld\ndwLength: %ld\n", dwArgCount
, dwLength
);
92 /* Build the argument vector and call the main service routine */
93 if (lpService
->bUnicode
)
98 lpArgVector
= HeapAlloc(GetProcessHeap(),
100 (dwArgCount
+ 1) * sizeof(LPWSTR
));
101 if (lpArgVector
== NULL
)
102 return ERROR_OUTOFMEMORY
;
105 Ptr
= lpService
->Arguments
;
108 lpArgVector
[dwArgCount
] = Ptr
;
111 Ptr
+= (wcslen(Ptr
) + 1);
113 lpArgVector
[dwArgCount
] = NULL
;
115 (lpService
->Main
.lpFuncW
)(dwArgCount
, lpArgVector
);
117 HeapFree(GetProcessHeap(),
128 AnsiLength
= WideCharToMultiByte(CP_ACP
,
130 lpService
->Arguments
,
137 return ERROR_INVALID_PARAMETER
; /* ? */
139 AnsiString
= HeapAlloc(GetProcessHeap(),
142 if (AnsiString
== NULL
)
143 return ERROR_OUTOFMEMORY
;
145 WideCharToMultiByte(CP_ACP
,
147 lpService
->Arguments
,
154 AnsiString
[AnsiLength
] = ANSI_NULL
;
156 lpArgVector
= HeapAlloc(GetProcessHeap(),
158 (dwArgCount
+ 1) * sizeof(LPSTR
));
159 if (lpArgVector
== NULL
)
161 HeapFree(GetProcessHeap(),
164 return ERROR_OUTOFMEMORY
;
171 lpArgVector
[dwArgCount
] = Ptr
;
174 Ptr
+= (strlen(Ptr
) + 1);
176 lpArgVector
[dwArgCount
] = NULL
;
178 (lpService
->Main
.lpFuncA
)(dwArgCount
, lpArgVector
);
180 HeapFree(GetProcessHeap(),
183 HeapFree(GetProcessHeap(),
188 return ERROR_SUCCESS
;
193 ScConnectControlPipe(HANDLE
*hPipe
)
195 DWORD dwBytesWritten
;
197 DWORD dwServiceCurrent
= 0;
199 WCHAR NtControlPipeName
[MAX_PATH
+ 1];
200 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 for pipe %S (Error %lu)\n", NtControlPipeName
, 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 /* Pass the ProcessId to the SCM */
253 dwProcessId
= GetCurrentProcessId();
260 TRACE("Sent Process ID %lu\n", dwProcessId
);
263 return ERROR_SUCCESS
;
268 ScStartService(PACTIVE_SERVICE lpService
,
269 PSCM_CONTROL_PACKET ControlPacket
)
274 TRACE("ScStartService() called\n");
275 TRACE("Size: %lu\n", ControlPacket
->dwSize
);
276 TRACE("Service: %S\n", &ControlPacket
->szArguments
[0]);
278 /* Set the service status handle */
279 lpService
->hServiceStatus
= ControlPacket
->hServiceStatus
;
281 lpService
->Arguments
= HeapAlloc(GetProcessHeap(),
283 (ControlPacket
->dwSize
+ 1) * sizeof(WCHAR
));
284 if (lpService
->Arguments
== NULL
)
285 return ERROR_OUTOFMEMORY
;
287 memcpy(lpService
->Arguments
,
288 ControlPacket
->szArguments
,
289 ControlPacket
->dwSize
* sizeof(WCHAR
));
291 /* invoke the services entry point and implement the command loop */
292 ThreadHandle
= CreateThread(NULL
,
298 if (ThreadHandle
== NULL
)
299 return ERROR_SERVICE_NO_THREAD
;
301 ResumeThread(ThreadHandle
);
302 CloseHandle(ThreadHandle
);
304 return ERROR_SUCCESS
;
309 ScControlService(PACTIVE_SERVICE lpService
,
310 PSCM_CONTROL_PACKET ControlPacket
)
312 TRACE("ScControlService() called\n");
313 TRACE("Size: %lu\n", ControlPacket
->dwSize
);
314 TRACE("Service: %S\n", &ControlPacket
->szArguments
[0]);
316 if (lpService
->HandlerFunction
)
318 (lpService
->HandlerFunction
)(ControlPacket
->dwControl
);
320 else if (lpService
->HandlerFunctionEx
)
322 /* FIXME: send correct params */
323 (lpService
->HandlerFunctionEx
)(ControlPacket
->dwControl
, 0, NULL
, NULL
);
326 if (ControlPacket
->dwControl
== SERVICE_CONTROL_STOP
)
328 HeapFree(GetProcessHeap(),
330 lpService
->Arguments
);
333 TRACE("ScControlService() done\n");
335 return ERROR_SUCCESS
;
340 ScServiceDispatcher(HANDLE hPipe
,
344 PSCM_CONTROL_PACKET ControlPacket
;
347 DWORD dwRunningServices
= 0;
348 LPWSTR lpServiceName
;
349 PACTIVE_SERVICE lpService
;
351 TRACE("ScDispatcherLoop() called\n");
353 ControlPacket
= HeapAlloc(GetProcessHeap(),
356 if (ControlPacket
== NULL
)
361 /* Read command from the control pipe */
362 bResult
= ReadFile(hPipe
,
367 if (bResult
== FALSE
)
369 ERR("Pipe read failed (Error: %lu)\n", GetLastError());
373 lpServiceName
= &ControlPacket
->szArguments
[0];
374 TRACE("Service: %S\n", lpServiceName
);
376 lpService
= ScLookupServiceByServiceName(lpServiceName
);
377 if (lpService
!= NULL
)
379 /* Execute command */
380 switch (ControlPacket
->dwControl
)
382 case SERVICE_CONTROL_START
:
383 TRACE("Start command - recieved SERVICE_CONTROL_START\n");
384 if (ScStartService(lpService
, ControlPacket
) == ERROR_SUCCESS
)
388 case SERVICE_CONTROL_STOP
:
389 TRACE("Stop command - recieved SERVICE_CONTROL_STOP\n");
390 if (ScControlService(lpService
, ControlPacket
) == ERROR_SUCCESS
)
395 TRACE("Command %lu received", ControlPacket
->dwControl
);
396 ScControlService(lpService
, ControlPacket
);
401 if (dwRunningServices
== 0)
405 HeapFree(GetProcessHeap(),
413 /**********************************************************************
414 * RegisterServiceCtrlHandlerA
418 SERVICE_STATUS_HANDLE WINAPI
419 RegisterServiceCtrlHandlerA(LPCSTR lpServiceName
,
420 LPHANDLER_FUNCTION lpHandlerProc
)
422 ANSI_STRING ServiceNameA
;
423 UNICODE_STRING ServiceNameU
;
424 SERVICE_STATUS_HANDLE SHandle
;
426 RtlInitAnsiString(&ServiceNameA
, (LPSTR
)lpServiceName
);
427 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ServiceNameU
, &ServiceNameA
, TRUE
)))
429 SetLastError(ERROR_OUTOFMEMORY
);
430 return (SERVICE_STATUS_HANDLE
)0;
433 SHandle
= RegisterServiceCtrlHandlerW(ServiceNameU
.Buffer
,
436 RtlFreeUnicodeString(&ServiceNameU
);
442 /**********************************************************************
443 * RegisterServiceCtrlHandlerW
447 SERVICE_STATUS_HANDLE WINAPI
448 RegisterServiceCtrlHandlerW(LPCWSTR lpServiceName
,
449 LPHANDLER_FUNCTION lpHandlerProc
)
451 PACTIVE_SERVICE Service
;
453 Service
= ScLookupServiceByServiceName((LPWSTR
)lpServiceName
);
456 return (SERVICE_STATUS_HANDLE
)NULL
;
459 Service
->HandlerFunction
= lpHandlerProc
;
460 Service
->HandlerFunctionEx
= NULL
;
462 TRACE("RegisterServiceCtrlHandler returning %lu\n", Service
->hServiceStatus
);
464 return Service
->hServiceStatus
;
468 /**********************************************************************
469 * RegisterServiceCtrlHandlerExA
473 SERVICE_STATUS_HANDLE WINAPI
474 RegisterServiceCtrlHandlerExA(LPCSTR lpServiceName
,
475 LPHANDLER_FUNCTION_EX lpHandlerProc
,
478 ANSI_STRING ServiceNameA
;
479 UNICODE_STRING ServiceNameU
;
480 SERVICE_STATUS_HANDLE SHandle
;
482 RtlInitAnsiString(&ServiceNameA
, (LPSTR
)lpServiceName
);
483 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ServiceNameU
, &ServiceNameA
, TRUE
)))
485 SetLastError(ERROR_OUTOFMEMORY
);
486 return (SERVICE_STATUS_HANDLE
)0;
489 SHandle
= RegisterServiceCtrlHandlerExW(ServiceNameU
.Buffer
,
493 RtlFreeUnicodeString(&ServiceNameU
);
499 /**********************************************************************
500 * RegisterServiceCtrlHandlerExW
504 SERVICE_STATUS_HANDLE WINAPI
505 RegisterServiceCtrlHandlerExW(LPCWSTR lpServiceName
,
506 LPHANDLER_FUNCTION_EX lpHandlerProc
,
509 PACTIVE_SERVICE Service
;
511 Service
= ScLookupServiceByServiceName(lpServiceName
);
514 return (SERVICE_STATUS_HANDLE
)NULL
;
517 Service
->HandlerFunction
= NULL
;
518 Service
->HandlerFunctionEx
= lpHandlerProc
;
519 Service
->HandlerContext
= lpContext
;
521 TRACE("RegisterServiceCtrlHandlerEx returning %lu\n", Service
->hServiceStatus
);
523 return Service
->hServiceStatus
;
527 /**********************************************************************
528 * I_ScSetServiceBitsA
535 I_ScSetServiceBitsA(SERVICE_STATUS_HANDLE hServiceStatus
,
538 BOOL bUpdateImmediately
,
545 /* Call to services.exe using RPC */
546 bResult
= RI_ScSetServiceBitsA((RPC_SERVICE_STATUS_HANDLE
)hServiceStatus
,
552 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
554 SetLastError(ScmRpcStatusToWinError(RpcExceptionCode()));
563 /**********************************************************************
564 * I_ScSetServiceBitsW
571 I_ScSetServiceBitsW(SERVICE_STATUS_HANDLE hServiceStatus
,
574 BOOL bUpdateImmediately
,
581 /* Call to services.exe using RPC */
582 bResult
= RI_ScSetServiceBitsW((RPC_SERVICE_STATUS_HANDLE
)hServiceStatus
,
588 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
590 SetLastError(ScmRpcStatusToWinError(RpcExceptionCode()));
599 /**********************************************************************
605 SetServiceBits(SERVICE_STATUS_HANDLE hServiceStatus
,
608 BOOL bUpdateImmediately
)
610 return I_ScSetServiceBitsW(hServiceStatus
,
618 /**********************************************************************
624 SetServiceStatus(SERVICE_STATUS_HANDLE hServiceStatus
,
625 LPSERVICE_STATUS lpServiceStatus
)
629 TRACE("SetServiceStatus() called\n");
630 TRACE("hServiceStatus %lu\n", hServiceStatus
);
632 /* Call to services.exe using RPC */
633 dwError
= RSetServiceStatus((RPC_SERVICE_STATUS_HANDLE
)hServiceStatus
,
635 if (dwError
!= ERROR_SUCCESS
)
637 ERR("ScmrSetServiceStatus() failed (Error %lu)\n", dwError
);
638 SetLastError(dwError
);
642 TRACE("SetServiceStatus() done (ret %lu)\n", dwError
);
648 /**********************************************************************
649 * StartServiceCtrlDispatcherA
654 StartServiceCtrlDispatcherA(const SERVICE_TABLE_ENTRYA
* lpServiceStartTable
)
659 PUCHAR lpMessageBuffer
;
661 TRACE("StartServiceCtrlDispatcherA() called\n");
664 while (lpServiceStartTable
[i
].lpServiceProc
!= NULL
)
669 dwActiveServiceCount
= i
;
670 lpActiveServices
= RtlAllocateHeap(RtlGetProcessHeap(),
672 dwActiveServiceCount
* sizeof(ACTIVE_SERVICE
));
673 if (lpActiveServices
== NULL
)
678 /* Copy service names and start procedure */
679 for (i
= 0; i
< dwActiveServiceCount
; i
++)
681 RtlCreateUnicodeStringFromAsciiz(&lpActiveServices
[i
].ServiceName
,
682 lpServiceStartTable
[i
].lpServiceName
);
683 lpActiveServices
[i
].Main
.lpFuncA
= lpServiceStartTable
[i
].lpServiceProc
;
684 lpActiveServices
[i
].hServiceStatus
= 0;
685 lpActiveServices
[i
].bUnicode
= FALSE
;
688 dwError
= ScConnectControlPipe(&hPipe
);
689 if (dwError
!= ERROR_SUCCESS
)
691 /* Free the service table */
692 for (i
= 0; i
< dwActiveServiceCount
; i
++)
694 RtlFreeUnicodeString(&lpActiveServices
[i
].ServiceName
);
696 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices
);
697 lpActiveServices
= NULL
;
698 dwActiveServiceCount
= 0;
702 lpMessageBuffer
= RtlAllocateHeap(RtlGetProcessHeap(),
705 if (lpMessageBuffer
== NULL
)
707 /* Free the service table */
708 for (i
= 0; i
< dwActiveServiceCount
; i
++)
710 RtlFreeUnicodeString(&lpActiveServices
[i
].ServiceName
);
712 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices
);
713 lpActiveServices
= NULL
;
714 dwActiveServiceCount
= 0;
719 ScServiceDispatcher(hPipe
, lpMessageBuffer
, 256);
722 /* Free the message buffer */
723 RtlFreeHeap(RtlGetProcessHeap(), 0, lpMessageBuffer
);
725 /* Free the service table */
726 for (i
= 0; i
< dwActiveServiceCount
; i
++)
728 RtlFreeUnicodeString(&lpActiveServices
[i
].ServiceName
);
730 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices
);
731 lpActiveServices
= NULL
;
732 dwActiveServiceCount
= 0;
738 /**********************************************************************
739 * StartServiceCtrlDispatcherW
744 StartServiceCtrlDispatcherW(const SERVICE_TABLE_ENTRYW
* lpServiceStartTable
)
749 PUCHAR lpMessageBuffer
;
751 TRACE("StartServiceCtrlDispatcherW() called\n");
754 while (lpServiceStartTable
[i
].lpServiceProc
!= NULL
)
759 dwActiveServiceCount
= i
;
760 lpActiveServices
= RtlAllocateHeap(RtlGetProcessHeap(),
762 dwActiveServiceCount
* sizeof(ACTIVE_SERVICE
));
763 if (lpActiveServices
== NULL
)
768 /* Copy service names and start procedure */
769 for (i
= 0; i
< dwActiveServiceCount
; i
++)
771 RtlCreateUnicodeString(&lpActiveServices
[i
].ServiceName
,
772 lpServiceStartTable
[i
].lpServiceName
);
773 lpActiveServices
[i
].Main
.lpFuncW
= lpServiceStartTable
[i
].lpServiceProc
;
774 lpActiveServices
[i
].hServiceStatus
= 0;
775 lpActiveServices
[i
].bUnicode
= TRUE
;
778 dwError
= ScConnectControlPipe(&hPipe
);
779 if (dwError
!= ERROR_SUCCESS
)
781 /* Free the service table */
782 for (i
= 0; i
< dwActiveServiceCount
; i
++)
784 RtlFreeUnicodeString(&lpActiveServices
[i
].ServiceName
);
786 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices
);
787 lpActiveServices
= NULL
;
788 dwActiveServiceCount
= 0;
792 lpMessageBuffer
= RtlAllocateHeap(RtlGetProcessHeap(),
795 if (lpMessageBuffer
== NULL
)
797 /* Free the service table */
798 for (i
= 0; i
< dwActiveServiceCount
; i
++)
800 RtlFreeUnicodeString(&lpActiveServices
[i
].ServiceName
);
802 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices
);
803 lpActiveServices
= NULL
;
804 dwActiveServiceCount
= 0;
809 ScServiceDispatcher(hPipe
, lpMessageBuffer
, 256);
812 /* Free the message buffer */
813 RtlFreeHeap(RtlGetProcessHeap(), 0, lpMessageBuffer
);
815 /* Free the service table */
816 for (i
= 0; i
< dwActiveServiceCount
; i
++)
818 RtlFreeUnicodeString(&lpActiveServices
[i
].ServiceName
);
820 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices
);
821 lpActiveServices
= NULL
;
822 dwActiveServiceCount
= 0;