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 VOID
HandleBind(VOID
);
25 typedef struct _ACTIVE_SERVICE
27 CLIENT_HANDLE hService
;
28 UNICODE_STRING ServiceName
;
31 LPSERVICE_MAIN_FUNCTIONA lpFuncA
;
32 LPSERVICE_MAIN_FUNCTIONW lpFuncW
;
34 LPHANDLER_FUNCTION HandlerFunction
;
35 LPHANDLER_FUNCTION_EX HandlerFunctionEx
;
36 LPVOID HandlerContext
;
37 SERVICE_STATUS ServiceStatus
;
40 } ACTIVE_SERVICE
, *PACTIVE_SERVICE
;
43 /* GLOBALS *******************************************************************/
45 extern handle_t BindingHandle
;
46 static DWORD dwActiveServiceCount
= 0;
47 static PACTIVE_SERVICE lpActiveServices
= NULL
;
50 /* FUNCTIONS *****************************************************************/
52 static PACTIVE_SERVICE
53 ScLookupServiceByServiceName(LPCWSTR lpServiceName
)
57 for (i
= 0; i
< dwActiveServiceCount
; i
++)
59 if (_wcsicmp(lpActiveServices
[i
].ServiceName
.Buffer
, lpServiceName
) == 0)
61 return &lpActiveServices
[i
];
65 SetLastError(ERROR_SERVICE_DOES_NOT_EXIST
);
72 ScServiceMainStub(LPVOID Context
)
74 PACTIVE_SERVICE lpService
;
80 lpService
= (PACTIVE_SERVICE
)Context
;
82 TRACE("ScServiceMainStub() called\n");
85 lpPtr
= lpService
->Arguments
;
88 TRACE("arg: %S\n", lpPtr
);
89 dwLen
= wcslen(lpPtr
) + 1;
94 TRACE("dwArgCount: %ld\ndwLength: %ld\n", dwArgCount
, dwLength
);
96 /* Build the argument vector and call the main service routine */
97 if (lpService
->bUnicode
)
102 lpArgVector
= HeapAlloc(GetProcessHeap(),
104 (dwArgCount
+ 1) * sizeof(LPWSTR
));
105 if (lpArgVector
== NULL
)
106 return ERROR_OUTOFMEMORY
;
109 Ptr
= lpService
->Arguments
;
112 lpArgVector
[dwArgCount
] = Ptr
;
115 Ptr
+= (wcslen(Ptr
) + 1);
117 lpArgVector
[dwArgCount
] = NULL
;
119 (lpService
->Main
.lpFuncW
)(dwArgCount
, lpArgVector
);
121 HeapFree(GetProcessHeap(),
132 AnsiLength
= WideCharToMultiByte(CP_ACP
,
134 lpService
->Arguments
,
141 return ERROR_INVALID_PARAMETER
; /* ? */
143 AnsiString
= HeapAlloc(GetProcessHeap(),
146 if (AnsiString
== NULL
)
147 return ERROR_OUTOFMEMORY
;
149 WideCharToMultiByte(CP_ACP
,
151 lpService
->Arguments
,
158 AnsiString
[AnsiLength
] = ANSI_NULL
;
160 lpArgVector
= HeapAlloc(GetProcessHeap(),
162 (dwArgCount
+ 1) * sizeof(LPSTR
));
163 if (lpArgVector
== NULL
)
165 HeapFree(GetProcessHeap(),
168 return ERROR_OUTOFMEMORY
;
175 lpArgVector
[dwArgCount
] = Ptr
;
178 Ptr
+= (strlen(Ptr
) + 1);
180 lpArgVector
[dwArgCount
] = NULL
;
182 (lpService
->Main
.lpFuncA
)(dwArgCount
, lpArgVector
);
184 HeapFree(GetProcessHeap(),
187 HeapFree(GetProcessHeap(),
192 return ERROR_SUCCESS
;
197 ScConnectControlPipe(HANDLE
*hPipe
)
199 DWORD dwBytesWritten
;
201 DWORD dwServiceCurrent
= 0;
203 WCHAR NtControlPipeName
[MAX_PATH
+ 1];
204 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
206 /* Get the service number and create the named pipe */
207 RtlZeroMemory(&QueryTable
,
210 QueryTable
[0].Name
= L
"";
211 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
212 QueryTable
[0].EntryContext
= &dwServiceCurrent
;
214 Status
= RtlQueryRegistryValues(RTL_REGISTRY_CONTROL
,
220 if (!NT_SUCCESS(Status
))
222 ERR("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
223 return RtlNtStatusToDosError(Status
);
226 swprintf(NtControlPipeName
, L
"\\\\.\\pipe\\net\\NtControlPipe%u", dwServiceCurrent
);
228 if (!WaitNamedPipeW(NtControlPipeName
, 15000))
230 ERR("WaitNamedPipe(%S) failed (Error %lu)\n", NtControlPipeName
, GetLastError());
231 return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT
;
234 *hPipe
= CreateFileW(NtControlPipeName
,
235 GENERIC_READ
| GENERIC_WRITE
,
239 FILE_ATTRIBUTE_NORMAL
,
241 if (*hPipe
== INVALID_HANDLE_VALUE
)
243 ERR("CreateFileW() failed (Error %lu)\n", GetLastError());
244 return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT
;
247 dwState
= PIPE_READMODE_MESSAGE
;
248 if (!SetNamedPipeHandleState(*hPipe
, &dwState
, NULL
, NULL
))
251 *hPipe
= INVALID_HANDLE_VALUE
;
252 return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT
;
255 /* Share the SERVICE_HANDLE handle with the SCM */
257 (DWORD
*)&lpActiveServices
->hService
,
258 sizeof(CLIENT_HANDLE
),
262 TRACE("Sent SERVICE_HANDLE %lu\n", lpActiveServices
->hService
);
264 return ERROR_SUCCESS
;
269 ScStartService(PSCM_CONTROL_PACKET ControlPacket
)
271 PACTIVE_SERVICE lpService
;
275 TRACE("ScStartService() called\n");
276 TRACE("client handle: %lu\n", ControlPacket
->hClient
);
277 TRACE("Size: %lu\n", ControlPacket
->dwSize
);
278 TRACE("Service: %S\n", &ControlPacket
->szArguments
[0]);
280 lpService
= (PACTIVE_SERVICE
)(ULONG_PTR
)ControlPacket
->hClient
;
281 if (lpService
== NULL
)
283 TRACE("Service not found\n");
284 return ERROR_SERVICE_DOES_NOT_EXIST
;
287 lpService
->Arguments
= HeapAlloc(GetProcessHeap(),
289 (ControlPacket
->dwSize
+ 1) * sizeof(WCHAR
));
290 if (lpService
->Arguments
== NULL
)
291 return ERROR_OUTOFMEMORY
;
293 memcpy(lpService
->Arguments
,
294 ControlPacket
->szArguments
,
295 ControlPacket
->dwSize
* sizeof(WCHAR
));
297 /* invoke the services entry point and implement the command loop */
298 ThreadHandle
= CreateThread(NULL
,
304 if (ThreadHandle
== NULL
)
305 return ERROR_SERVICE_NO_THREAD
;
307 ResumeThread(ThreadHandle
);
308 CloseHandle(ThreadHandle
);
310 return ERROR_SUCCESS
;
315 ScControlService(PSCM_CONTROL_PACKET ControlPacket
)
317 PACTIVE_SERVICE lpService
;
319 TRACE("ScControlService() called\n");
320 TRACE("Size: %lu\n", ControlPacket
->dwSize
);
321 TRACE("Service: %S\n", &ControlPacket
->szArguments
[0]);
323 lpService
= (PACTIVE_SERVICE
)(ULONG_PTR
)ControlPacket
->hClient
;
324 if (lpService
== NULL
)
326 TRACE("Service not found\n");
327 return ERROR_SERVICE_DOES_NOT_EXIST
;
330 if (lpService
->HandlerFunction
)
332 (lpService
->HandlerFunction
)(ControlPacket
->dwControl
);
334 else if (lpService
->HandlerFunctionEx
)
336 /* FIXME: send correct params */
337 (lpService
->HandlerFunctionEx
)(ControlPacket
->dwControl
, 0, NULL
, NULL
);
340 if (ControlPacket
->dwControl
== SERVICE_CONTROL_STOP
)
342 HeapFree(GetProcessHeap(),
344 lpService
->Arguments
);
347 TRACE("ScControlService() done\n");
349 return ERROR_SUCCESS
;
354 ScServiceDispatcher(HANDLE hPipe
,
358 PSCM_CONTROL_PACKET ControlPacket
;
361 DWORD dwRunningServices
= 0;
363 TRACE("ScDispatcherLoop() called\n");
365 ControlPacket
= HeapAlloc(GetProcessHeap(),
368 if (ControlPacket
== NULL
)
373 /* Read command from the control pipe */
374 bResult
= ReadFile(hPipe
,
379 if (bResult
== FALSE
)
381 ERR("Pipe read failed (Error: %lu)\n", GetLastError());
385 /* Execute command */
386 switch (ControlPacket
->dwControl
)
388 case SERVICE_CONTROL_START
:
389 TRACE("Start command - recieved SERVICE_CONTROL_START\n");
390 if (ScStartService(ControlPacket
) == ERROR_SUCCESS
)
394 case SERVICE_CONTROL_STOP
:
395 TRACE("Stop command - recieved SERVICE_CONTROL_STOP\n");
396 if (ScControlService(ControlPacket
) == ERROR_SUCCESS
)
401 TRACE("Unknown command %lu", ControlPacket
->dwControl
);
405 if (dwRunningServices
== 0)
409 HeapFree(GetProcessHeap(),
417 /**********************************************************************
418 * RegisterServiceCtrlHandlerA
422 SERVICE_STATUS_HANDLE STDCALL
423 RegisterServiceCtrlHandlerA(LPCSTR lpServiceName
,
424 LPHANDLER_FUNCTION lpHandlerProc
)
426 ANSI_STRING ServiceNameA
;
427 UNICODE_STRING ServiceNameU
;
428 SERVICE_STATUS_HANDLE SHandle
;
430 RtlInitAnsiString(&ServiceNameA
, (LPSTR
)lpServiceName
);
431 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ServiceNameU
, &ServiceNameA
, TRUE
)))
433 SetLastError(ERROR_OUTOFMEMORY
);
434 return (SERVICE_STATUS_HANDLE
)0;
437 SHandle
= RegisterServiceCtrlHandlerW(ServiceNameU
.Buffer
,
440 RtlFreeUnicodeString(&ServiceNameU
);
446 /**********************************************************************
447 * RegisterServiceCtrlHandlerW
451 SERVICE_STATUS_HANDLE STDCALL
452 RegisterServiceCtrlHandlerW(LPCWSTR lpServiceName
,
453 LPHANDLER_FUNCTION lpHandlerProc
)
455 PACTIVE_SERVICE Service
;
457 Service
= ScLookupServiceByServiceName((LPWSTR
)lpServiceName
);
460 return (SERVICE_STATUS_HANDLE
)NULL
;
463 Service
->HandlerFunction
= lpHandlerProc
;
464 Service
->HandlerFunctionEx
= NULL
;
466 TRACE("RegisterServiceCtrlHandler returning %lu\n", Service
->hService
);
468 return (SERVICE_STATUS_HANDLE
)Service
->hService
;
472 /**********************************************************************
473 * RegisterServiceCtrlHandlerExA
477 SERVICE_STATUS_HANDLE STDCALL
478 RegisterServiceCtrlHandlerExA(LPCSTR lpServiceName
,
479 LPHANDLER_FUNCTION_EX lpHandlerProc
,
482 ANSI_STRING ServiceNameA
;
483 UNICODE_STRING ServiceNameU
;
484 SERVICE_STATUS_HANDLE SHandle
;
486 RtlInitAnsiString(&ServiceNameA
, (LPSTR
)lpServiceName
);
487 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ServiceNameU
, &ServiceNameA
, TRUE
)))
489 SetLastError(ERROR_OUTOFMEMORY
);
490 return (SERVICE_STATUS_HANDLE
)0;
493 SHandle
= RegisterServiceCtrlHandlerExW(ServiceNameU
.Buffer
,
497 RtlFreeUnicodeString(&ServiceNameU
);
503 /**********************************************************************
504 * RegisterServiceCtrlHandlerExW
508 SERVICE_STATUS_HANDLE STDCALL
509 RegisterServiceCtrlHandlerExW(LPCWSTR lpServiceName
,
510 LPHANDLER_FUNCTION_EX lpHandlerProc
,
513 PACTIVE_SERVICE Service
;
515 Service
= ScLookupServiceByServiceName(lpServiceName
);
518 return (SERVICE_STATUS_HANDLE
)NULL
;
521 Service
->HandlerFunction
= NULL
;
522 Service
->HandlerFunctionEx
= lpHandlerProc
;
523 Service
->HandlerContext
= lpContext
;
525 TRACE("RegisterServiceCtrlHandlerEx returning %lu", Service
->hService
);
527 return (SERVICE_STATUS_HANDLE
)Service
->hService
;
531 /**********************************************************************
532 * I_ScSetServiceBitsA
539 I_ScSetServiceBitsA(SC_RPC_HANDLE hServiceStatus
,
542 BOOL bUpdateImmediately
,
551 /* Call to services.exe using RPC */
552 bResult
= RI_ScSetServiceBitsA(BindingHandle
,
553 (SC_RPC_HANDLE
)hServiceStatus
,
561 SetLastError(ScmRpcStatusToWinError(RpcExceptionCode()));
570 /**********************************************************************
571 * I_ScSetServiceBitsW
578 I_ScSetServiceBitsW(SC_RPC_HANDLE hServiceStatus
,
581 BOOL bUpdateImmediately
,
590 /* Call to services.exe using RPC */
591 bResult
= RI_ScSetServiceBitsW(BindingHandle
,
592 (SC_RPC_HANDLE
)hServiceStatus
,
600 SetLastError(ScmRpcStatusToWinError(RpcExceptionCode()));
609 /**********************************************************************
615 SetServiceBits(SERVICE_STATUS_HANDLE hServiceStatus
,
618 BOOL bUpdateImmediately
)
620 return I_ScSetServiceBitsW(hServiceStatus
,
628 /**********************************************************************
634 SetServiceStatus(SERVICE_STATUS_HANDLE hServiceStatus
,
635 LPSERVICE_STATUS lpServiceStatus
)
639 TRACE("SetServiceStatus() called\n");
640 TRACE("hServiceStatus %lu\n", hServiceStatus
);
644 /* Call to services.exe using RPC */
645 dwError
= RSetServiceStatus(BindingHandle
,
646 (SC_RPC_HANDLE
)hServiceStatus
,
648 if (dwError
!= ERROR_SUCCESS
)
650 ERR("ScmrSetServiceStatus() failed (Error %lu)\n", dwError
);
651 SetLastError(dwError
);
655 TRACE("SetServiceStatus() done (ret %lu)\n", dwError
);
661 /**********************************************************************
662 * StartServiceCtrlDispatcherA
667 StartServiceCtrlDispatcherA(LPSERVICE_TABLE_ENTRYA lpServiceStartTable
)
672 PUCHAR lpMessageBuffer
;
674 TRACE("StartServiceCtrlDispatcherA() called\n");
677 while (lpServiceStartTable
[i
].lpServiceProc
!= NULL
)
682 dwActiveServiceCount
= i
;
683 lpActiveServices
= RtlAllocateHeap(RtlGetProcessHeap(),
685 dwActiveServiceCount
* sizeof(ACTIVE_SERVICE
));
686 if (lpActiveServices
== NULL
)
691 /* Copy service names and start procedure */
692 for (i
= 0; i
< dwActiveServiceCount
; i
++)
694 RtlCreateUnicodeStringFromAsciiz(&lpActiveServices
[i
].ServiceName
,
695 lpServiceStartTable
[i
].lpServiceName
);
696 lpActiveServices
[i
].Main
.lpFuncA
= lpServiceStartTable
[i
].lpServiceProc
;
697 lpActiveServices
[i
].hService
= (CLIENT_HANDLE
)&lpActiveServices
[i
];
698 lpActiveServices
[i
].bUnicode
= FALSE
;
701 dwError
= ScConnectControlPipe(&hPipe
);
702 if (dwError
!= ERROR_SUCCESS
)
704 /* Free the service table */
705 for (i
= 0; i
< dwActiveServiceCount
; i
++)
707 RtlFreeUnicodeString(&lpActiveServices
[i
].ServiceName
);
709 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices
);
710 lpActiveServices
= NULL
;
711 dwActiveServiceCount
= 0;
715 lpMessageBuffer
= RtlAllocateHeap(RtlGetProcessHeap(),
718 if (lpMessageBuffer
== NULL
)
720 /* Free the service table */
721 for (i
= 0; i
< dwActiveServiceCount
; i
++)
723 RtlFreeUnicodeString(&lpActiveServices
[i
].ServiceName
);
725 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices
);
726 lpActiveServices
= NULL
;
727 dwActiveServiceCount
= 0;
732 ScServiceDispatcher(hPipe
, lpMessageBuffer
, 256);
735 /* Free the message buffer */
736 RtlFreeHeap(RtlGetProcessHeap(), 0, lpMessageBuffer
);
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;
751 /**********************************************************************
752 * StartServiceCtrlDispatcherW
757 StartServiceCtrlDispatcherW(LPSERVICE_TABLE_ENTRYW lpServiceStartTable
)
762 PUCHAR lpMessageBuffer
;
764 TRACE("StartServiceCtrlDispatcherW() called\n");
767 while (lpServiceStartTable
[i
].lpServiceProc
!= NULL
)
772 dwActiveServiceCount
= i
;
773 lpActiveServices
= RtlAllocateHeap(RtlGetProcessHeap(),
775 dwActiveServiceCount
* sizeof(ACTIVE_SERVICE
));
776 if (lpActiveServices
== NULL
)
781 /* Copy service names and start procedure */
782 for (i
= 0; i
< dwActiveServiceCount
; i
++)
784 RtlCreateUnicodeString(&lpActiveServices
[i
].ServiceName
,
785 lpServiceStartTable
[i
].lpServiceName
);
786 lpActiveServices
[i
].Main
.lpFuncW
= lpServiceStartTable
[i
].lpServiceProc
;
787 lpActiveServices
[i
].hService
= (CLIENT_HANDLE
)&lpActiveServices
[i
];
788 lpActiveServices
[i
].bUnicode
= TRUE
;
791 dwError
= ScConnectControlPipe(&hPipe
);
792 if (dwError
!= ERROR_SUCCESS
)
794 /* Free the service table */
795 for (i
= 0; i
< dwActiveServiceCount
; i
++)
797 RtlFreeUnicodeString(&lpActiveServices
[i
].ServiceName
);
799 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices
);
800 lpActiveServices
= NULL
;
801 dwActiveServiceCount
= 0;
805 lpMessageBuffer
= RtlAllocateHeap(RtlGetProcessHeap(),
808 if (lpMessageBuffer
== NULL
)
810 /* Free the service table */
811 for (i
= 0; i
< dwActiveServiceCount
; i
++)
813 RtlFreeUnicodeString(&lpActiveServices
[i
].ServiceName
);
815 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices
);
816 lpActiveServices
= NULL
;
817 dwActiveServiceCount
= 0;
822 ScServiceDispatcher(hPipe
, lpMessageBuffer
, 256);
825 /* Free the message buffer */
826 RtlFreeHeap(RtlGetProcessHeap(), 0, lpMessageBuffer
);
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;