3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS system libraries
5 * FILE: lib/advapi32/service/sctrl.c
6 * PURPOSE: Service control manager functions
7 * PROGRAMMER: Emanuele Aliberti
13 /* INCLUDES ******************************************************************/
21 /* TYPES *********************************************************************/
23 typedef struct _ACTIVE_SERVICE
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
);
68 static PACTIVE_SERVICE
69 ScLookupServiceByThreadId(DWORD ThreadId
)
73 for (i
= 0; i
< dwActiveServiceCount
; i
++)
75 if (lpActiveServices
[i
].ThreadId
== ThreadId
)
77 return &lpActiveServices
[i
];
81 SetLastError(ERROR_SERVICE_DOES_NOT_EXIST
);
88 ScServiceMainStub(LPVOID Context
)
90 PACTIVE_SERVICE lpService
;
96 lpService
= (PACTIVE_SERVICE
)Context
;
98 DPRINT("ScServiceMainStub() called\n");
100 /* Count arguments */
101 lpPtr
= lpService
->Arguments
;
104 DPRINT("arg: %S\n", *lpPtr
);
105 dwLen
= wcslen(lpPtr
) + 1;
110 DPRINT("dwArgCount: %ld\ndwLength: %ld\n", dwArgCount
, dwLength
);
112 /* Build the argument vector and call the main service routine */
113 if (lpService
->bUnicode
)
118 lpArgVector
= HeapAlloc(GetProcessHeap(),
120 (dwArgCount
+ 1) * sizeof(LPWSTR
));
121 if (lpArgVector
== NULL
)
122 return ERROR_OUTOFMEMORY
;
125 Ptr
= lpService
->Arguments
;
128 lpArgVector
[dwArgCount
] = Ptr
;
131 Ptr
+= (wcslen(Ptr
) + 1);
133 lpArgVector
[dwArgCount
] = NULL
;
135 (lpService
->Main
.lpFuncW
)(dwArgCount
, lpArgVector
);
137 HeapFree(GetProcessHeap(),
148 AnsiLength
= WideCharToMultiByte(CP_ACP
,
150 lpService
->Arguments
,
156 AnsiString
= HeapAlloc(GetProcessHeap(),
159 WideCharToMultiByte(CP_ACP
,
161 lpService
->Arguments
,
168 lpArgVector
= HeapAlloc(GetProcessHeap(),
170 (dwArgCount
+ 1) * sizeof(LPSTR
));
176 lpArgVector
[dwArgCount
] = Ptr
;
179 Ptr
+= (strlen(Ptr
) + 1);
181 lpArgVector
[dwArgCount
] = NULL
;
183 (lpService
->Main
.lpFuncA
)(dwArgCount
, lpArgVector
);
185 HeapFree(GetProcessHeap(),
188 HeapFree(GetProcessHeap(),
193 return ERROR_SUCCESS
;
198 ScConnectControlPipe(HANDLE
*hPipe
)
200 DWORD dwBytesWritten
;
204 if (!WaitNamedPipeW(L
"\\\\.\\pipe\\net\\NtControlPipe", 15000))
206 DPRINT1("WaitNamedPipe() failed (Error %lu)\n", GetLastError());
207 return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT
;
210 *hPipe
= CreateFileW(L
"\\\\.\\pipe\\net\\NtControlPipe",
211 GENERIC_READ
| GENERIC_WRITE
,
215 FILE_ATTRIBUTE_NORMAL
,
217 if (*hPipe
== INVALID_HANDLE_VALUE
)
219 DPRINT1("CreateFileW() failed (Error %lu)\n", GetLastError());
220 return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT
;
223 dwState
= PIPE_READMODE_MESSAGE
;
224 if (!SetNamedPipeHandleState(*hPipe
, &dwState
, NULL
, NULL
))
227 *hPipe
= INVALID_HANDLE_VALUE
;
228 return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT
;
231 dwProcessId
= GetCurrentProcessId();
238 DPRINT("Sent process id %lu\n", dwProcessId
);
240 return ERROR_SUCCESS
;
246 ScStartService(PSCM_CONTROL_PACKET ControlPacket
)
248 PACTIVE_SERVICE lpService
;
251 DPRINT("ScStartService() called\n");
252 DPRINT("Size: %lu\n", ControlPacket
->dwSize
);
253 DPRINT("Service: %S\n", &ControlPacket
->szArguments
[0]);
255 lpService
= ScLookupServiceByServiceName(&ControlPacket
->szArguments
[0]);
256 if (lpService
== NULL
)
257 return ERROR_SERVICE_DOES_NOT_EXIST
;
259 lpService
->Arguments
= HeapAlloc(GetProcessHeap(),
261 ControlPacket
->dwSize
* sizeof(WCHAR
));
262 if (lpService
->Arguments
== NULL
)
263 return ERROR_OUTOFMEMORY
;
265 memcpy(lpService
->Arguments
,
266 ControlPacket
->szArguments
,
267 ControlPacket
->dwSize
* sizeof(WCHAR
));
269 ThreadHandle
= CreateThread(NULL
,
274 &lpService
->ThreadId
);
275 if (ThreadHandle
== NULL
)
276 return ERROR_SERVICE_NO_THREAD
;
278 ResumeThread(ThreadHandle
);
279 CloseHandle(ThreadHandle
);
281 return ERROR_SUCCESS
;
286 ScServiceDispatcher(HANDLE hPipe
,
290 PSCM_CONTROL_PACKET ControlPacket
;
293 DWORD dwRunningServices
= 0;
295 DPRINT("ScDispatcherLoop() called\n");
297 ControlPacket
= HeapAlloc(GetProcessHeap(),
300 if (ControlPacket
== NULL
)
305 /* Read command from the control pipe */
306 bResult
= ReadFile(hPipe
,
311 if (bResult
== FALSE
)
313 DPRINT1("Pipe read failed (Error: %lu)\n", GetLastError());
317 /* Execute command */
318 switch (ControlPacket
->dwControl
)
320 case SERVICE_CONTROL_START
:
321 DPRINT("Start command\n");
322 if (ScStartService(ControlPacket
) == ERROR_SUCCESS
)
326 case SERVICE_CONTROL_STOP
:
327 DPRINT("Stop command\n");
332 DPRINT1("Unknown command %lu", ControlPacket
->dwControl
);
336 if (dwRunningServices
== 0)
340 HeapFree(GetProcessHeap(),
348 /**********************************************************************
349 * RegisterServiceCtrlHandlerA
353 SERVICE_STATUS_HANDLE STDCALL
354 RegisterServiceCtrlHandlerA(LPCSTR lpServiceName
,
355 LPHANDLER_FUNCTION lpHandlerProc
)
357 ANSI_STRING ServiceNameA
;
358 UNICODE_STRING ServiceNameU
;
359 SERVICE_STATUS_HANDLE SHandle
;
361 RtlInitAnsiString(&ServiceNameA
, (LPSTR
)lpServiceName
);
362 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ServiceNameU
, &ServiceNameA
, TRUE
)))
364 SetLastError(ERROR_OUTOFMEMORY
);
365 return (SERVICE_STATUS_HANDLE
)0;
368 SHandle
= RegisterServiceCtrlHandlerW(ServiceNameU
.Buffer
,
371 RtlFreeUnicodeString(&ServiceNameU
);
377 /**********************************************************************
378 * RegisterServiceCtrlHandlerW
382 SERVICE_STATUS_HANDLE STDCALL
383 RegisterServiceCtrlHandlerW(LPCWSTR lpServiceName
,
384 LPHANDLER_FUNCTION lpHandlerProc
)
386 PACTIVE_SERVICE Service
;
388 Service
= ScLookupServiceByServiceName((LPWSTR
)lpServiceName
);
391 return (SERVICE_STATUS_HANDLE
)NULL
;
394 Service
->HandlerFunction
= lpHandlerProc
;
395 Service
->HandlerFunctionEx
= NULL
;
397 return (SERVICE_STATUS_HANDLE
)Service
->ThreadId
;
401 /**********************************************************************
402 * RegisterServiceCtrlHandlerExA
406 SERVICE_STATUS_HANDLE STDCALL
407 RegisterServiceCtrlHandlerExA(LPCSTR lpServiceName
,
408 LPHANDLER_FUNCTION_EX lpHandlerProc
,
411 ANSI_STRING ServiceNameA
;
412 UNICODE_STRING ServiceNameU
;
413 SERVICE_STATUS_HANDLE SHandle
;
415 RtlInitAnsiString(&ServiceNameA
, (LPSTR
)lpServiceName
);
416 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ServiceNameU
, &ServiceNameA
, TRUE
)))
418 SetLastError(ERROR_OUTOFMEMORY
);
419 return (SERVICE_STATUS_HANDLE
)0;
422 SHandle
= RegisterServiceCtrlHandlerExW(ServiceNameU
.Buffer
,
426 RtlFreeUnicodeString(&ServiceNameU
);
432 /**********************************************************************
433 * RegisterServiceCtrlHandlerExW
437 SERVICE_STATUS_HANDLE STDCALL
438 RegisterServiceCtrlHandlerExW(LPCWSTR lpServiceName
,
439 LPHANDLER_FUNCTION_EX lpHandlerProc
,
442 PACTIVE_SERVICE Service
;
444 Service
= ScLookupServiceByServiceName(lpServiceName
);
447 return (SERVICE_STATUS_HANDLE
)NULL
;
450 Service
->HandlerFunction
= NULL
;
451 Service
->HandlerFunctionEx
= lpHandlerProc
;
452 Service
->HandlerContext
= lpContext
;
454 return (SERVICE_STATUS_HANDLE
)Service
->ThreadId
;
458 /**********************************************************************
464 SetServiceBits(SERVICE_STATUS_HANDLE hServiceStatus
,
467 BOOL bUpdateImmediately
)
469 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
474 /**********************************************************************
480 SetServiceStatus(SERVICE_STATUS_HANDLE hServiceStatus
,
481 LPSERVICE_STATUS lpServiceStatus
)
483 PACTIVE_SERVICE Service
;
485 Service
= ScLookupServiceByThreadId((DWORD
)hServiceStatus
);
488 SetLastError(ERROR_INVALID_HANDLE
);
492 RtlCopyMemory(&Service
->ServiceStatus
,
494 sizeof(SERVICE_STATUS
));
500 /**********************************************************************
501 * StartServiceCtrlDispatcherA
506 StartServiceCtrlDispatcherA(LPSERVICE_TABLE_ENTRYA lpServiceStartTable
)
511 PUCHAR lpMessageBuffer
;
513 DPRINT("StartServiceCtrlDispatcherA() called\n");
516 while (lpServiceStartTable
[i
].lpServiceProc
!= NULL
)
521 dwActiveServiceCount
= i
;
522 lpActiveServices
= RtlAllocateHeap(RtlGetProcessHeap(),
524 dwActiveServiceCount
* sizeof(ACTIVE_SERVICE
));
525 if (lpActiveServices
== NULL
)
530 /* Copy service names and start procedure */
531 for (i
= 0; i
< dwActiveServiceCount
; i
++)
533 RtlCreateUnicodeStringFromAsciiz(&lpActiveServices
[i
].ServiceName
,
534 lpServiceStartTable
[i
].lpServiceName
);
535 lpActiveServices
[i
].Main
.lpFuncA
= lpServiceStartTable
[i
].lpServiceProc
;
536 lpActiveServices
[i
].bUnicode
= FALSE
;
539 dwError
= ScConnectControlPipe(&hPipe
);
540 if (dwError
!= ERROR_SUCCESS
)
542 /* Free the service table */
543 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices
);
544 lpActiveServices
= NULL
;
545 dwActiveServiceCount
= 0;
549 lpMessageBuffer
= RtlAllocateHeap(RtlGetProcessHeap(),
552 if (lpMessageBuffer
== NULL
)
554 /* Free the service table */
555 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices
);
556 lpActiveServices
= NULL
;
557 dwActiveServiceCount
= 0;
562 ScServiceDispatcher(hPipe
, lpMessageBuffer
, 256);
565 /* Free the message buffer */
566 RtlFreeHeap(RtlGetProcessHeap(), 0, lpMessageBuffer
);
568 /* Free the service table */
569 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices
);
570 lpActiveServices
= NULL
;
571 dwActiveServiceCount
= 0;
577 /**********************************************************************
578 * StartServiceCtrlDispatcherW
583 StartServiceCtrlDispatcherW(LPSERVICE_TABLE_ENTRYW lpServiceStartTable
)
588 PUCHAR lpMessageBuffer
;
590 DPRINT("StartServiceCtrlDispatcherW() called\n");
593 while (lpServiceStartTable
[i
].lpServiceProc
!= NULL
)
598 dwActiveServiceCount
= i
;
599 lpActiveServices
= RtlAllocateHeap(RtlGetProcessHeap(),
601 dwActiveServiceCount
* sizeof(ACTIVE_SERVICE
));
602 if (lpActiveServices
== NULL
)
607 /* Copy service names and start procedure */
608 for (i
= 0; i
< dwActiveServiceCount
; i
++)
610 RtlCreateUnicodeString(&lpActiveServices
[i
].ServiceName
,
611 lpServiceStartTable
[i
].lpServiceName
);
612 lpActiveServices
[i
].Main
.lpFuncW
= lpServiceStartTable
[i
].lpServiceProc
;
613 lpActiveServices
[i
].bUnicode
= TRUE
;
616 dwError
= ScConnectControlPipe(&hPipe
);
617 if (dwError
!= ERROR_SUCCESS
)
619 /* Free the service table */
620 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices
);
621 lpActiveServices
= NULL
;
622 dwActiveServiceCount
= 0;
626 lpMessageBuffer
= RtlAllocateHeap(RtlGetProcessHeap(),
629 if (lpMessageBuffer
== NULL
)
631 /* Free the service table */
632 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices
);
633 lpActiveServices
= NULL
;
634 dwActiveServiceCount
= 0;
639 ScServiceDispatcher(hPipe
, lpMessageBuffer
, 256);
642 /* Free the message buffer */
643 RtlFreeHeap(RtlGetProcessHeap(), 0, lpMessageBuffer
);
645 /* Free the service table */
646 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices
);
647 lpActiveServices
= NULL
;
648 dwActiveServiceCount
= 0;