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 ******************************************************************/
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 DPRINT("ScServiceMainStub() called\n");
85 lpPtr
= lpService
->Arguments
;
88 DPRINT("arg: %S\n", lpPtr
);
89 dwLen
= wcslen(lpPtr
) + 1;
94 DPRINT("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 DPRINT1("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 DPRINT1("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 DPRINT1("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 DPRINT("Sent SERVICE_HANDLE %lu\n", lpActiveServices
->hService
);
264 return ERROR_SUCCESS
;
269 ScStartService(PSCM_CONTROL_PACKET ControlPacket
)
271 PACTIVE_SERVICE lpService
;
275 DPRINT("ScStartService() called\n");
276 DPRINT("client handle: %lu\n", ControlPacket
->hClient
);
277 DPRINT("Size: %lu\n", ControlPacket
->dwSize
);
278 DPRINT("Service: %S\n", &ControlPacket
->szArguments
[0]);
280 lpService
= (PACTIVE_SERVICE
)ControlPacket
->hClient
;
281 if (lpService
== NULL
)
283 DPRINT1("Service not found\n");
284 return ERROR_SERVICE_DOES_NOT_EXIST
;
287 lpService
->Arguments
= HeapAlloc(GetProcessHeap(),
289 ControlPacket
->dwSize
* 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 DPRINT("ScControlService() called\n");
320 DPRINT("Size: %lu\n", ControlPacket
->dwSize
);
321 DPRINT("Service: %S\n", &ControlPacket
->szArguments
[0]);
323 lpService
= (PACTIVE_SERVICE
)ControlPacket
->hClient
;
324 if (lpService
== NULL
)
326 DPRINT1("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 DPRINT("ScControlService() done\n");
349 return ERROR_SUCCESS
;
354 ScServiceDispatcher(HANDLE hPipe
,
358 PSCM_CONTROL_PACKET ControlPacket
;
361 DWORD dwRunningServices
= 0;
363 DPRINT("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 DPRINT1("Pipe read failed (Error: %lu)\n", GetLastError());
385 /* Execute command */
386 switch (ControlPacket
->dwControl
)
388 case SERVICE_CONTROL_START
:
389 DPRINT("Start command - recieved SERVICE_CONTROL_START\n");
390 if (ScStartService(ControlPacket
) == ERROR_SUCCESS
)
394 case SERVICE_CONTROL_STOP
:
395 DPRINT("Stop command - recieved SERVICE_CONTROL_STOP\n");
396 if (ScControlService(ControlPacket
) == ERROR_SUCCESS
)
401 DPRINT("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 DPRINT("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 DPRINT("RegisterServiceCtrlHandlerEx returning %lu", Service
->hService
);
527 return (SERVICE_STATUS_HANDLE
)Service
->hService
;
531 /**********************************************************************
537 SetServiceBits(SERVICE_STATUS_HANDLE hServiceStatus
,
540 BOOL bUpdateImmediately
)
542 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
547 /**********************************************************************
553 SetServiceStatus(SERVICE_STATUS_HANDLE hServiceStatus
,
554 LPSERVICE_STATUS lpServiceStatus
)
558 DPRINT("SetServiceStatus() called\n");
559 DPRINT("hServiceStatus %lu\n", hServiceStatus
);
563 /* Call to services.exe using RPC */
564 dwError
= ScmrSetServiceStatus(BindingHandle
,
565 (unsigned long)hServiceStatus
,
567 if (dwError
!= ERROR_SUCCESS
)
569 DPRINT1("ScmrSetServiceStatus() failed (Error %lu)\n", dwError
);
570 SetLastError(dwError
);
574 DPRINT("SetServiceStatus() done (ret %lu)\n", dwError
);
580 /**********************************************************************
581 * StartServiceCtrlDispatcherA
586 StartServiceCtrlDispatcherA(LPSERVICE_TABLE_ENTRYA lpServiceStartTable
)
591 PUCHAR lpMessageBuffer
;
593 DPRINT("StartServiceCtrlDispatcherA() called\n");
596 while (lpServiceStartTable
[i
].lpServiceProc
!= NULL
)
601 dwActiveServiceCount
= i
;
602 lpActiveServices
= RtlAllocateHeap(RtlGetProcessHeap(),
604 dwActiveServiceCount
* sizeof(ACTIVE_SERVICE
));
605 if (lpActiveServices
== NULL
)
610 /* Copy service names and start procedure */
611 for (i
= 0; i
< dwActiveServiceCount
; i
++)
613 RtlCreateUnicodeStringFromAsciiz(&lpActiveServices
[i
].ServiceName
,
614 lpServiceStartTable
[i
].lpServiceName
);
615 lpActiveServices
[i
].Main
.lpFuncA
= lpServiceStartTable
[i
].lpServiceProc
;
616 lpActiveServices
[i
].hService
= (CLIENT_HANDLE
)&lpActiveServices
[i
];
617 lpActiveServices
[i
].bUnicode
= FALSE
;
620 dwError
= ScConnectControlPipe(&hPipe
);
621 if (dwError
!= ERROR_SUCCESS
)
623 /* Free the service table */
624 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices
);
625 lpActiveServices
= NULL
;
626 dwActiveServiceCount
= 0;
630 lpMessageBuffer
= RtlAllocateHeap(RtlGetProcessHeap(),
633 if (lpMessageBuffer
== NULL
)
635 /* Free the service table */
636 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices
);
637 lpActiveServices
= NULL
;
638 dwActiveServiceCount
= 0;
643 ScServiceDispatcher(hPipe
, lpMessageBuffer
, 256);
646 /* Free the message buffer */
647 RtlFreeHeap(RtlGetProcessHeap(), 0, lpMessageBuffer
);
649 /* Free the service table */
650 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices
);
651 lpActiveServices
= NULL
;
652 dwActiveServiceCount
= 0;
658 /**********************************************************************
659 * StartServiceCtrlDispatcherW
664 StartServiceCtrlDispatcherW(LPSERVICE_TABLE_ENTRYW lpServiceStartTable
)
669 PUCHAR lpMessageBuffer
;
671 DPRINT("StartServiceCtrlDispatcherW() called\n");
674 while (lpServiceStartTable
[i
].lpServiceProc
!= NULL
)
679 dwActiveServiceCount
= i
;
680 lpActiveServices
= RtlAllocateHeap(RtlGetProcessHeap(),
682 dwActiveServiceCount
* sizeof(ACTIVE_SERVICE
));
683 if (lpActiveServices
== NULL
)
688 /* Copy service names and start procedure */
689 for (i
= 0; i
< dwActiveServiceCount
; i
++)
691 RtlCreateUnicodeString(&lpActiveServices
[i
].ServiceName
,
692 lpServiceStartTable
[i
].lpServiceName
);
693 lpActiveServices
[i
].Main
.lpFuncW
= lpServiceStartTable
[i
].lpServiceProc
;
694 lpActiveServices
[i
].hService
= (CLIENT_HANDLE
)&lpActiveServices
[i
];
695 lpActiveServices
[i
].bUnicode
= TRUE
;
698 dwError
= ScConnectControlPipe(&hPipe
);
699 if (dwError
!= ERROR_SUCCESS
)
701 /* Free the service table */
702 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices
);
703 lpActiveServices
= NULL
;
704 dwActiveServiceCount
= 0;
708 lpMessageBuffer
= RtlAllocateHeap(RtlGetProcessHeap(),
711 if (lpMessageBuffer
== NULL
)
713 /* Free the service table */
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 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices
);
729 lpActiveServices
= NULL
;
730 dwActiveServiceCount
= 0;