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 WINE_DEFAULT_DEBUG_CHANNEL(advapi
);
19 /* TYPES *********************************************************************/
21 typedef struct _ACTIVE_SERVICE
23 SERVICE_STATUS_HANDLE hServiceStatus
;
24 UNICODE_STRING ServiceName
;
27 LPSERVICE_MAIN_FUNCTIONA lpFuncA
;
28 LPSERVICE_MAIN_FUNCTIONW lpFuncW
;
30 LPHANDLER_FUNCTION HandlerFunction
;
31 LPHANDLER_FUNCTION_EX HandlerFunctionEx
;
32 LPVOID HandlerContext
;
35 } ACTIVE_SERVICE
, *PACTIVE_SERVICE
;
38 /* GLOBALS *******************************************************************/
40 static DWORD dwActiveServiceCount
= 0;
41 static PACTIVE_SERVICE lpActiveServices
= NULL
;
42 static handle_t hStatusBinding
= NULL
;
45 /* FUNCTIONS *****************************************************************/
48 RPC_SERVICE_STATUS_HANDLE_bind(RPC_SERVICE_STATUS_HANDLE hServiceStatus
)
50 return hStatusBinding
;
55 RPC_SERVICE_STATUS_HANDLE_unbind(RPC_SERVICE_STATUS_HANDLE hServiceStatus
,
62 ScCreateStatusBinding(VOID
)
64 LPWSTR pszStringBinding
;
67 TRACE("ScCreateStatusBinding() called\n");
69 status
= RpcStringBindingComposeW(NULL
,
75 if (status
!= RPC_S_OK
)
77 ERR("RpcStringBindingCompose returned 0x%x\n", status
);
81 /* Set the binding handle that will be used to bind to the server. */
82 status
= RpcBindingFromStringBindingW(pszStringBinding
,
84 if (status
!= RPC_S_OK
)
86 ERR("RpcBindingFromStringBinding returned 0x%x\n", status
);
89 status
= RpcStringFreeW(&pszStringBinding
);
90 if (status
!= RPC_S_OK
)
92 ERR("RpcStringFree returned 0x%x\n", status
);
100 ScDestroyStatusBinding(VOID
)
104 TRACE("ScDestroyStatusBinding() called\n");
106 if (hStatusBinding
== NULL
)
109 status
= RpcBindingFree(&hStatusBinding
);
110 if (status
!= RPC_S_OK
)
112 ERR("RpcBindingFree returned 0x%x\n", status
);
116 hStatusBinding
= NULL
;
123 static PACTIVE_SERVICE
124 ScLookupServiceByServiceName(LPCWSTR lpServiceName
)
128 TRACE("ScLookupServiceByServiceName(%S) called\n", lpServiceName
);
130 for (i
= 0; i
< dwActiveServiceCount
; i
++)
132 TRACE("Checking %S\n", lpActiveServices
[i
].ServiceName
.Buffer
);
133 if (_wcsicmp(lpActiveServices
[i
].ServiceName
.Buffer
, lpServiceName
) == 0)
136 return &lpActiveServices
[i
];
140 TRACE("No service found!\n");
142 SetLastError(ERROR_SERVICE_DOES_NOT_EXIST
);
149 ScServiceMainStub(LPVOID Context
)
151 PACTIVE_SERVICE lpService
;
152 DWORD dwArgCount
= 0;
157 lpService
= (PACTIVE_SERVICE
)Context
;
159 TRACE("ScServiceMainStub() called\n");
161 /* Count arguments */
162 lpPtr
= lpService
->Arguments
;
165 TRACE("arg: %S\n", lpPtr
);
166 dwLen
= wcslen(lpPtr
) + 1;
171 TRACE("dwArgCount: %ld\ndwLength: %ld\n", dwArgCount
, dwLength
);
173 /* Build the argument vector and call the main service routine */
174 if (lpService
->bUnicode
)
179 lpArgVector
= HeapAlloc(GetProcessHeap(),
181 (dwArgCount
+ 1) * sizeof(LPWSTR
));
182 if (lpArgVector
== NULL
)
183 return ERROR_OUTOFMEMORY
;
186 Ptr
= lpService
->Arguments
;
189 lpArgVector
[dwArgCount
] = Ptr
;
192 Ptr
+= (wcslen(Ptr
) + 1);
194 lpArgVector
[dwArgCount
] = NULL
;
196 (lpService
->Main
.lpFuncW
)(dwArgCount
, lpArgVector
);
198 HeapFree(GetProcessHeap(),
209 AnsiLength
= WideCharToMultiByte(CP_ACP
,
211 lpService
->Arguments
,
218 return ERROR_INVALID_PARAMETER
; /* ? */
220 AnsiString
= HeapAlloc(GetProcessHeap(),
223 if (AnsiString
== NULL
)
224 return ERROR_OUTOFMEMORY
;
226 WideCharToMultiByte(CP_ACP
,
228 lpService
->Arguments
,
235 AnsiString
[AnsiLength
] = ANSI_NULL
;
237 lpArgVector
= HeapAlloc(GetProcessHeap(),
239 (dwArgCount
+ 1) * sizeof(LPSTR
));
240 if (lpArgVector
== NULL
)
242 HeapFree(GetProcessHeap(),
245 return ERROR_OUTOFMEMORY
;
252 lpArgVector
[dwArgCount
] = Ptr
;
255 Ptr
+= (strlen(Ptr
) + 1);
257 lpArgVector
[dwArgCount
] = NULL
;
259 (lpService
->Main
.lpFuncA
)(dwArgCount
, lpArgVector
);
261 HeapFree(GetProcessHeap(),
264 HeapFree(GetProcessHeap(),
269 return ERROR_SUCCESS
;
274 ScConnectControlPipe(HANDLE
*hPipe
)
276 DWORD dwBytesWritten
;
278 DWORD dwServiceCurrent
= 0;
280 WCHAR NtControlPipeName
[MAX_PATH
+ 1];
281 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
284 /* Get the service number and create the named pipe */
285 RtlZeroMemory(&QueryTable
,
288 QueryTable
[0].Name
= L
"";
289 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
290 QueryTable
[0].EntryContext
= &dwServiceCurrent
;
292 Status
= RtlQueryRegistryValues(RTL_REGISTRY_CONTROL
,
298 if (!NT_SUCCESS(Status
))
300 ERR("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
301 return RtlNtStatusToDosError(Status
);
304 swprintf(NtControlPipeName
, L
"\\\\.\\pipe\\net\\NtControlPipe%u", dwServiceCurrent
);
306 if (!WaitNamedPipeW(NtControlPipeName
, 15000))
308 ERR("WaitNamedPipe(%S) failed (Error %lu)\n", NtControlPipeName
, GetLastError());
309 return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT
;
312 *hPipe
= CreateFileW(NtControlPipeName
,
313 GENERIC_READ
| GENERIC_WRITE
,
317 FILE_ATTRIBUTE_NORMAL
,
319 if (*hPipe
== INVALID_HANDLE_VALUE
)
321 ERR("CreateFileW() failed for pipe %S (Error %lu)\n", NtControlPipeName
, GetLastError());
322 return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT
;
325 dwState
= PIPE_READMODE_MESSAGE
;
326 if (!SetNamedPipeHandleState(*hPipe
, &dwState
, NULL
, NULL
))
329 *hPipe
= INVALID_HANDLE_VALUE
;
330 return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT
;
333 /* Pass the ProcessId to the SCM */
334 dwProcessId
= GetCurrentProcessId();
341 TRACE("Sent Process ID %lu\n", dwProcessId
);
343 return ERROR_SUCCESS
;
348 ScStartService(PACTIVE_SERVICE lpService
,
349 PSCM_CONTROL_PACKET ControlPacket
)
355 DWORD dwArgumentsSize
;
357 TRACE("ScStartService() called\n");
358 TRACE("Size: %lu\n", ControlPacket
->dwSize
);
359 TRACE("Service: %S\n", (PWSTR
)((PBYTE
)ControlPacket
+ ControlPacket
->dwServiceNameOffset
));
361 /* Set the service status handle */
362 lpService
->hServiceStatus
= ControlPacket
->hServiceStatus
;
364 pServiceName
= (PWSTR
)((PBYTE
)ControlPacket
+ ControlPacket
->dwServiceNameOffset
);
366 /* Get the service name size */
367 dwArgumentsSize
= (wcslen(pServiceName
) + 1) * sizeof(WCHAR
);
369 /* Get the size of the service start arguments */
370 if (ControlPacket
->dwArgumentsCount
> 0 &&
371 ControlPacket
->dwArgumentsOffset
!= 0)
375 dwArgumentSize
+= (wcslen(...) + 1) * sizeof(WCHAR
);
379 lpService
->Arguments
= HeapAlloc(GetProcessHeap(),
381 dwArgumentsSize
+ sizeof(WCHAR
));
382 if (lpService
->Arguments
== NULL
)
383 return ERROR_OUTOFMEMORY
;
385 Ptr
= lpService
->Arguments
;
387 /* Add the service name as first argument */
388 wcscpy(Ptr
, pServiceName
);
389 Ptr
+= (wcslen(pServiceName
) + 1);
391 /* Add service start arguments */
392 if (ControlPacket
->dwArgumentsCount
> 0 &&
393 ControlPacket
->dwArgumentsOffset
!= 0)
400 /* invoke the services entry point and implement the command loop */
401 ThreadHandle
= CreateThread(NULL
,
407 if (ThreadHandle
== NULL
)
408 return ERROR_SERVICE_NO_THREAD
;
410 ResumeThread(ThreadHandle
);
411 CloseHandle(ThreadHandle
);
413 return ERROR_SUCCESS
;
418 ScControlService(PACTIVE_SERVICE lpService
,
419 PSCM_CONTROL_PACKET ControlPacket
)
421 TRACE("ScControlService() called\n");
422 TRACE("Size: %lu\n", ControlPacket
->dwSize
);
423 TRACE("Service: %S\n", (PWSTR
)((PBYTE
)ControlPacket
+ ControlPacket
->dwServiceNameOffset
));
425 if (lpService
->HandlerFunction
)
427 (lpService
->HandlerFunction
)(ControlPacket
->dwControl
);
429 else if (lpService
->HandlerFunctionEx
)
431 /* FIXME: send correct params */
432 (lpService
->HandlerFunctionEx
)(ControlPacket
->dwControl
, 0, NULL
, NULL
);
435 if (ControlPacket
->dwControl
== SERVICE_CONTROL_STOP
)
437 HeapFree(GetProcessHeap(),
439 lpService
->Arguments
);
442 TRACE("ScControlService() done\n");
444 return ERROR_SUCCESS
;
449 ScServiceDispatcher(HANDLE hPipe
,
453 PSCM_CONTROL_PACKET ControlPacket
;
456 DWORD dwRunningServices
= 0;
457 LPWSTR lpServiceName
;
458 PACTIVE_SERVICE lpService
;
459 SCM_REPLY_PACKET ReplyPacket
;
462 TRACE("ScDispatcherLoop() called\n");
464 ControlPacket
= HeapAlloc(GetProcessHeap(),
467 if (ControlPacket
== NULL
)
472 /* Read command from the control pipe */
473 bResult
= ReadFile(hPipe
,
478 if (bResult
== FALSE
)
480 ERR("Pipe read failed (Error: %lu)\n", GetLastError());
484 lpServiceName
= (LPWSTR
)((PBYTE
)ControlPacket
+ ControlPacket
->dwServiceNameOffset
);
485 TRACE("Service: %S\n", lpServiceName
);
487 lpService
= ScLookupServiceByServiceName(lpServiceName
);
488 if (lpService
!= NULL
)
490 /* Execute command */
491 switch (ControlPacket
->dwControl
)
493 case SERVICE_CONTROL_START
:
494 TRACE("Start command - recieved SERVICE_CONTROL_START\n");
495 dwError
= ScStartService(lpService
, ControlPacket
);
496 if (dwError
== ERROR_SUCCESS
)
500 case SERVICE_CONTROL_STOP
:
501 TRACE("Stop command - recieved SERVICE_CONTROL_STOP\n");
502 dwError
= ScControlService(lpService
, ControlPacket
);
503 if (dwError
== ERROR_SUCCESS
)
508 TRACE("Command %lu received", ControlPacket
->dwControl
);
509 dwError
= ScControlService(lpService
, ControlPacket
);
515 dwError
= ERROR_SERVICE_DOES_NOT_EXIST
;
518 ReplyPacket
.dwError
= dwError
;
520 /* Send the reply packet */
521 bResult
= WriteFile(hPipe
,
526 if (bResult
== FALSE
)
528 ERR("Pipe write failed (Error: %lu)\n", GetLastError());
532 if (dwRunningServices
== 0)
536 HeapFree(GetProcessHeap(),
544 /**********************************************************************
545 * RegisterServiceCtrlHandlerA
549 SERVICE_STATUS_HANDLE WINAPI
550 RegisterServiceCtrlHandlerA(LPCSTR lpServiceName
,
551 LPHANDLER_FUNCTION lpHandlerProc
)
553 ANSI_STRING ServiceNameA
;
554 UNICODE_STRING ServiceNameU
;
555 SERVICE_STATUS_HANDLE SHandle
;
557 RtlInitAnsiString(&ServiceNameA
, (LPSTR
)lpServiceName
);
558 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ServiceNameU
, &ServiceNameA
, TRUE
)))
560 SetLastError(ERROR_OUTOFMEMORY
);
561 return (SERVICE_STATUS_HANDLE
)0;
564 SHandle
= RegisterServiceCtrlHandlerW(ServiceNameU
.Buffer
,
567 RtlFreeUnicodeString(&ServiceNameU
);
573 /**********************************************************************
574 * RegisterServiceCtrlHandlerW
578 SERVICE_STATUS_HANDLE WINAPI
579 RegisterServiceCtrlHandlerW(LPCWSTR lpServiceName
,
580 LPHANDLER_FUNCTION lpHandlerProc
)
582 PACTIVE_SERVICE Service
;
584 Service
= ScLookupServiceByServiceName((LPWSTR
)lpServiceName
);
587 return (SERVICE_STATUS_HANDLE
)NULL
;
590 Service
->HandlerFunction
= lpHandlerProc
;
591 Service
->HandlerFunctionEx
= NULL
;
593 TRACE("RegisterServiceCtrlHandler returning %lu\n", Service
->hServiceStatus
);
595 return Service
->hServiceStatus
;
599 /**********************************************************************
600 * RegisterServiceCtrlHandlerExA
604 SERVICE_STATUS_HANDLE WINAPI
605 RegisterServiceCtrlHandlerExA(LPCSTR lpServiceName
,
606 LPHANDLER_FUNCTION_EX lpHandlerProc
,
609 ANSI_STRING ServiceNameA
;
610 UNICODE_STRING ServiceNameU
;
611 SERVICE_STATUS_HANDLE SHandle
;
613 RtlInitAnsiString(&ServiceNameA
, (LPSTR
)lpServiceName
);
614 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ServiceNameU
, &ServiceNameA
, TRUE
)))
616 SetLastError(ERROR_OUTOFMEMORY
);
617 return (SERVICE_STATUS_HANDLE
)0;
620 SHandle
= RegisterServiceCtrlHandlerExW(ServiceNameU
.Buffer
,
624 RtlFreeUnicodeString(&ServiceNameU
);
630 /**********************************************************************
631 * RegisterServiceCtrlHandlerExW
635 SERVICE_STATUS_HANDLE WINAPI
636 RegisterServiceCtrlHandlerExW(LPCWSTR lpServiceName
,
637 LPHANDLER_FUNCTION_EX lpHandlerProc
,
640 PACTIVE_SERVICE Service
;
642 Service
= ScLookupServiceByServiceName(lpServiceName
);
645 return (SERVICE_STATUS_HANDLE
)NULL
;
648 Service
->HandlerFunction
= NULL
;
649 Service
->HandlerFunctionEx
= lpHandlerProc
;
650 Service
->HandlerContext
= lpContext
;
652 TRACE("RegisterServiceCtrlHandlerEx returning %lu\n", Service
->hServiceStatus
);
654 return Service
->hServiceStatus
;
658 /**********************************************************************
659 * I_ScSetServiceBitsA
666 I_ScSetServiceBitsA(SERVICE_STATUS_HANDLE hServiceStatus
,
669 BOOL bUpdateImmediately
,
676 /* Call to services.exe using RPC */
677 bResult
= RI_ScSetServiceBitsA((RPC_SERVICE_STATUS_HANDLE
)hServiceStatus
,
683 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
685 SetLastError(ScmRpcStatusToWinError(RpcExceptionCode()));
694 /**********************************************************************
695 * I_ScSetServiceBitsW
702 I_ScSetServiceBitsW(SERVICE_STATUS_HANDLE hServiceStatus
,
705 BOOL bUpdateImmediately
,
712 /* Call to services.exe using RPC */
713 bResult
= RI_ScSetServiceBitsW((RPC_SERVICE_STATUS_HANDLE
)hServiceStatus
,
719 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
721 SetLastError(ScmRpcStatusToWinError(RpcExceptionCode()));
730 /**********************************************************************
736 SetServiceBits(SERVICE_STATUS_HANDLE hServiceStatus
,
739 BOOL bUpdateImmediately
)
741 return I_ScSetServiceBitsW(hServiceStatus
,
749 /**********************************************************************
755 SetServiceStatus(SERVICE_STATUS_HANDLE hServiceStatus
,
756 LPSERVICE_STATUS lpServiceStatus
)
760 TRACE("SetServiceStatus() called\n");
761 TRACE("hServiceStatus %lu\n", hServiceStatus
);
765 /* Call to services.exe using RPC */
766 dwError
= RSetServiceStatus((RPC_SERVICE_STATUS_HANDLE
)hServiceStatus
,
769 RpcExcept(EXCEPTION_EXECUTE_HANDLER
)
771 dwError
= ScmRpcStatusToWinError(RpcExceptionCode());
775 if (dwError
!= ERROR_SUCCESS
)
777 ERR("ScmrSetServiceStatus() failed (Error %lu)\n", dwError
);
778 SetLastError(dwError
);
782 TRACE("SetServiceStatus() done (ret %lu)\n", dwError
);
788 /**********************************************************************
789 * StartServiceCtrlDispatcherA
794 StartServiceCtrlDispatcherA(const SERVICE_TABLE_ENTRYA
* lpServiceStartTable
)
799 PUCHAR lpMessageBuffer
;
801 TRACE("StartServiceCtrlDispatcherA() called\n");
804 while (lpServiceStartTable
[i
].lpServiceProc
!= NULL
)
809 dwActiveServiceCount
= i
;
810 lpActiveServices
= RtlAllocateHeap(RtlGetProcessHeap(),
812 dwActiveServiceCount
* sizeof(ACTIVE_SERVICE
));
813 if (lpActiveServices
== NULL
)
818 /* Copy service names and start procedure */
819 for (i
= 0; i
< dwActiveServiceCount
; i
++)
821 RtlCreateUnicodeStringFromAsciiz(&lpActiveServices
[i
].ServiceName
,
822 lpServiceStartTable
[i
].lpServiceName
);
823 lpActiveServices
[i
].Main
.lpFuncA
= lpServiceStartTable
[i
].lpServiceProc
;
824 lpActiveServices
[i
].hServiceStatus
= 0;
825 lpActiveServices
[i
].bUnicode
= FALSE
;
828 dwError
= ScConnectControlPipe(&hPipe
);
829 if (dwError
!= ERROR_SUCCESS
)
831 /* Free the service table */
832 for (i
= 0; i
< dwActiveServiceCount
; i
++)
834 RtlFreeUnicodeString(&lpActiveServices
[i
].ServiceName
);
836 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices
);
837 lpActiveServices
= NULL
;
838 dwActiveServiceCount
= 0;
842 lpMessageBuffer
= RtlAllocateHeap(RtlGetProcessHeap(),
845 if (lpMessageBuffer
== NULL
)
847 /* Free the service table */
848 for (i
= 0; i
< dwActiveServiceCount
; i
++)
850 RtlFreeUnicodeString(&lpActiveServices
[i
].ServiceName
);
852 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices
);
853 lpActiveServices
= NULL
;
854 dwActiveServiceCount
= 0;
859 ScCreateStatusBinding();
861 ScServiceDispatcher(hPipe
, lpMessageBuffer
, 256);
863 ScDestroyStatusBinding();
867 /* Free the message buffer */
868 RtlFreeHeap(RtlGetProcessHeap(), 0, lpMessageBuffer
);
870 /* Free the service table */
871 for (i
= 0; i
< dwActiveServiceCount
; i
++)
873 RtlFreeUnicodeString(&lpActiveServices
[i
].ServiceName
);
875 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices
);
876 lpActiveServices
= NULL
;
877 dwActiveServiceCount
= 0;
883 /**********************************************************************
884 * StartServiceCtrlDispatcherW
889 StartServiceCtrlDispatcherW(const SERVICE_TABLE_ENTRYW
* lpServiceStartTable
)
894 PUCHAR lpMessageBuffer
;
896 TRACE("StartServiceCtrlDispatcherW() called\n");
899 while (lpServiceStartTable
[i
].lpServiceProc
!= NULL
)
904 dwActiveServiceCount
= i
;
905 lpActiveServices
= RtlAllocateHeap(RtlGetProcessHeap(),
907 dwActiveServiceCount
* sizeof(ACTIVE_SERVICE
));
908 if (lpActiveServices
== NULL
)
913 /* Copy service names and start procedure */
914 for (i
= 0; i
< dwActiveServiceCount
; i
++)
916 RtlCreateUnicodeString(&lpActiveServices
[i
].ServiceName
,
917 lpServiceStartTable
[i
].lpServiceName
);
918 lpActiveServices
[i
].Main
.lpFuncW
= lpServiceStartTable
[i
].lpServiceProc
;
919 lpActiveServices
[i
].hServiceStatus
= 0;
920 lpActiveServices
[i
].bUnicode
= TRUE
;
923 dwError
= ScConnectControlPipe(&hPipe
);
924 if (dwError
!= ERROR_SUCCESS
)
926 /* Free the service table */
927 for (i
= 0; i
< dwActiveServiceCount
; i
++)
929 RtlFreeUnicodeString(&lpActiveServices
[i
].ServiceName
);
931 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices
);
932 lpActiveServices
= NULL
;
933 dwActiveServiceCount
= 0;
937 lpMessageBuffer
= RtlAllocateHeap(RtlGetProcessHeap(),
940 if (lpMessageBuffer
== NULL
)
942 /* Free the service table */
943 for (i
= 0; i
< dwActiveServiceCount
; i
++)
945 RtlFreeUnicodeString(&lpActiveServices
[i
].ServiceName
);
947 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices
);
948 lpActiveServices
= NULL
;
949 dwActiveServiceCount
= 0;
954 ScCreateStatusBinding();
956 ScServiceDispatcher(hPipe
, lpMessageBuffer
, 256);
958 ScDestroyStatusBinding();
962 /* Free the message buffer */
963 RtlFreeHeap(RtlGetProcessHeap(), 0, lpMessageBuffer
);
965 /* Free the service table */
966 for (i
= 0; i
< dwActiveServiceCount
; i
++)
968 RtlFreeUnicodeString(&lpActiveServices
[i
].ServiceName
);
970 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices
);
971 lpActiveServices
= NULL
;
972 dwActiveServiceCount
= 0;