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
;
350 SCM_REPLY_PACKET ReplyPacket
;
353 TRACE("ScDispatcherLoop() called\n");
355 ControlPacket
= HeapAlloc(GetProcessHeap(),
358 if (ControlPacket
== NULL
)
363 /* Read command from the control pipe */
364 bResult
= ReadFile(hPipe
,
369 if (bResult
== FALSE
)
371 ERR("Pipe read failed (Error: %lu)\n", GetLastError());
375 lpServiceName
= &ControlPacket
->szArguments
[0];
376 TRACE("Service: %S\n", lpServiceName
);
378 lpService
= ScLookupServiceByServiceName(lpServiceName
);
379 if (lpService
!= NULL
)
381 /* Execute command */
382 switch (ControlPacket
->dwControl
)
384 case SERVICE_CONTROL_START
:
385 TRACE("Start command - recieved SERVICE_CONTROL_START\n");
386 dwError
= ScStartService(lpService
, ControlPacket
);
387 if (dwError
== ERROR_SUCCESS
)
391 case SERVICE_CONTROL_STOP
:
392 TRACE("Stop command - recieved SERVICE_CONTROL_STOP\n");
393 dwError
= ScControlService(lpService
, ControlPacket
);
394 if (dwError
== ERROR_SUCCESS
)
399 TRACE("Command %lu received", ControlPacket
->dwControl
);
400 dwError
= ScControlService(lpService
, ControlPacket
);
406 dwError
= ERROR_NOT_FOUND
;
409 ReplyPacket
.dwError
= dwError
;
411 /* Send the reply packet */
412 bResult
= WriteFile(hPipe
,
417 if (bResult
== FALSE
)
419 ERR("Pipe write failed (Error: %lu)\n", GetLastError());
423 if (dwRunningServices
== 0)
427 HeapFree(GetProcessHeap(),
435 /**********************************************************************
436 * RegisterServiceCtrlHandlerA
440 SERVICE_STATUS_HANDLE WINAPI
441 RegisterServiceCtrlHandlerA(LPCSTR lpServiceName
,
442 LPHANDLER_FUNCTION lpHandlerProc
)
444 ANSI_STRING ServiceNameA
;
445 UNICODE_STRING ServiceNameU
;
446 SERVICE_STATUS_HANDLE SHandle
;
448 RtlInitAnsiString(&ServiceNameA
, (LPSTR
)lpServiceName
);
449 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ServiceNameU
, &ServiceNameA
, TRUE
)))
451 SetLastError(ERROR_OUTOFMEMORY
);
452 return (SERVICE_STATUS_HANDLE
)0;
455 SHandle
= RegisterServiceCtrlHandlerW(ServiceNameU
.Buffer
,
458 RtlFreeUnicodeString(&ServiceNameU
);
464 /**********************************************************************
465 * RegisterServiceCtrlHandlerW
469 SERVICE_STATUS_HANDLE WINAPI
470 RegisterServiceCtrlHandlerW(LPCWSTR lpServiceName
,
471 LPHANDLER_FUNCTION lpHandlerProc
)
473 PACTIVE_SERVICE Service
;
475 Service
= ScLookupServiceByServiceName((LPWSTR
)lpServiceName
);
478 return (SERVICE_STATUS_HANDLE
)NULL
;
481 Service
->HandlerFunction
= lpHandlerProc
;
482 Service
->HandlerFunctionEx
= NULL
;
484 TRACE("RegisterServiceCtrlHandler returning %lu\n", Service
->hServiceStatus
);
486 return Service
->hServiceStatus
;
490 /**********************************************************************
491 * RegisterServiceCtrlHandlerExA
495 SERVICE_STATUS_HANDLE WINAPI
496 RegisterServiceCtrlHandlerExA(LPCSTR lpServiceName
,
497 LPHANDLER_FUNCTION_EX lpHandlerProc
,
500 ANSI_STRING ServiceNameA
;
501 UNICODE_STRING ServiceNameU
;
502 SERVICE_STATUS_HANDLE SHandle
;
504 RtlInitAnsiString(&ServiceNameA
, (LPSTR
)lpServiceName
);
505 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ServiceNameU
, &ServiceNameA
, TRUE
)))
507 SetLastError(ERROR_OUTOFMEMORY
);
508 return (SERVICE_STATUS_HANDLE
)0;
511 SHandle
= RegisterServiceCtrlHandlerExW(ServiceNameU
.Buffer
,
515 RtlFreeUnicodeString(&ServiceNameU
);
521 /**********************************************************************
522 * RegisterServiceCtrlHandlerExW
526 SERVICE_STATUS_HANDLE WINAPI
527 RegisterServiceCtrlHandlerExW(LPCWSTR lpServiceName
,
528 LPHANDLER_FUNCTION_EX lpHandlerProc
,
531 PACTIVE_SERVICE Service
;
533 Service
= ScLookupServiceByServiceName(lpServiceName
);
536 return (SERVICE_STATUS_HANDLE
)NULL
;
539 Service
->HandlerFunction
= NULL
;
540 Service
->HandlerFunctionEx
= lpHandlerProc
;
541 Service
->HandlerContext
= lpContext
;
543 TRACE("RegisterServiceCtrlHandlerEx returning %lu\n", Service
->hServiceStatus
);
545 return Service
->hServiceStatus
;
549 /**********************************************************************
550 * I_ScSetServiceBitsA
557 I_ScSetServiceBitsA(SERVICE_STATUS_HANDLE hServiceStatus
,
560 BOOL bUpdateImmediately
,
567 /* Call to services.exe using RPC */
568 bResult
= RI_ScSetServiceBitsA((RPC_SERVICE_STATUS_HANDLE
)hServiceStatus
,
574 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
576 SetLastError(ScmRpcStatusToWinError(RpcExceptionCode()));
585 /**********************************************************************
586 * I_ScSetServiceBitsW
593 I_ScSetServiceBitsW(SERVICE_STATUS_HANDLE hServiceStatus
,
596 BOOL bUpdateImmediately
,
603 /* Call to services.exe using RPC */
604 bResult
= RI_ScSetServiceBitsW((RPC_SERVICE_STATUS_HANDLE
)hServiceStatus
,
610 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
612 SetLastError(ScmRpcStatusToWinError(RpcExceptionCode()));
621 /**********************************************************************
627 SetServiceBits(SERVICE_STATUS_HANDLE hServiceStatus
,
630 BOOL bUpdateImmediately
)
632 return I_ScSetServiceBitsW(hServiceStatus
,
640 /**********************************************************************
646 SetServiceStatus(SERVICE_STATUS_HANDLE hServiceStatus
,
647 LPSERVICE_STATUS lpServiceStatus
)
651 TRACE("SetServiceStatus() called\n");
652 TRACE("hServiceStatus %lu\n", hServiceStatus
);
656 /* Call to services.exe using RPC */
657 dwError
= RSetServiceStatus((RPC_SERVICE_STATUS_HANDLE
)hServiceStatus
,
660 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
662 dwError
= ScmRpcStatusToWinError(RpcExceptionCode());
666 if (dwError
!= ERROR_SUCCESS
)
668 ERR("ScmrSetServiceStatus() failed (Error %lu)\n", dwError
);
669 SetLastError(dwError
);
673 TRACE("SetServiceStatus() done (ret %lu)\n", dwError
);
679 /**********************************************************************
680 * StartServiceCtrlDispatcherA
685 StartServiceCtrlDispatcherA(const SERVICE_TABLE_ENTRYA
* lpServiceStartTable
)
690 PUCHAR lpMessageBuffer
;
692 TRACE("StartServiceCtrlDispatcherA() called\n");
695 while (lpServiceStartTable
[i
].lpServiceProc
!= NULL
)
700 dwActiveServiceCount
= i
;
701 lpActiveServices
= RtlAllocateHeap(RtlGetProcessHeap(),
703 dwActiveServiceCount
* sizeof(ACTIVE_SERVICE
));
704 if (lpActiveServices
== NULL
)
709 /* Copy service names and start procedure */
710 for (i
= 0; i
< dwActiveServiceCount
; i
++)
712 RtlCreateUnicodeStringFromAsciiz(&lpActiveServices
[i
].ServiceName
,
713 lpServiceStartTable
[i
].lpServiceName
);
714 lpActiveServices
[i
].Main
.lpFuncA
= lpServiceStartTable
[i
].lpServiceProc
;
715 lpActiveServices
[i
].hServiceStatus
= 0;
716 lpActiveServices
[i
].bUnicode
= FALSE
;
719 dwError
= ScConnectControlPipe(&hPipe
);
720 if (dwError
!= ERROR_SUCCESS
)
722 /* Free the service table */
723 for (i
= 0; i
< dwActiveServiceCount
; i
++)
725 RtlFreeUnicodeString(&lpActiveServices
[i
].ServiceName
);
727 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices
);
728 lpActiveServices
= NULL
;
729 dwActiveServiceCount
= 0;
733 lpMessageBuffer
= RtlAllocateHeap(RtlGetProcessHeap(),
736 if (lpMessageBuffer
== NULL
)
738 /* Free the service table */
739 for (i
= 0; i
< dwActiveServiceCount
; i
++)
741 RtlFreeUnicodeString(&lpActiveServices
[i
].ServiceName
);
743 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices
);
744 lpActiveServices
= NULL
;
745 dwActiveServiceCount
= 0;
750 ScServiceDispatcher(hPipe
, lpMessageBuffer
, 256);
753 /* Free the message buffer */
754 RtlFreeHeap(RtlGetProcessHeap(), 0, lpMessageBuffer
);
756 /* Free the service table */
757 for (i
= 0; i
< dwActiveServiceCount
; i
++)
759 RtlFreeUnicodeString(&lpActiveServices
[i
].ServiceName
);
761 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices
);
762 lpActiveServices
= NULL
;
763 dwActiveServiceCount
= 0;
769 /**********************************************************************
770 * StartServiceCtrlDispatcherW
775 StartServiceCtrlDispatcherW(const SERVICE_TABLE_ENTRYW
* lpServiceStartTable
)
780 PUCHAR lpMessageBuffer
;
782 TRACE("StartServiceCtrlDispatcherW() called\n");
785 while (lpServiceStartTable
[i
].lpServiceProc
!= NULL
)
790 dwActiveServiceCount
= i
;
791 lpActiveServices
= RtlAllocateHeap(RtlGetProcessHeap(),
793 dwActiveServiceCount
* sizeof(ACTIVE_SERVICE
));
794 if (lpActiveServices
== NULL
)
799 /* Copy service names and start procedure */
800 for (i
= 0; i
< dwActiveServiceCount
; i
++)
802 RtlCreateUnicodeString(&lpActiveServices
[i
].ServiceName
,
803 lpServiceStartTable
[i
].lpServiceName
);
804 lpActiveServices
[i
].Main
.lpFuncW
= lpServiceStartTable
[i
].lpServiceProc
;
805 lpActiveServices
[i
].hServiceStatus
= 0;
806 lpActiveServices
[i
].bUnicode
= TRUE
;
809 dwError
= ScConnectControlPipe(&hPipe
);
810 if (dwError
!= ERROR_SUCCESS
)
812 /* Free the service table */
813 for (i
= 0; i
< dwActiveServiceCount
; i
++)
815 RtlFreeUnicodeString(&lpActiveServices
[i
].ServiceName
);
817 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices
);
818 lpActiveServices
= NULL
;
819 dwActiveServiceCount
= 0;
823 lpMessageBuffer
= RtlAllocateHeap(RtlGetProcessHeap(),
826 if (lpMessageBuffer
== NULL
)
828 /* Free the service table */
829 for (i
= 0; i
< dwActiveServiceCount
; i
++)
831 RtlFreeUnicodeString(&lpActiveServices
[i
].ServiceName
);
833 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices
);
834 lpActiveServices
= NULL
;
835 dwActiveServiceCount
= 0;
840 ScServiceDispatcher(hPipe
, lpMessageBuffer
, 256);
843 /* Free the message buffer */
844 RtlFreeHeap(RtlGetProcessHeap(), 0, lpMessageBuffer
);
846 /* Free the service table */
847 for (i
= 0; i
< dwActiveServiceCount
; i
++)
849 RtlFreeUnicodeString(&lpActiveServices
[i
].ServiceName
);
851 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices
);
852 lpActiveServices
= NULL
;
853 dwActiveServiceCount
= 0;