3 * service control manager
5 * ReactOS Operating System
7 * --------------------------------------------------------------------
9 * This software is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of the
12 * License, or (at your option) any later version.
14 * This software is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this software; see the file COPYING.LIB. If not, write
21 * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
26 /* INCLUDES *****************************************************************/
34 /* GLOBALS *******************************************************************/
36 LIST_ENTRY ServiceListHead
;
38 static RTL_RESOURCE DatabaseLock
;
39 static DWORD dwResumeCount
= 1;
42 /* FUNCTIONS *****************************************************************/
45 ScmGetServiceEntryByName(LPWSTR lpServiceName
)
47 PLIST_ENTRY ServiceEntry
;
48 PSERVICE CurrentService
;
50 DPRINT("ScmGetServiceEntryByName() called\n");
52 ServiceEntry
= ServiceListHead
.Flink
;
53 while (ServiceEntry
!= &ServiceListHead
)
55 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
58 if (_wcsicmp(CurrentService
->lpServiceName
, lpServiceName
) == 0)
60 DPRINT("Found service: '%S'\n", CurrentService
->lpServiceName
);
61 return CurrentService
;
64 ServiceEntry
= ServiceEntry
->Flink
;
67 DPRINT("Couldn't find a matching service\n");
74 ScmGetServiceEntryByDisplayName(LPWSTR lpDisplayName
)
76 PLIST_ENTRY ServiceEntry
;
77 PSERVICE CurrentService
;
79 DPRINT("ScmGetServiceEntryByDisplayName() called\n");
81 ServiceEntry
= ServiceListHead
.Flink
;
82 while (ServiceEntry
!= &ServiceListHead
)
84 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
87 if (_wcsicmp(CurrentService
->lpDisplayName
, lpDisplayName
) == 0)
89 DPRINT("Found service: '%S'\n", CurrentService
->lpDisplayName
);
90 return CurrentService
;
93 ServiceEntry
= ServiceEntry
->Flink
;
96 DPRINT("Couldn't find a matching service\n");
103 ScmGetServiceEntryByResumeCount(DWORD dwResumeCount
)
105 PLIST_ENTRY ServiceEntry
;
106 PSERVICE CurrentService
;
108 DPRINT("ScmGetServiceEntryByResumeCount() called\n");
110 ServiceEntry
= ServiceListHead
.Flink
;
111 while (ServiceEntry
!= &ServiceListHead
)
113 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
116 if (CurrentService
->dwResumeCount
> dwResumeCount
)
118 DPRINT("Found service: '%S'\n", CurrentService
->lpDisplayName
);
119 return CurrentService
;
122 ServiceEntry
= ServiceEntry
->Flink
;
125 DPRINT("Couldn't find a matching service\n");
132 ScmCreateNewServiceRecord(LPWSTR lpServiceName
,
133 PSERVICE
*lpServiceRecord
)
135 PSERVICE lpService
= NULL
;
137 DPRINT("Service: '%S'\n", lpServiceName
);
139 /* Allocate service entry */
140 lpService
= HeapAlloc(GetProcessHeap(),
142 sizeof(SERVICE
) + ((wcslen(lpServiceName
) + 1) * sizeof(WCHAR
)));
143 if (lpService
== NULL
)
144 return ERROR_NOT_ENOUGH_MEMORY
;
146 *lpServiceRecord
= lpService
;
148 /* Copy service name */
149 wcscpy(lpService
->szServiceName
, lpServiceName
);
150 lpService
->lpServiceName
= lpService
->szServiceName
;
151 lpService
->lpDisplayName
= lpService
->lpServiceName
;
153 /* Set the resume count */
154 lpService
->dwResumeCount
= dwResumeCount
++;
156 /* Append service entry */
157 InsertTailList(&ServiceListHead
,
158 &lpService
->ServiceListEntry
);
160 lpService
->Status
.dwCurrentState
= SERVICE_STOPPED
;
161 lpService
->Status
.dwControlsAccepted
= 0;
162 lpService
->Status
.dwWin32ExitCode
= ERROR_SERVICE_NEVER_STARTED
;
163 lpService
->Status
.dwServiceSpecificExitCode
= 0;
164 lpService
->Status
.dwCheckPoint
= 0;
165 lpService
->Status
.dwWaitHint
= 2000; /* 2 seconds */
167 return ERROR_SUCCESS
;
172 CreateServiceListEntry(LPWSTR lpServiceName
,
175 PSERVICE lpService
= NULL
;
176 LPWSTR lpDisplayName
= NULL
;
177 LPWSTR lpGroup
= NULL
;
182 DWORD dwErrorControl
;
185 DPRINT("Service: '%S'\n", lpServiceName
);
186 if (*lpServiceName
== L
'{')
187 return ERROR_SUCCESS
;
189 dwSize
= sizeof(DWORD
);
190 dwError
= RegQueryValueExW(hServiceKey
,
194 (LPBYTE
)&dwServiceType
,
196 if (dwError
!= ERROR_SUCCESS
)
197 return ERROR_SUCCESS
;
199 if (((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_OWN_PROCESS
) &&
200 ((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_SHARE_PROCESS
) &&
201 (dwServiceType
!= SERVICE_KERNEL_DRIVER
) &&
202 (dwServiceType
!= SERVICE_FILE_SYSTEM_DRIVER
))
203 return ERROR_SUCCESS
;
205 DPRINT("Service type: %lx\n", dwServiceType
);
207 dwSize
= sizeof(DWORD
);
208 dwError
= RegQueryValueExW(hServiceKey
,
212 (LPBYTE
)&dwStartType
,
214 if (dwError
!= ERROR_SUCCESS
)
215 return ERROR_SUCCESS
;
217 DPRINT("Start type: %lx\n", dwStartType
);
219 dwSize
= sizeof(DWORD
);
220 dwError
= RegQueryValueExW(hServiceKey
,
224 (LPBYTE
)&dwErrorControl
,
226 if (dwError
!= ERROR_SUCCESS
)
227 return ERROR_SUCCESS
;
229 DPRINT("Error control: %lx\n", dwErrorControl
);
231 dwError
= RegQueryValueExW(hServiceKey
,
237 if (dwError
!= ERROR_SUCCESS
)
240 DPRINT("Tag: %lx\n", dwTagId
);
242 dwError
= ScmReadString(hServiceKey
,
245 if (dwError
!= ERROR_SUCCESS
)
248 DPRINT("Group: %S\n", lpGroup
);
250 dwError
= ScmReadString(hServiceKey
,
253 if (dwError
!= ERROR_SUCCESS
)
254 lpDisplayName
= NULL
;
256 DPRINT("Display name: %S\n", lpDisplayName
);
258 dwError
= ScmCreateNewServiceRecord(lpServiceName
,
260 if (dwError
!= ERROR_SUCCESS
)
263 lpService
->Status
.dwServiceType
= dwServiceType
;
264 lpService
->dwStartType
= dwStartType
;
265 lpService
->dwErrorControl
= dwErrorControl
;
266 lpService
->dwTag
= dwTagId
;
270 dwError
= ScmSetServiceGroup(lpService
, lpGroup
);
271 if (dwError
!= ERROR_SUCCESS
)
275 if (lpDisplayName
!= NULL
)
277 lpService
->lpDisplayName
= lpDisplayName
;
278 lpDisplayName
= NULL
;
281 DPRINT("ServiceName: '%S'\n", lpService
->lpServiceName
);
282 DPRINT("Group: '%S'\n", lpService
->lpGroup
->lpGroupName
);
283 DPRINT("Start %lx Type %lx Tag %lx ErrorControl %lx\n",
284 lpService
->dwStartType
,
285 lpService
->Status
.dwServiceType
,
287 lpService
->dwErrorControl
);
289 if (ScmIsDeleteFlagSet(hServiceKey
))
290 lpService
->bDeleted
= TRUE
;
294 HeapFree(GetProcessHeap(), 0, lpGroup
);
296 if (lpDisplayName
!= NULL
)
297 HeapFree(GetProcessHeap(), 0, lpDisplayName
);
304 ScmDeleteMarkedServices(VOID
)
306 PLIST_ENTRY ServiceEntry
;
307 PSERVICE CurrentService
;
309 ServiceEntry
= ServiceListHead
.Flink
;
310 while (ServiceEntry
!= &ServiceListHead
)
312 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
314 ServiceEntry
= ServiceEntry
->Flink
;
316 if (CurrentService
->bDeleted
== TRUE
)
318 DPRINT1("Delete service: %S\n", CurrentService
->lpServiceName
);
320 /* FIXME: Delete the registry keys */
322 /* FIXME: Delete the service record from the list */
330 ScmCreateServiceDatabase(VOID
)
332 WCHAR szSubKey
[MAX_PATH
];
336 DWORD dwSubKeyLength
;
337 FILETIME ftLastChanged
;
340 DPRINT("ScmCreateServiceDatabase() called\n");
342 dwError
= ScmCreateGroupList();
343 if (dwError
!= ERROR_SUCCESS
)
346 /* Initialize basic variables */
347 InitializeListHead(&ServiceListHead
);
349 /* Initialize the database lock */
350 RtlInitializeResource(&DatabaseLock
);
352 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
353 L
"System\\CurrentControlSet\\Services",
357 if (dwError
!= ERROR_SUCCESS
)
363 dwSubKeyLength
= MAX_PATH
;
364 dwError
= RegEnumKeyExW(hServicesKey
,
372 if (dwError
== ERROR_SUCCESS
&&
375 DPRINT("SubKeyName: '%S'\n", szSubKey
);
377 dwError
= RegOpenKeyExW(hServicesKey
,
382 if (dwError
== ERROR_SUCCESS
)
384 dwError
= CreateServiceListEntry(szSubKey
,
387 RegCloseKey(hServiceKey
);
391 if (dwError
!= ERROR_SUCCESS
)
397 RegCloseKey(hServicesKey
);
399 /* Delete services that are marked for delete */
400 ScmDeleteMarkedServices();
402 DPRINT("ScmCreateServiceDatabase() done\n");
404 return ERROR_SUCCESS
;
409 ScmCheckDriver(PSERVICE Service
)
411 OBJECT_ATTRIBUTES ObjectAttributes
;
412 UNICODE_STRING DirName
;
415 POBJECT_DIRECTORY_INFORMATION DirInfo
;
420 DPRINT("ScmCheckDriver(%S) called\n", Service
->lpServiceName
);
422 if (Service
->Status
.dwServiceType
== SERVICE_KERNEL_DRIVER
)
424 RtlInitUnicodeString(&DirName
,
429 RtlInitUnicodeString(&DirName
,
433 InitializeObjectAttributes(&ObjectAttributes
,
439 Status
= NtOpenDirectoryObject(&DirHandle
,
440 DIRECTORY_QUERY
| DIRECTORY_TRAVERSE
,
442 if (!NT_SUCCESS(Status
))
447 BufferLength
= sizeof(OBJECT_DIRECTORY_INFORMATION
) +
448 2 * MAX_PATH
* sizeof(WCHAR
);
449 DirInfo
= HeapAlloc(GetProcessHeap(),
456 Status
= NtQueryDirectoryObject(DirHandle
,
463 if (Status
== STATUS_NO_MORE_ENTRIES
)
465 /* FIXME: Add current service to 'failed service' list */
466 DPRINT("Service '%S' failed\n", Service
->lpServiceName
);
470 if (!NT_SUCCESS(Status
))
473 DPRINT("Comparing: '%S' '%wZ'\n", Service
->lpServiceName
, &DirInfo
->Name
);
475 if (_wcsicmp(Service
->lpServiceName
, DirInfo
->Name
.Buffer
) == 0)
477 DPRINT("Found: '%S' '%wZ'\n",
478 Service
->lpServiceName
, &DirInfo
->Name
);
480 /* Mark service as 'running' */
481 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
483 /* Mark the service group as 'running' */
484 if (Service
->lpGroup
!= NULL
)
486 Service
->lpGroup
->ServicesRunning
= TRUE
;
493 HeapFree(GetProcessHeap(),
498 return STATUS_SUCCESS
;
503 ScmGetBootAndSystemDriverState(VOID
)
505 PLIST_ENTRY ServiceEntry
;
506 PSERVICE CurrentService
;
508 DPRINT("ScmGetBootAndSystemDriverState() called\n");
510 ServiceEntry
= ServiceListHead
.Flink
;
511 while (ServiceEntry
!= &ServiceListHead
)
513 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
515 if (CurrentService
->dwStartType
== SERVICE_BOOT_START
||
516 CurrentService
->dwStartType
== SERVICE_SYSTEM_START
)
519 DPRINT(" Checking service: %S\n", CurrentService
->lpServiceName
);
521 ScmCheckDriver(CurrentService
);
524 ServiceEntry
= ServiceEntry
->Flink
;
527 DPRINT("ScmGetBootAndSystemDriverState() done\n");
532 ScmSendStartCommand(PSERVICE Service
,
535 PSCM_START_PACKET StartPacket
;
537 DWORD ArgsLength
= 0;
542 DPRINT("ScmSendStartCommand() called\n");
544 /* Calculate the total length of the start command line */
545 TotalLength
= wcslen(Service
->lpServiceName
) + 1;
546 if (Arguments
!= NULL
)
551 Length
= wcslen(Ptr
) + 1;
552 TotalLength
+= Length
;
553 ArgsLength
+= Length
;
555 DPRINT("Arg: %S\n", Ptr
);
559 DPRINT("ArgsLength: %ld\nTotalLength: %ld\n\n", ArgsLength
, TotalLength
);
561 /* Allocate start command packet */
562 StartPacket
= HeapAlloc(GetProcessHeap(),
564 sizeof(SCM_START_PACKET
) + (TotalLength
- 1) * sizeof(WCHAR
));
565 if (StartPacket
== NULL
)
566 return ERROR_NOT_ENOUGH_MEMORY
;
568 StartPacket
->Command
= SCM_START_COMMAND
;
569 StartPacket
->Size
= TotalLength
;
570 Ptr
= &StartPacket
->Arguments
[0];
571 wcscpy(Ptr
, Service
->lpServiceName
);
572 Ptr
+= (wcslen(Service
->lpServiceName
) + 1);
574 /* Copy argument list */
575 if (Arguments
!= NULL
)
577 memcpy(Ptr
, Arguments
, ArgsLength
);
581 /* Terminate the argument list */
584 /* Send the start command */
585 WriteFile(Service
->ControlPipeHandle
,
587 sizeof(SCM_START_PACKET
) + (TotalLength
- 1) * sizeof(WCHAR
),
591 /* FIXME: Read the reply */
593 /* Release the start command packet */
594 HeapFree(GetProcessHeap(),
598 DPRINT("ScmSendStartCommand() done\n");
600 return ERROR_SUCCESS
;
605 ScmStartUserModeService(PSERVICE Service
,
608 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
609 PROCESS_INFORMATION ProcessInformation
;
610 STARTUPINFOW StartupInfo
;
611 UNICODE_STRING ImagePath
;
615 DWORD dwError
= ERROR_SUCCESS
;
617 RtlInitUnicodeString(&ImagePath
, NULL
);
619 /* Get service data */
620 RtlZeroMemory(&QueryTable
,
623 QueryTable
[0].Name
= L
"Type";
624 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
625 QueryTable
[0].EntryContext
= &Type
;
627 QueryTable
[1].Name
= L
"ImagePath";
628 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
629 QueryTable
[1].EntryContext
= &ImagePath
;
631 Status
= RtlQueryRegistryValues(RTL_REGISTRY_SERVICES
,
632 Service
->lpServiceName
,
636 if (!NT_SUCCESS(Status
))
638 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
639 return RtlNtStatusToDosError(Status
);
641 DPRINT("ImagePath: '%S'\n", ImagePath
.Buffer
);
642 DPRINT("Type: %lx\n", Type
);
644 /* Create '\\.\pipe\net\NtControlPipe' instance */
645 Service
->ControlPipeHandle
= CreateNamedPipeW(L
"\\\\.\\pipe\\net\\NtControlPipe",
647 PIPE_TYPE_MESSAGE
| PIPE_READMODE_MESSAGE
| PIPE_WAIT
,
653 DPRINT("CreateNamedPipeW() done\n");
654 if (Service
->ControlPipeHandle
== INVALID_HANDLE_VALUE
)
656 DPRINT1("Failed to create control pipe!\n");
657 return GetLastError();
660 StartupInfo
.cb
= sizeof(StartupInfo
);
661 StartupInfo
.lpReserved
= NULL
;
662 StartupInfo
.lpDesktop
= NULL
;
663 StartupInfo
.lpTitle
= NULL
;
664 StartupInfo
.dwFlags
= 0;
665 StartupInfo
.cbReserved2
= 0;
666 StartupInfo
.lpReserved2
= 0;
668 Result
= CreateProcessW(ImagePath
.Buffer
,
673 DETACHED_PROCESS
| CREATE_SUSPENDED
,
677 &ProcessInformation
);
678 RtlFreeUnicodeString(&ImagePath
);
682 dwError
= GetLastError();
683 /* Close control pipe */
684 CloseHandle(Service
->ControlPipeHandle
);
685 Service
->ControlPipeHandle
= INVALID_HANDLE_VALUE
;
687 DPRINT1("Starting '%S' failed!\n", Service
->lpServiceName
);
691 DPRINT("Process Id: %lu Handle %lx\n",
692 ProcessInformation
.dwProcessId
,
693 ProcessInformation
.hProcess
);
694 DPRINT("Thread Id: %lu Handle %lx\n",
695 ProcessInformation
.dwThreadId
,
696 ProcessInformation
.hThread
);
698 /* Get process and thread ids */
699 Service
->ProcessId
= ProcessInformation
.dwProcessId
;
700 Service
->ThreadId
= ProcessInformation
.dwThreadId
;
703 ResumeThread(ProcessInformation
.hThread
);
705 /* Connect control pipe */
706 if (ConnectNamedPipe(Service
->ControlPipeHandle
, NULL
))
708 DWORD dwProcessId
= 0;
711 DPRINT("Control pipe connected!\n");
713 /* Read thread id from pipe */
714 if (!ReadFile(Service
->ControlPipeHandle
,
715 (LPVOID
)&dwProcessId
,
720 dwError
= GetLastError();
721 DPRINT1("Reading the service control pipe failed (Error %lu)\n",
726 DPRINT("Received process id %lu\n", dwProcessId
);
728 /* Send start command */
729 dwError
= ScmSendStartCommand(Service
, lpArgs
);
734 dwError
= GetLastError();
735 DPRINT("Connecting control pipe failed!\n");
737 /* Close control pipe */
738 CloseHandle(Service
->ControlPipeHandle
);
739 Service
->ControlPipeHandle
= INVALID_HANDLE_VALUE
;
740 Service
->ProcessId
= 0;
741 Service
->ThreadId
= 0;
744 /* Close process and thread handle */
745 CloseHandle(ProcessInformation
.hThread
);
746 CloseHandle(ProcessInformation
.hProcess
);
753 ScmStartService(PSERVICE Service
, LPWSTR lpArgs
)
755 PSERVICE_GROUP Group
= Service
->lpGroup
;
756 DWORD dwError
= ERROR_SUCCESS
;
758 DPRINT("ScmStartService() called\n");
760 Service
->ControlPipeHandle
= INVALID_HANDLE_VALUE
;
761 DPRINT("Service->Type: %lu\n", Service
->Status
.dwServiceType
);
763 if (Service
->Status
.dwServiceType
& SERVICE_DRIVER
)
766 dwError
= ScmLoadDriver(Service
);
767 if (dwError
== ERROR_SUCCESS
)
768 Service
->Status
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
;
772 /* Start user-mode service */
773 dwError
= ScmStartUserModeService(Service
, lpArgs
);
776 DPRINT("ScmStartService() done (Error %lu)\n", dwError
);
778 if (dwError
== ERROR_SUCCESS
)
782 Group
->ServicesRunning
= TRUE
;
784 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
789 switch (Service
->ErrorControl
)
791 case SERVICE_ERROR_NORMAL
:
792 /* FIXME: Log error */
795 case SERVICE_ERROR_SEVERE
:
796 if (IsLastKnownGood
== FALSE
)
798 /* FIXME: Boot last known good configuration */
802 case SERVICE_ERROR_CRITICAL
:
803 if (IsLastKnownGood
== FALSE
)
805 /* FIXME: Boot last known good configuration */
821 ScmAutoStartServices(VOID
)
823 PLIST_ENTRY GroupEntry
;
824 PLIST_ENTRY ServiceEntry
;
825 PSERVICE_GROUP CurrentGroup
;
826 PSERVICE CurrentService
;
829 /* Clear 'ServiceVisited' flag */
830 ServiceEntry
= ServiceListHead
.Flink
;
831 while (ServiceEntry
!= &ServiceListHead
)
833 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
834 CurrentService
->ServiceVisited
= FALSE
;
835 ServiceEntry
= ServiceEntry
->Flink
;
838 /* Start all services which are members of an existing group */
839 GroupEntry
= GroupListHead
.Flink
;
840 while (GroupEntry
!= &GroupListHead
)
842 CurrentGroup
= CONTAINING_RECORD(GroupEntry
, SERVICE_GROUP
, GroupListEntry
);
844 DPRINT("Group '%S'\n", CurrentGroup
->lpGroupName
);
846 /* Start all services witch have a valid tag */
847 for (i
= 0; i
< CurrentGroup
->TagCount
; i
++)
849 ServiceEntry
= ServiceListHead
.Flink
;
850 while (ServiceEntry
!= &ServiceListHead
)
852 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
854 if ((CurrentService
->lpGroup
== CurrentGroup
) &&
855 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
856 (CurrentService
->ServiceVisited
== FALSE
) &&
857 (CurrentService
->dwTag
== CurrentGroup
->TagArray
[i
]))
859 CurrentService
->ServiceVisited
= TRUE
;
860 ScmStartService(CurrentService
, NULL
);
863 ServiceEntry
= ServiceEntry
->Flink
;
867 /* Start all services which have an invalid tag or which do not have a tag */
868 ServiceEntry
= ServiceListHead
.Flink
;
869 while (ServiceEntry
!= &ServiceListHead
)
871 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
873 if ((CurrentService
->lpGroup
== CurrentGroup
) &&
874 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
875 (CurrentService
->ServiceVisited
== FALSE
))
877 CurrentService
->ServiceVisited
= TRUE
;
878 ScmStartService(CurrentService
, NULL
);
881 ServiceEntry
= ServiceEntry
->Flink
;
884 GroupEntry
= GroupEntry
->Flink
;
887 /* Start all services which are members of any non-existing group */
888 ServiceEntry
= ServiceListHead
.Flink
;
889 while (ServiceEntry
!= &ServiceListHead
)
891 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
893 if ((CurrentService
->lpGroup
!= NULL
) &&
894 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
895 (CurrentService
->ServiceVisited
== FALSE
))
897 CurrentService
->ServiceVisited
= TRUE
;
898 ScmStartService(CurrentService
, NULL
);
901 ServiceEntry
= ServiceEntry
->Flink
;
904 /* Start all services which are not a member of any group */
905 ServiceEntry
= ServiceListHead
.Flink
;
906 while (ServiceEntry
!= &ServiceListHead
)
908 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
910 if ((CurrentService
->lpGroup
== NULL
) &&
911 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
912 (CurrentService
->ServiceVisited
== FALSE
))
914 CurrentService
->ServiceVisited
= TRUE
;
915 ScmStartService(CurrentService
, NULL
);
918 ServiceEntry
= ServiceEntry
->Flink
;
921 /* Clear 'ServiceVisited' flag again */
922 ServiceEntry
= ServiceListHead
.Flink
;
923 while (ServiceEntry
!= &ServiceListHead
)
925 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
926 CurrentService
->ServiceVisited
= FALSE
;
927 ServiceEntry
= ServiceEntry
->Flink
;