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 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 /* 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
)(ULONG_PTR
)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
)(ULONG_PTR
)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("Command %lu received", ControlPacket
->dwControl
);
399 ScControlService(ControlPacket
);
403 if (dwRunningServices
== 0)
407 HeapFree(GetProcessHeap(),
415 /**********************************************************************
416 * RegisterServiceCtrlHandlerA
420 SERVICE_STATUS_HANDLE WINAPI
421 RegisterServiceCtrlHandlerA(LPCSTR lpServiceName
,
422 LPHANDLER_FUNCTION lpHandlerProc
)
424 ANSI_STRING ServiceNameA
;
425 UNICODE_STRING ServiceNameU
;
426 SERVICE_STATUS_HANDLE SHandle
;
428 RtlInitAnsiString(&ServiceNameA
, (LPSTR
)lpServiceName
);
429 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ServiceNameU
, &ServiceNameA
, TRUE
)))
431 SetLastError(ERROR_OUTOFMEMORY
);
432 return (SERVICE_STATUS_HANDLE
)0;
435 SHandle
= RegisterServiceCtrlHandlerW(ServiceNameU
.Buffer
,
438 RtlFreeUnicodeString(&ServiceNameU
);
444 /**********************************************************************
445 * RegisterServiceCtrlHandlerW
449 SERVICE_STATUS_HANDLE WINAPI
450 RegisterServiceCtrlHandlerW(LPCWSTR lpServiceName
,
451 LPHANDLER_FUNCTION lpHandlerProc
)
453 PACTIVE_SERVICE Service
;
455 Service
= ScLookupServiceByServiceName((LPWSTR
)lpServiceName
);
458 return (SERVICE_STATUS_HANDLE
)NULL
;
461 Service
->HandlerFunction
= lpHandlerProc
;
462 Service
->HandlerFunctionEx
= NULL
;
464 TRACE("RegisterServiceCtrlHandler returning %lu\n", Service
->hService
);
466 return (SERVICE_STATUS_HANDLE
)Service
->hService
;
470 /**********************************************************************
471 * RegisterServiceCtrlHandlerExA
475 SERVICE_STATUS_HANDLE WINAPI
476 RegisterServiceCtrlHandlerExA(LPCSTR lpServiceName
,
477 LPHANDLER_FUNCTION_EX lpHandlerProc
,
480 ANSI_STRING ServiceNameA
;
481 UNICODE_STRING ServiceNameU
;
482 SERVICE_STATUS_HANDLE SHandle
;
484 RtlInitAnsiString(&ServiceNameA
, (LPSTR
)lpServiceName
);
485 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ServiceNameU
, &ServiceNameA
, TRUE
)))
487 SetLastError(ERROR_OUTOFMEMORY
);
488 return (SERVICE_STATUS_HANDLE
)0;
491 SHandle
= RegisterServiceCtrlHandlerExW(ServiceNameU
.Buffer
,
495 RtlFreeUnicodeString(&ServiceNameU
);
501 /**********************************************************************
502 * RegisterServiceCtrlHandlerExW
506 SERVICE_STATUS_HANDLE WINAPI
507 RegisterServiceCtrlHandlerExW(LPCWSTR lpServiceName
,
508 LPHANDLER_FUNCTION_EX lpHandlerProc
,
511 PACTIVE_SERVICE Service
;
513 Service
= ScLookupServiceByServiceName(lpServiceName
);
516 return (SERVICE_STATUS_HANDLE
)NULL
;
519 Service
->HandlerFunction
= NULL
;
520 Service
->HandlerFunctionEx
= lpHandlerProc
;
521 Service
->HandlerContext
= lpContext
;
523 TRACE("RegisterServiceCtrlHandlerEx returning %lu\n", Service
->hService
);
525 return (SERVICE_STATUS_HANDLE
)Service
->hService
;
529 /**********************************************************************
530 * I_ScSetServiceBitsA
537 I_ScSetServiceBitsA(SERVICE_STATUS_HANDLE hServiceStatus
,
540 BOOL bUpdateImmediately
,
547 /* Call to services.exe using RPC */
548 bResult
= RI_ScSetServiceBitsA((RPC_SERVICE_STATUS_HANDLE
)hServiceStatus
,
554 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
556 SetLastError(ScmRpcStatusToWinError(RpcExceptionCode()));
565 /**********************************************************************
566 * I_ScSetServiceBitsW
573 I_ScSetServiceBitsW(SERVICE_STATUS_HANDLE hServiceStatus
,
576 BOOL bUpdateImmediately
,
583 /* Call to services.exe using RPC */
584 bResult
= RI_ScSetServiceBitsW((RPC_SERVICE_STATUS_HANDLE
)hServiceStatus
,
590 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
592 SetLastError(ScmRpcStatusToWinError(RpcExceptionCode()));
601 /**********************************************************************
607 SetServiceBits(SERVICE_STATUS_HANDLE hServiceStatus
,
610 BOOL bUpdateImmediately
)
612 return I_ScSetServiceBitsW(hServiceStatus
,
620 /**********************************************************************
626 SetServiceStatus(SERVICE_STATUS_HANDLE hServiceStatus
,
627 LPSERVICE_STATUS lpServiceStatus
)
631 TRACE("SetServiceStatus() called\n");
632 TRACE("hServiceStatus %lu\n", hServiceStatus
);
634 /* Call to services.exe using RPC */
635 dwError
= RSetServiceStatus((RPC_SERVICE_STATUS_HANDLE
)hServiceStatus
,
637 if (dwError
!= ERROR_SUCCESS
)
639 ERR("ScmrSetServiceStatus() failed (Error %lu)\n", dwError
);
640 SetLastError(dwError
);
644 TRACE("SetServiceStatus() done (ret %lu)\n", dwError
);
650 /**********************************************************************
651 * StartServiceCtrlDispatcherA
656 StartServiceCtrlDispatcherA(const SERVICE_TABLE_ENTRYA
* lpServiceStartTable
)
661 PUCHAR lpMessageBuffer
;
663 TRACE("StartServiceCtrlDispatcherA() called\n");
666 while (lpServiceStartTable
[i
].lpServiceProc
!= NULL
)
671 dwActiveServiceCount
= i
;
672 lpActiveServices
= RtlAllocateHeap(RtlGetProcessHeap(),
674 dwActiveServiceCount
* sizeof(ACTIVE_SERVICE
));
675 if (lpActiveServices
== NULL
)
680 /* Copy service names and start procedure */
681 for (i
= 0; i
< dwActiveServiceCount
; i
++)
683 RtlCreateUnicodeStringFromAsciiz(&lpActiveServices
[i
].ServiceName
,
684 lpServiceStartTable
[i
].lpServiceName
);
685 lpActiveServices
[i
].Main
.lpFuncA
= lpServiceStartTable
[i
].lpServiceProc
;
686 lpActiveServices
[i
].hService
= (CLIENT_HANDLE
)&lpActiveServices
[i
];
687 lpActiveServices
[i
].bUnicode
= FALSE
;
690 dwError
= ScConnectControlPipe(&hPipe
);
691 if (dwError
!= ERROR_SUCCESS
)
693 /* Free the service table */
694 for (i
= 0; i
< dwActiveServiceCount
; i
++)
696 RtlFreeUnicodeString(&lpActiveServices
[i
].ServiceName
);
698 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices
);
699 lpActiveServices
= NULL
;
700 dwActiveServiceCount
= 0;
704 lpMessageBuffer
= RtlAllocateHeap(RtlGetProcessHeap(),
707 if (lpMessageBuffer
== NULL
)
709 /* Free the service table */
710 for (i
= 0; i
< dwActiveServiceCount
; i
++)
712 RtlFreeUnicodeString(&lpActiveServices
[i
].ServiceName
);
714 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices
);
715 lpActiveServices
= NULL
;
716 dwActiveServiceCount
= 0;
721 ScServiceDispatcher(hPipe
, lpMessageBuffer
, 256);
724 /* Free the message buffer */
725 RtlFreeHeap(RtlGetProcessHeap(), 0, lpMessageBuffer
);
727 /* Free the service table */
728 for (i
= 0; i
< dwActiveServiceCount
; i
++)
730 RtlFreeUnicodeString(&lpActiveServices
[i
].ServiceName
);
732 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices
);
733 lpActiveServices
= NULL
;
734 dwActiveServiceCount
= 0;
740 /**********************************************************************
741 * StartServiceCtrlDispatcherW
746 StartServiceCtrlDispatcherW(const SERVICE_TABLE_ENTRYW
* lpServiceStartTable
)
751 PUCHAR lpMessageBuffer
;
753 TRACE("StartServiceCtrlDispatcherW() called\n");
756 while (lpServiceStartTable
[i
].lpServiceProc
!= NULL
)
761 dwActiveServiceCount
= i
;
762 lpActiveServices
= RtlAllocateHeap(RtlGetProcessHeap(),
764 dwActiveServiceCount
* sizeof(ACTIVE_SERVICE
));
765 if (lpActiveServices
== NULL
)
770 /* Copy service names and start procedure */
771 for (i
= 0; i
< dwActiveServiceCount
; i
++)
773 RtlCreateUnicodeString(&lpActiveServices
[i
].ServiceName
,
774 lpServiceStartTable
[i
].lpServiceName
);
775 lpActiveServices
[i
].Main
.lpFuncW
= lpServiceStartTable
[i
].lpServiceProc
;
776 lpActiveServices
[i
].hService
= (CLIENT_HANDLE
)&lpActiveServices
[i
];
777 lpActiveServices
[i
].bUnicode
= TRUE
;
780 dwError
= ScConnectControlPipe(&hPipe
);
781 if (dwError
!= ERROR_SUCCESS
)
783 /* Free the service table */
784 for (i
= 0; i
< dwActiveServiceCount
; i
++)
786 RtlFreeUnicodeString(&lpActiveServices
[i
].ServiceName
);
788 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices
);
789 lpActiveServices
= NULL
;
790 dwActiveServiceCount
= 0;
794 lpMessageBuffer
= RtlAllocateHeap(RtlGetProcessHeap(),
797 if (lpMessageBuffer
== NULL
)
799 /* Free the service table */
800 for (i
= 0; i
< dwActiveServiceCount
; i
++)
802 RtlFreeUnicodeString(&lpActiveServices
[i
].ServiceName
);
804 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices
);
805 lpActiveServices
= NULL
;
806 dwActiveServiceCount
= 0;
811 ScServiceDispatcher(hPipe
, lpMessageBuffer
, 256);
814 /* Free the message buffer */
815 RtlFreeHeap(RtlGetProcessHeap(), 0, lpMessageBuffer
);
817 /* Free the service table */
818 for (i
= 0; i
< dwActiveServiceCount
; i
++)
820 RtlFreeUnicodeString(&lpActiveServices
[i
].ServiceName
);
822 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices
);
823 lpActiveServices
= NULL
;
824 dwActiveServiceCount
= 0;