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>
12 /* INCLUDES ******************************************************************/
15 WINE_DEFAULT_DEBUG_CHANNEL(advapi
);
18 /* TYPES *********************************************************************/
20 typedef struct _SERVICE_THREAD_PARAMSA
22 LPSERVICE_MAIN_FUNCTIONA lpServiceMain
;
26 } SERVICE_THREAD_PARAMSA
, *PSERVICE_THREAD_PARAMSA
;
29 typedef struct _SERVICE_THREAD_PARAMSW
31 LPSERVICE_MAIN_FUNCTIONW lpServiceMain
;
35 } SERVICE_THREAD_PARAMSW
, *PSERVICE_THREAD_PARAMSW
;
38 typedef struct _ACTIVE_SERVICE
40 SERVICE_STATUS_HANDLE hServiceStatus
;
41 UNICODE_STRING ServiceName
;
44 LPSERVICE_MAIN_FUNCTIONA A
;
45 LPSERVICE_MAIN_FUNCTIONW W
;
47 LPHANDLER_FUNCTION HandlerFunction
;
48 LPHANDLER_FUNCTION_EX HandlerFunctionEx
;
49 LPVOID HandlerContext
;
53 } ACTIVE_SERVICE
, *PACTIVE_SERVICE
;
56 /* GLOBALS *******************************************************************/
58 static DWORD dwActiveServiceCount
= 0;
59 static PACTIVE_SERVICE lpActiveServices
= NULL
;
60 static handle_t hStatusBinding
= NULL
;
61 static BOOL bSecurityServiceProcess
= FALSE
;
64 /* FUNCTIONS *****************************************************************/
67 RPC_SERVICE_STATUS_HANDLE_bind(RPC_SERVICE_STATUS_HANDLE hServiceStatus
)
69 return hStatusBinding
;
74 RPC_SERVICE_STATUS_HANDLE_unbind(RPC_SERVICE_STATUS_HANDLE hServiceStatus
,
81 ScCreateStatusBinding(VOID
)
83 LPWSTR pszStringBinding
;
86 TRACE("ScCreateStatusBinding()\n");
88 status
= RpcStringBindingComposeW(NULL
,
94 if (status
!= RPC_S_OK
)
96 ERR("RpcStringBindingCompose returned 0x%x\n", status
);
100 /* Set the binding handle that will be used to bind to the server. */
101 status
= RpcBindingFromStringBindingW(pszStringBinding
,
103 if (status
!= RPC_S_OK
)
105 ERR("RpcBindingFromStringBinding returned 0x%x\n", status
);
108 status
= RpcStringFreeW(&pszStringBinding
);
109 if (status
!= RPC_S_OK
)
111 ERR("RpcStringFree returned 0x%x\n", status
);
119 ScDestroyStatusBinding(VOID
)
123 TRACE("ScDestroyStatusBinding()\n");
125 if (hStatusBinding
== NULL
)
128 status
= RpcBindingFree(&hStatusBinding
);
129 if (status
!= RPC_S_OK
)
131 ERR("RpcBindingFree returned 0x%x\n", status
);
135 hStatusBinding
= NULL
;
142 static PACTIVE_SERVICE
143 ScLookupServiceByServiceName(LPCWSTR lpServiceName
)
147 TRACE("ScLookupServiceByServiceName(%S)\n",
150 if (lpActiveServices
[0].bOwnProcess
)
151 return &lpActiveServices
[0];
153 for (i
= 0; i
< dwActiveServiceCount
; i
++)
155 TRACE("Checking %S\n", lpActiveServices
[i
].ServiceName
.Buffer
);
156 if (_wcsicmp(lpActiveServices
[i
].ServiceName
.Buffer
, lpServiceName
) == 0)
159 return &lpActiveServices
[i
];
163 TRACE("No service found!\n");
169 ScServiceMainStubA(LPVOID Context
)
172 PSERVICE_THREAD_PARAMSA ThreadParams
= Context
;
174 TRACE("ScServiceMainStubA(%p)\n", Context
);
176 /* Set service tag */
177 Teb
= NtCurrentTeb();
178 Teb
->SubProcessTag
= UlongToPtr(ThreadParams
->dwServiceTag
);
180 /* Call the main service routine and free the arguments vector */
181 (ThreadParams
->lpServiceMain
)(ThreadParams
->dwArgCount
,
182 ThreadParams
->lpArgVector
);
184 /* Reset service tag */
185 Teb
->SubProcessTag
= 0;
187 if (ThreadParams
->lpArgVector
!= NULL
)
189 HeapFree(GetProcessHeap(), 0, ThreadParams
->lpArgVector
);
191 HeapFree(GetProcessHeap(), 0, ThreadParams
);
193 return ERROR_SUCCESS
;
198 ScServiceMainStubW(LPVOID Context
)
201 PSERVICE_THREAD_PARAMSW ThreadParams
= Context
;
203 TRACE("ScServiceMainStubW(%p)\n", Context
);
205 /* Set service tag */
206 Teb
= NtCurrentTeb();
207 Teb
->SubProcessTag
= UlongToPtr(ThreadParams
->dwServiceTag
);
209 /* Call the main service routine and free the arguments vector */
210 (ThreadParams
->lpServiceMain
)(ThreadParams
->dwArgCount
,
211 ThreadParams
->lpArgVector
);
213 /* Reset service tag */
214 Teb
->SubProcessTag
= 0;
216 if (ThreadParams
->lpArgVector
!= NULL
)
218 HeapFree(GetProcessHeap(), 0, ThreadParams
->lpArgVector
);
220 HeapFree(GetProcessHeap(), 0, ThreadParams
);
222 return ERROR_SUCCESS
;
227 ScConnectControlPipe(HANDLE
*hPipe
)
229 DWORD dwBytesWritten
;
231 DWORD dwServiceCurrent
= 1;
233 WCHAR NtControlPipeName
[MAX_PATH
+ 1];
234 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
237 TRACE("ScConnectControlPipe(%p)\n",
240 /* Get the service number and create the named pipe */
241 if (bSecurityServiceProcess
== FALSE
)
243 RtlZeroMemory(&QueryTable
, sizeof(QueryTable
));
245 QueryTable
[0].Name
= L
"";
246 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
247 QueryTable
[0].EntryContext
= &dwServiceCurrent
;
249 Status
= RtlQueryRegistryValues(RTL_REGISTRY_CONTROL
,
254 if (!NT_SUCCESS(Status
))
256 ERR("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
257 return RtlNtStatusToDosError(Status
);
262 dwServiceCurrent
= 0;
265 swprintf(NtControlPipeName
, L
"\\\\.\\pipe\\net\\NtControlPipe%u", dwServiceCurrent
);
266 TRACE("PipeName: %S\n", NtControlPipeName
);
268 if (!WaitNamedPipeW(NtControlPipeName
, 30000))
270 ERR("WaitNamedPipe(%S) failed (Error %lu)\n", NtControlPipeName
, GetLastError());
271 return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT
;
274 *hPipe
= CreateFileW(NtControlPipeName
,
275 GENERIC_READ
| GENERIC_WRITE
,
276 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
279 FILE_ATTRIBUTE_NORMAL
,
281 if (*hPipe
== INVALID_HANDLE_VALUE
)
283 ERR("CreateFileW() failed for pipe %S (Error %lu)\n", NtControlPipeName
, GetLastError());
284 return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT
;
287 dwState
= PIPE_READMODE_MESSAGE
;
288 if (!SetNamedPipeHandleState(*hPipe
, &dwState
, NULL
, NULL
))
291 *hPipe
= INVALID_HANDLE_VALUE
;
292 return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT
;
295 /* Pass the ProcessId to the SCM */
296 dwProcessId
= GetCurrentProcessId();
303 TRACE("Sent Process ID %lu\n", dwProcessId
);
305 return ERROR_SUCCESS
;
310 * Ansi/Unicode argument layout of the vector passed to a service at startup,
311 * depending on the different versions of Windows considered:
314 * [argv array of pointers][parameter 1][parameter 2]...[service name]
317 * [argv array of pointers][align to 8 bytes]
318 * [parameter 1][parameter 2]...[service name]
321 * [argv array of pointers][service name]
322 * [parameter 1][align to 4 bytes][parameter 2][align to 4 bytes]...
324 * Space for parameters and service name is always enough to store
325 * both the Ansi and the Unicode versions including NULL terminator.
329 ScBuildUnicodeArgsVector(PSCM_CONTROL_PACKET ControlPacket
,
331 LPWSTR
**lpArgVector
)
334 PWSTR pszServiceName
;
340 if (ControlPacket
== NULL
|| lpArgCount
== NULL
|| lpArgVector
== NULL
)
341 return ERROR_INVALID_PARAMETER
;
346 /* Retrieve and count the start command line (NULL-terminated) */
347 pszServiceName
= (PWSTR
)((ULONG_PTR
)ControlPacket
+ ControlPacket
->dwServiceNameOffset
);
348 cbServiceName
= lstrlenW(pszServiceName
) * sizeof(WCHAR
) + sizeof(UNICODE_NULL
);
351 * The total size of the argument vector is equal to the entry for
352 * the service name, plus the size of the original argument vector.
354 cbTotal
= sizeof(PWSTR
) + cbServiceName
;
355 if (ControlPacket
->dwArgumentsCount
> 0)
356 cbArguments
= ControlPacket
->dwSize
- ControlPacket
->dwArgumentsOffset
;
359 cbTotal
+= cbArguments
;
361 /* Allocate the new argument vector */
362 lpVector
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, cbTotal
);
363 if (lpVector
== NULL
)
364 return ERROR_NOT_ENOUGH_MEMORY
;
367 * The first argument is reserved for the service name, which
368 * will be appended to the end of the argument string list.
371 /* Copy the remaining arguments */
372 if (ControlPacket
->dwArgumentsCount
> 0)
375 (PWSTR
)((ULONG_PTR
)ControlPacket
+ ControlPacket
->dwArgumentsOffset
),
378 for (i
= 0; i
< ControlPacket
->dwArgumentsCount
; i
++)
380 lpVector
[i
+ 1] = (PWSTR
)((ULONG_PTR
)&lpVector
[1] + (ULONG_PTR
)lpVector
[i
+ 1]);
381 TRACE("Unicode lpVector[%lu] = '%ls'\n", i
+ 1, lpVector
[i
+ 1]);
385 /* Now copy the service name */
386 lpVector
[0] = (PWSTR
)((ULONG_PTR
)&lpVector
[1] + cbArguments
);
387 memcpy(lpVector
[0], pszServiceName
, cbServiceName
);
388 TRACE("Unicode lpVector[%lu] = '%ls'\n", 0, lpVector
[0]);
390 *lpArgCount
= ControlPacket
->dwArgumentsCount
+ 1;
391 *lpArgVector
= lpVector
;
393 return ERROR_SUCCESS
;
398 ScBuildAnsiArgsVector(PSCM_CONTROL_PACKET ControlPacket
,
407 UNICODE_STRING UnicodeString
;
408 ANSI_STRING AnsiString
;
410 if (ControlPacket
== NULL
|| lpArgCount
== NULL
|| lpArgVector
== NULL
)
411 return ERROR_INVALID_PARAMETER
;
416 /* Build the UNICODE arguments vector */
417 dwError
= ScBuildUnicodeArgsVector(ControlPacket
, &ArgCount
, &lpVectorW
);
418 if (dwError
!= ERROR_SUCCESS
)
421 /* Convert the vector to ANSI in place */
422 lpVectorA
= (PSTR
*)lpVectorW
;
423 for (i
= 0; i
< ArgCount
; i
++)
425 RtlInitUnicodeString(&UnicodeString
, lpVectorW
[i
]);
426 RtlInitEmptyAnsiString(&AnsiString
, lpVectorA
[i
], UnicodeString
.MaximumLength
);
427 Status
= RtlUnicodeStringToAnsiString(&AnsiString
, &UnicodeString
, FALSE
);
428 if (!NT_SUCCESS(Status
))
430 /* Failed to convert to ANSI; free the allocated vector and return */
431 dwError
= RtlNtStatusToDosError(Status
);
432 HeapFree(GetProcessHeap(), 0, lpVectorW
);
436 /* NULL-terminate the string */
437 AnsiString
.Buffer
[AnsiString
.Length
/ sizeof(CHAR
)] = ANSI_NULL
;
439 TRACE("Ansi lpVector[%lu] = '%s'\n", i
, lpVectorA
[i
]);
442 *lpArgCount
= ArgCount
;
443 *lpArgVector
= lpVectorA
;
445 return ERROR_SUCCESS
;
450 ScStartService(PACTIVE_SERVICE lpService
,
451 PSCM_CONTROL_PACKET ControlPacket
)
456 PSERVICE_THREAD_PARAMSA ThreadParamsA
;
457 PSERVICE_THREAD_PARAMSW ThreadParamsW
;
459 TRACE("ScStartService(%p %p)\n",
460 lpService
, ControlPacket
);
462 if (lpService
== NULL
|| ControlPacket
== NULL
)
463 return ERROR_INVALID_PARAMETER
;
465 TRACE("Size: %lu\n", ControlPacket
->dwSize
);
466 TRACE("Service: %S\n", (PWSTR
)((ULONG_PTR
)ControlPacket
+ ControlPacket
->dwServiceNameOffset
));
468 /* Set the service status handle */
469 lpService
->hServiceStatus
= ControlPacket
->hServiceStatus
;
470 /* Set the service tag */
471 lpService
->dwServiceTag
= ControlPacket
->dwServiceTag
;
473 /* Build the arguments vector */
474 if (lpService
->bUnicode
!= FALSE
)
476 ThreadParamsW
= HeapAlloc(GetProcessHeap(), 0, sizeof(*ThreadParamsW
));
477 if (ThreadParamsW
== NULL
)
478 return ERROR_NOT_ENOUGH_MEMORY
;
479 dwError
= ScBuildUnicodeArgsVector(ControlPacket
,
480 &ThreadParamsW
->dwArgCount
,
481 &ThreadParamsW
->lpArgVector
);
482 if (dwError
!= ERROR_SUCCESS
)
484 HeapFree(GetProcessHeap(), 0, ThreadParamsW
);
487 ThreadParamsW
->lpServiceMain
= lpService
->ServiceMain
.W
;
488 ThreadParamsW
->dwServiceTag
= ControlPacket
->dwServiceTag
;
489 ThreadHandle
= CreateThread(NULL
,
495 if (ThreadHandle
== NULL
)
497 if (ThreadParamsW
->lpArgVector
!= NULL
)
499 HeapFree(GetProcessHeap(), 0, ThreadParamsW
->lpArgVector
);
501 HeapFree(GetProcessHeap(), 0, ThreadParamsW
);
503 return ERROR_SERVICE_NO_THREAD
;
506 CloseHandle(ThreadHandle
);
510 ThreadParamsA
= HeapAlloc(GetProcessHeap(), 0, sizeof(*ThreadParamsA
));
511 if (ThreadParamsA
== NULL
)
512 return ERROR_NOT_ENOUGH_MEMORY
;
513 dwError
= ScBuildAnsiArgsVector(ControlPacket
,
514 &ThreadParamsA
->dwArgCount
,
515 &ThreadParamsA
->lpArgVector
);
516 if (dwError
!= ERROR_SUCCESS
)
518 HeapFree(GetProcessHeap(), 0, ThreadParamsA
);
521 ThreadParamsA
->lpServiceMain
= lpService
->ServiceMain
.A
;
522 ThreadParamsA
->dwServiceTag
= ControlPacket
->dwServiceTag
;
523 ThreadHandle
= CreateThread(NULL
,
529 if (ThreadHandle
== NULL
)
531 if (ThreadParamsA
->lpArgVector
!= NULL
)
533 HeapFree(GetProcessHeap(), 0, ThreadParamsA
->lpArgVector
);
535 HeapFree(GetProcessHeap(), 0, ThreadParamsA
);
537 return ERROR_SERVICE_NO_THREAD
;
540 CloseHandle(ThreadHandle
);
543 return ERROR_SUCCESS
;
548 ScControlService(PACTIVE_SERVICE lpService
,
549 PSCM_CONTROL_PACKET ControlPacket
)
551 DWORD dwError
= ERROR_SUCCESS
;
553 TRACE("ScControlService(%p %p)\n",
554 lpService
, ControlPacket
);
556 if (lpService
== NULL
|| ControlPacket
== NULL
)
557 return ERROR_INVALID_PARAMETER
;
559 TRACE("Size: %lu\n", ControlPacket
->dwSize
);
560 TRACE("Service: %S\n", (PWSTR
)((ULONG_PTR
)ControlPacket
+ ControlPacket
->dwServiceNameOffset
));
562 /* Set service tag */
563 NtCurrentTeb()->SubProcessTag
= UlongToPtr(lpService
->dwServiceTag
);
565 if (lpService
->HandlerFunction
)
569 (lpService
->HandlerFunction
)(ControlPacket
->dwControl
);
571 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
573 dwError
= ERROR_EXCEPTION_IN_SERVICE
;
577 else if (lpService
->HandlerFunctionEx
)
581 /* FIXME: Send correct 2nd and 3rd parameters */
582 (lpService
->HandlerFunctionEx
)(ControlPacket
->dwControl
,
584 lpService
->HandlerContext
);
586 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
588 dwError
= ERROR_EXCEPTION_IN_SERVICE
;
594 dwError
= ERROR_SERVICE_CANNOT_ACCEPT_CTRL
;
597 /* Reset service tag */
598 NtCurrentTeb()->SubProcessTag
= 0;
600 TRACE("ScControlService() done (Error %lu)\n", dwError
);
607 ScServiceDispatcher(HANDLE hPipe
,
608 PSCM_CONTROL_PACKET ControlPacket
,
613 BOOL bRunning
= TRUE
;
614 LPWSTR lpServiceName
;
615 PACTIVE_SERVICE lpService
;
616 SCM_REPLY_PACKET ReplyPacket
;
619 TRACE("ScServiceDispatcher(%p %p %lu)\n",
620 hPipe
, ControlPacket
, dwBufferSize
);
622 if (ControlPacket
== NULL
|| dwBufferSize
< sizeof(SCM_CONTROL_PACKET
))
627 /* Read command from the control pipe */
628 bResult
= ReadFile(hPipe
,
633 if (bResult
== FALSE
)
635 ERR("Pipe read failed (Error: %lu)\n", GetLastError());
639 lpServiceName
= (LPWSTR
)((PBYTE
)ControlPacket
+ ControlPacket
->dwServiceNameOffset
);
640 TRACE("Service: %S\n", lpServiceName
);
642 if ((ControlPacket
->dwControl
== SERVICE_CONTROL_STOP
) &&
643 (lpServiceName
[0] == UNICODE_NULL
))
645 TRACE("Stop dispatcher thread\n");
647 dwError
= ERROR_SUCCESS
;
651 if (ControlPacket
->dwControl
== SERVICE_CONTROL_START_OWN
)
652 lpActiveServices
[0].bOwnProcess
= TRUE
;
654 lpService
= ScLookupServiceByServiceName(lpServiceName
);
655 if (lpService
!= NULL
)
657 /* Execute command */
658 switch (ControlPacket
->dwControl
)
660 case SERVICE_CONTROL_START_SHARE
:
661 case SERVICE_CONTROL_START_OWN
:
662 TRACE("Start command - received SERVICE_CONTROL_START\n");
663 dwError
= ScStartService(lpService
, ControlPacket
);
666 case SERVICE_CONTROL_STOP
:
667 TRACE("Stop command - received SERVICE_CONTROL_STOP\n");
668 dwError
= ScControlService(lpService
, ControlPacket
);
672 TRACE("Command %lu received", ControlPacket
->dwControl
);
673 dwError
= ScControlService(lpService
, ControlPacket
);
679 dwError
= ERROR_SERVICE_NOT_IN_EXE
;
683 ReplyPacket
.dwError
= dwError
;
685 /* Send the reply packet */
686 bResult
= WriteFile(hPipe
,
691 if (bResult
== FALSE
)
693 ERR("Pipe write failed (Error: %lu)\n", GetLastError());
702 /**********************************************************************
703 * RegisterServiceCtrlHandlerA
707 SERVICE_STATUS_HANDLE WINAPI
708 RegisterServiceCtrlHandlerA(LPCSTR lpServiceName
,
709 LPHANDLER_FUNCTION lpHandlerProc
)
711 ANSI_STRING ServiceNameA
;
712 UNICODE_STRING ServiceNameU
;
713 SERVICE_STATUS_HANDLE hServiceStatus
;
715 TRACE("RegisterServiceCtrlHandlerA(%s %p)\n",
716 debugstr_a(lpServiceName
), lpHandlerProc
);
718 RtlInitAnsiString(&ServiceNameA
, lpServiceName
);
719 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ServiceNameU
, &ServiceNameA
, TRUE
)))
721 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
725 hServiceStatus
= RegisterServiceCtrlHandlerW(ServiceNameU
.Buffer
,
728 RtlFreeUnicodeString(&ServiceNameU
);
730 return hServiceStatus
;
734 /**********************************************************************
735 * RegisterServiceCtrlHandlerW
739 SERVICE_STATUS_HANDLE WINAPI
740 RegisterServiceCtrlHandlerW(LPCWSTR lpServiceName
,
741 LPHANDLER_FUNCTION lpHandlerProc
)
743 PACTIVE_SERVICE Service
;
745 TRACE("RegisterServiceCtrlHandlerW(%s %p)\n",
746 debugstr_w(lpServiceName
), lpHandlerProc
);
748 Service
= ScLookupServiceByServiceName(lpServiceName
);
751 SetLastError(ERROR_SERVICE_NOT_IN_EXE
);
757 SetLastError(ERROR_INVALID_PARAMETER
);
761 Service
->HandlerFunction
= lpHandlerProc
;
762 Service
->HandlerFunctionEx
= NULL
;
764 TRACE("RegisterServiceCtrlHandler returning %p\n", Service
->hServiceStatus
);
766 return Service
->hServiceStatus
;
770 /**********************************************************************
771 * RegisterServiceCtrlHandlerExA
775 SERVICE_STATUS_HANDLE WINAPI
776 RegisterServiceCtrlHandlerExA(LPCSTR lpServiceName
,
777 LPHANDLER_FUNCTION_EX lpHandlerProc
,
780 ANSI_STRING ServiceNameA
;
781 UNICODE_STRING ServiceNameU
;
782 SERVICE_STATUS_HANDLE hServiceStatus
;
784 TRACE("RegisterServiceCtrlHandlerExA(%s %p %p)\n",
785 debugstr_a(lpServiceName
), lpHandlerProc
, lpContext
);
787 RtlInitAnsiString(&ServiceNameA
, lpServiceName
);
788 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ServiceNameU
, &ServiceNameA
, TRUE
)))
790 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
794 hServiceStatus
= RegisterServiceCtrlHandlerExW(ServiceNameU
.Buffer
,
798 RtlFreeUnicodeString(&ServiceNameU
);
800 return hServiceStatus
;
804 /**********************************************************************
805 * RegisterServiceCtrlHandlerExW
809 SERVICE_STATUS_HANDLE WINAPI
810 RegisterServiceCtrlHandlerExW(LPCWSTR lpServiceName
,
811 LPHANDLER_FUNCTION_EX lpHandlerProc
,
814 PACTIVE_SERVICE Service
;
816 TRACE("RegisterServiceCtrlHandlerExW(%s %p %p)\n",
817 debugstr_w(lpServiceName
), lpHandlerProc
, lpContext
);
819 Service
= ScLookupServiceByServiceName(lpServiceName
);
822 SetLastError(ERROR_SERVICE_NOT_IN_EXE
);
828 SetLastError(ERROR_INVALID_PARAMETER
);
832 Service
->HandlerFunction
= NULL
;
833 Service
->HandlerFunctionEx
= lpHandlerProc
;
834 Service
->HandlerContext
= lpContext
;
836 TRACE("RegisterServiceCtrlHandlerEx returning %p\n", Service
->hServiceStatus
);
838 return Service
->hServiceStatus
;
842 /**********************************************************************
843 * I_ScIsSecurityProcess
851 I_ScIsSecurityProcess(VOID
)
853 TRACE("I_ScIsSecurityProcess()\n");
854 bSecurityServiceProcess
= TRUE
;
858 /**********************************************************************
859 * I_ScPnPGetServiceName
867 I_ScPnPGetServiceName(IN SERVICE_STATUS_HANDLE hServiceStatus
,
868 OUT LPWSTR lpServiceName
,
869 IN DWORD cchServiceName
)
873 TRACE("I_ScPnPGetServiceName(%lu %p %lu)\n",
874 hServiceStatus
, lpServiceName
, cchServiceName
);
876 for (i
= 0; i
< dwActiveServiceCount
; i
++)
878 if (lpActiveServices
[i
].hServiceStatus
== hServiceStatus
)
880 wcscpy(lpServiceName
, lpActiveServices
[i
].ServiceName
.Buffer
);
881 return ERROR_SUCCESS
;
885 return ERROR_SERVICE_NOT_IN_EXE
;
889 /**********************************************************************
890 * I_ScSetServiceBitsA
897 I_ScSetServiceBitsA(SERVICE_STATUS_HANDLE hServiceStatus
,
900 BOOL bUpdateImmediately
,
905 TRACE("I_ScSetServiceBitsA(%lu %lx %u %u %s)\n",
906 hServiceStatus
, dwServiceBits
, bSetBitsOn
, bUpdateImmediately
,
907 debugstr_a(lpString
));
911 bResult
= RI_ScSetServiceBitsA((RPC_SERVICE_STATUS_HANDLE
)hServiceStatus
,
917 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
919 SetLastError(ScmRpcStatusToWinError(RpcExceptionCode()));
928 /**********************************************************************
929 * I_ScSetServiceBitsW
936 I_ScSetServiceBitsW(SERVICE_STATUS_HANDLE hServiceStatus
,
939 BOOL bUpdateImmediately
,
944 TRACE("I_ScSetServiceBitsW(%lu %lx %u %u %s)\n",
945 hServiceStatus
, dwServiceBits
, bSetBitsOn
, bUpdateImmediately
,
946 debugstr_w(lpString
));
950 bResult
= RI_ScSetServiceBitsW((RPC_SERVICE_STATUS_HANDLE
)hServiceStatus
,
956 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
958 SetLastError(ScmRpcStatusToWinError(RpcExceptionCode()));
967 /**********************************************************************
973 SetServiceBits(SERVICE_STATUS_HANDLE hServiceStatus
,
976 BOOL bUpdateImmediately
)
978 TRACE("SetServiceBits(%lu %lx %u %u)\n",
979 hServiceStatus
, dwServiceBits
, bSetBitsOn
, bUpdateImmediately
);
981 return I_ScSetServiceBitsW(hServiceStatus
,
989 /**********************************************************************
995 SetServiceStatus(SERVICE_STATUS_HANDLE hServiceStatus
,
996 LPSERVICE_STATUS lpServiceStatus
)
1000 TRACE("SetServiceStatus(%lu %p)\n",
1001 hServiceStatus
, lpServiceStatus
);
1005 dwError
= RSetServiceStatus((RPC_SERVICE_STATUS_HANDLE
)hServiceStatus
,
1008 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
1010 dwError
= ScmRpcStatusToWinError(RpcExceptionCode());
1014 if (dwError
!= ERROR_SUCCESS
)
1016 ERR("RSetServiceStatus() failed (Error %lu)\n", dwError
);
1017 SetLastError(dwError
);
1021 TRACE("SetServiceStatus() done\n");
1027 /**********************************************************************
1028 * StartServiceCtrlDispatcherA
1033 StartServiceCtrlDispatcherA(const SERVICE_TABLE_ENTRYA
*lpServiceStartTable
)
1038 PSCM_CONTROL_PACKET ControlPacket
;
1042 TRACE("StartServiceCtrlDispatcherA(%p)\n",
1043 lpServiceStartTable
);
1046 while (lpServiceStartTable
[i
].lpServiceProc
!= NULL
)
1051 dwActiveServiceCount
= i
;
1053 /* Allocate the service table */
1054 lpActiveServices
= RtlAllocateHeap(RtlGetProcessHeap(),
1056 dwActiveServiceCount
* sizeof(ACTIVE_SERVICE
));
1057 if (lpActiveServices
== NULL
)
1059 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1063 /* Copy service names and start procedure */
1064 for (i
= 0; i
< dwActiveServiceCount
; i
++)
1066 RtlCreateUnicodeStringFromAsciiz(&lpActiveServices
[i
].ServiceName
,
1067 lpServiceStartTable
[i
].lpServiceName
);
1068 lpActiveServices
[i
].ServiceMain
.A
= lpServiceStartTable
[i
].lpServiceProc
;
1069 lpActiveServices
[i
].hServiceStatus
= NULL
;
1070 lpActiveServices
[i
].bUnicode
= FALSE
;
1071 lpActiveServices
[i
].bOwnProcess
= FALSE
;
1074 /* Connect to the SCM */
1075 dwError
= ScConnectControlPipe(&hPipe
);
1076 if (dwError
!= ERROR_SUCCESS
)
1082 dwBufSize
= sizeof(SCM_CONTROL_PACKET
) +
1083 (MAX_SERVICE_NAME_LENGTH
+ 1) * sizeof(WCHAR
);
1085 ControlPacket
= RtlAllocateHeap(RtlGetProcessHeap(),
1088 if (ControlPacket
== NULL
)
1090 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
1095 ScCreateStatusBinding();
1097 /* Call the dispatcher loop */
1098 ScServiceDispatcher(hPipe
, ControlPacket
, dwBufSize
);
1101 ScDestroyStatusBinding();
1103 /* Close the connection */
1106 /* Free the control packet */
1107 RtlFreeHeap(RtlGetProcessHeap(), 0, ControlPacket
);
1110 /* Free the service table */
1111 for (i
= 0; i
< dwActiveServiceCount
; i
++)
1113 RtlFreeUnicodeString(&lpActiveServices
[i
].ServiceName
);
1115 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices
);
1116 lpActiveServices
= NULL
;
1117 dwActiveServiceCount
= 0;
1120 SetLastError(dwError
);
1126 /**********************************************************************
1127 * StartServiceCtrlDispatcherW
1132 StartServiceCtrlDispatcherW(const SERVICE_TABLE_ENTRYW
*lpServiceStartTable
)
1137 PSCM_CONTROL_PACKET ControlPacket
;
1141 TRACE("StartServiceCtrlDispatcherW(%p)\n",
1142 lpServiceStartTable
);
1145 while (lpServiceStartTable
[i
].lpServiceProc
!= NULL
)
1150 dwActiveServiceCount
= i
;
1152 /* Allocate the service table */
1153 lpActiveServices
= RtlAllocateHeap(RtlGetProcessHeap(),
1155 dwActiveServiceCount
* sizeof(ACTIVE_SERVICE
));
1156 if (lpActiveServices
== NULL
)
1158 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1162 /* Copy service names and start procedure */
1163 for (i
= 0; i
< dwActiveServiceCount
; i
++)
1165 RtlCreateUnicodeString(&lpActiveServices
[i
].ServiceName
,
1166 lpServiceStartTable
[i
].lpServiceName
);
1167 lpActiveServices
[i
].ServiceMain
.W
= lpServiceStartTable
[i
].lpServiceProc
;
1168 lpActiveServices
[i
].hServiceStatus
= NULL
;
1169 lpActiveServices
[i
].bUnicode
= TRUE
;
1170 lpActiveServices
[i
].bOwnProcess
= FALSE
;
1173 /* Connect to the SCM */
1174 dwError
= ScConnectControlPipe(&hPipe
);
1175 if (dwError
!= ERROR_SUCCESS
)
1181 dwBufSize
= sizeof(SCM_CONTROL_PACKET
) +
1182 (MAX_SERVICE_NAME_LENGTH
+ 1) * sizeof(WCHAR
);
1184 ControlPacket
= RtlAllocateHeap(RtlGetProcessHeap(),
1187 if (ControlPacket
== NULL
)
1189 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
1194 ScCreateStatusBinding();
1196 /* Call the dispatcher loop */
1197 ScServiceDispatcher(hPipe
, ControlPacket
, dwBufSize
);
1199 ScDestroyStatusBinding();
1201 /* Close the connection */
1204 /* Free the control packet */
1205 RtlFreeHeap(RtlGetProcessHeap(), 0, ControlPacket
);
1208 /* Free the service table */
1209 for (i
= 0; i
< dwActiveServiceCount
; i
++)
1211 RtlFreeUnicodeString(&lpActiveServices
[i
].ServiceName
);
1213 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices
);
1214 lpActiveServices
= NULL
;
1215 dwActiveServiceCount
= 0;
1218 SetLastError(dwError
);