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 if (lpService
->lpGroup
!= NULL
)
284 DPRINT("Group: '%S'\n", lpService
->lpGroup
->lpGroupName
);
286 DPRINT("Start %lx Type %lx Tag %lx ErrorControl %lx\n",
287 lpService
->dwStartType
,
288 lpService
->Status
.dwServiceType
,
290 lpService
->dwErrorControl
);
292 if (ScmIsDeleteFlagSet(hServiceKey
))
293 lpService
->bDeleted
= TRUE
;
297 HeapFree(GetProcessHeap(), 0, lpGroup
);
299 if (lpDisplayName
!= NULL
)
300 HeapFree(GetProcessHeap(), 0, lpDisplayName
);
307 ScmDeleteMarkedServices(VOID
)
309 PLIST_ENTRY ServiceEntry
;
310 PSERVICE CurrentService
;
312 ServiceEntry
= ServiceListHead
.Flink
;
313 while (ServiceEntry
!= &ServiceListHead
)
315 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
317 ServiceEntry
= ServiceEntry
->Flink
;
319 if (CurrentService
->bDeleted
== TRUE
)
321 DPRINT1("Delete service: %S\n", CurrentService
->lpServiceName
);
323 /* FIXME: Delete the registry keys */
325 /* FIXME: Delete the service record from the list */
333 ScmCreateServiceDatabase(VOID
)
335 WCHAR szSubKey
[MAX_PATH
];
339 DWORD dwSubKeyLength
;
340 FILETIME ftLastChanged
;
343 DPRINT("ScmCreateServiceDatabase() called\n");
345 dwError
= ScmCreateGroupList();
346 if (dwError
!= ERROR_SUCCESS
)
349 /* Initialize basic variables */
350 InitializeListHead(&ServiceListHead
);
352 /* Initialize the database lock */
353 RtlInitializeResource(&DatabaseLock
);
355 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
356 L
"System\\CurrentControlSet\\Services",
360 if (dwError
!= ERROR_SUCCESS
)
366 dwSubKeyLength
= MAX_PATH
;
367 dwError
= RegEnumKeyExW(hServicesKey
,
375 if (dwError
== ERROR_SUCCESS
&&
378 DPRINT("SubKeyName: '%S'\n", szSubKey
);
380 dwError
= RegOpenKeyExW(hServicesKey
,
385 if (dwError
== ERROR_SUCCESS
)
387 dwError
= CreateServiceListEntry(szSubKey
,
390 RegCloseKey(hServiceKey
);
394 if (dwError
!= ERROR_SUCCESS
)
400 RegCloseKey(hServicesKey
);
402 /* Delete services that are marked for delete */
403 ScmDeleteMarkedServices();
405 DPRINT("ScmCreateServiceDatabase() done\n");
407 return ERROR_SUCCESS
;
412 ScmCheckDriver(PSERVICE Service
)
414 OBJECT_ATTRIBUTES ObjectAttributes
;
415 UNICODE_STRING DirName
;
418 POBJECT_DIRECTORY_INFORMATION DirInfo
;
423 DPRINT("ScmCheckDriver(%S) called\n", Service
->lpServiceName
);
425 if (Service
->Status
.dwServiceType
== SERVICE_KERNEL_DRIVER
)
427 RtlInitUnicodeString(&DirName
,
432 RtlInitUnicodeString(&DirName
,
436 InitializeObjectAttributes(&ObjectAttributes
,
442 Status
= NtOpenDirectoryObject(&DirHandle
,
443 DIRECTORY_QUERY
| DIRECTORY_TRAVERSE
,
445 if (!NT_SUCCESS(Status
))
450 BufferLength
= sizeof(OBJECT_DIRECTORY_INFORMATION
) +
451 2 * MAX_PATH
* sizeof(WCHAR
);
452 DirInfo
= HeapAlloc(GetProcessHeap(),
459 Status
= NtQueryDirectoryObject(DirHandle
,
466 if (Status
== STATUS_NO_MORE_ENTRIES
)
468 /* FIXME: Add current service to 'failed service' list */
469 DPRINT("Service '%S' failed\n", Service
->lpServiceName
);
473 if (!NT_SUCCESS(Status
))
476 DPRINT("Comparing: '%S' '%wZ'\n", Service
->lpServiceName
, &DirInfo
->Name
);
478 if (_wcsicmp(Service
->lpServiceName
, DirInfo
->Name
.Buffer
) == 0)
480 DPRINT("Found: '%S' '%wZ'\n",
481 Service
->lpServiceName
, &DirInfo
->Name
);
483 /* Mark service as 'running' */
484 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
486 /* Mark the service group as 'running' */
487 if (Service
->lpGroup
!= NULL
)
489 Service
->lpGroup
->ServicesRunning
= TRUE
;
496 HeapFree(GetProcessHeap(),
501 return STATUS_SUCCESS
;
506 ScmGetBootAndSystemDriverState(VOID
)
508 PLIST_ENTRY ServiceEntry
;
509 PSERVICE CurrentService
;
511 DPRINT("ScmGetBootAndSystemDriverState() called\n");
513 ServiceEntry
= ServiceListHead
.Flink
;
514 while (ServiceEntry
!= &ServiceListHead
)
516 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
518 if (CurrentService
->dwStartType
== SERVICE_BOOT_START
||
519 CurrentService
->dwStartType
== SERVICE_SYSTEM_START
)
522 DPRINT(" Checking service: %S\n", CurrentService
->lpServiceName
);
524 ScmCheckDriver(CurrentService
);
527 ServiceEntry
= ServiceEntry
->Flink
;
530 DPRINT("ScmGetBootAndSystemDriverState() done\n");
535 ScmControlService(PSERVICE Service
,
537 LPSERVICE_STATUS lpServiceStatus
)
539 PSCM_CONTROL_PACKET ControlPacket
;
542 DPRINT("ScmControlService() called\n");
544 ControlPacket
= HeapAlloc(GetProcessHeap(),
546 sizeof(SCM_CONTROL_PACKET
));
547 if (ControlPacket
== NULL
)
548 return ERROR_NOT_ENOUGH_MEMORY
;
550 ControlPacket
->dwControl
= dwControl
;
552 /* Send the start command */
553 WriteFile(Service
->ControlPipeHandle
,
555 sizeof(SCM_CONTROL_PACKET
),
559 /* FIXME: Read the reply */
561 /* Release the contol packet */
562 HeapFree(GetProcessHeap(),
566 DPRINT("ScmControlService) done\n");
568 return ERROR_SUCCESS
;
573 ScmSendStartCommand(PSERVICE Service
,
576 PSCM_CONTROL_PACKET ControlPacket
;
578 DWORD ArgsLength
= 0;
583 DPRINT("ScmSendStartCommand() called\n");
585 /* Calculate the total length of the start command line */
586 TotalLength
= wcslen(Service
->lpServiceName
) + 1;
587 if (Arguments
!= NULL
)
592 Length
= wcslen(Ptr
) + 1;
593 TotalLength
+= Length
;
594 ArgsLength
+= Length
;
596 DPRINT("Arg: %S\n", Ptr
);
600 DPRINT("ArgsLength: %ld\nTotalLength: %ld\n\n", ArgsLength
, TotalLength
);
602 /* Allocate a control packet */
603 ControlPacket
= HeapAlloc(GetProcessHeap(),
605 sizeof(SCM_CONTROL_PACKET
) + (TotalLength
- 1) * sizeof(WCHAR
));
606 if (ControlPacket
== NULL
)
607 return ERROR_NOT_ENOUGH_MEMORY
;
609 ControlPacket
->dwControl
= SERVICE_CONTROL_START
;
610 ControlPacket
->dwSize
= TotalLength
;
611 Ptr
= &ControlPacket
->szArguments
[0];
612 wcscpy(Ptr
, Service
->lpServiceName
);
613 Ptr
+= (wcslen(Service
->lpServiceName
) + 1);
615 /* Copy argument list */
616 if (Arguments
!= NULL
)
618 memcpy(Ptr
, Arguments
, ArgsLength
);
622 /* Terminate the argument list */
625 /* Send the start command */
626 WriteFile(Service
->ControlPipeHandle
,
628 sizeof(SCM_CONTROL_PACKET
) + (TotalLength
- 1) * sizeof(WCHAR
),
632 /* FIXME: Read the reply */
634 /* Release the contol packet */
635 HeapFree(GetProcessHeap(),
639 DPRINT("ScmSendStartCommand() done\n");
641 return ERROR_SUCCESS
;
646 ScmStartUserModeService(PSERVICE Service
,
649 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
650 PROCESS_INFORMATION ProcessInformation
;
651 STARTUPINFOW StartupInfo
;
652 UNICODE_STRING ImagePath
;
656 DWORD dwError
= ERROR_SUCCESS
;
658 RtlInitUnicodeString(&ImagePath
, NULL
);
660 /* Get service data */
661 RtlZeroMemory(&QueryTable
,
664 QueryTable
[0].Name
= L
"Type";
665 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
666 QueryTable
[0].EntryContext
= &Type
;
668 QueryTable
[1].Name
= L
"ImagePath";
669 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
670 QueryTable
[1].EntryContext
= &ImagePath
;
672 Status
= RtlQueryRegistryValues(RTL_REGISTRY_SERVICES
,
673 Service
->lpServiceName
,
677 if (!NT_SUCCESS(Status
))
679 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
680 return RtlNtStatusToDosError(Status
);
682 DPRINT("ImagePath: '%S'\n", ImagePath
.Buffer
);
683 DPRINT("Type: %lx\n", Type
);
685 /* Create '\\.\pipe\net\NtControlPipe' instance */
686 Service
->ControlPipeHandle
= CreateNamedPipeW(L
"\\\\.\\pipe\\net\\NtControlPipe",
688 PIPE_TYPE_MESSAGE
| PIPE_READMODE_MESSAGE
| PIPE_WAIT
,
694 DPRINT("CreateNamedPipeW() done\n");
695 if (Service
->ControlPipeHandle
== INVALID_HANDLE_VALUE
)
697 DPRINT1("Failed to create control pipe!\n");
698 return GetLastError();
701 StartupInfo
.cb
= sizeof(StartupInfo
);
702 StartupInfo
.lpReserved
= NULL
;
703 StartupInfo
.lpDesktop
= NULL
;
704 StartupInfo
.lpTitle
= NULL
;
705 StartupInfo
.dwFlags
= 0;
706 StartupInfo
.cbReserved2
= 0;
707 StartupInfo
.lpReserved2
= 0;
709 Result
= CreateProcessW(ImagePath
.Buffer
,
714 DETACHED_PROCESS
| CREATE_SUSPENDED
,
718 &ProcessInformation
);
719 RtlFreeUnicodeString(&ImagePath
);
723 dwError
= GetLastError();
724 /* Close control pipe */
725 CloseHandle(Service
->ControlPipeHandle
);
726 Service
->ControlPipeHandle
= INVALID_HANDLE_VALUE
;
728 DPRINT1("Starting '%S' failed!\n", Service
->lpServiceName
);
732 DPRINT("Process Id: %lu Handle %lx\n",
733 ProcessInformation
.dwProcessId
,
734 ProcessInformation
.hProcess
);
735 DPRINT("Thread Id: %lu Handle %lx\n",
736 ProcessInformation
.dwThreadId
,
737 ProcessInformation
.hThread
);
739 /* Get process and thread ids */
740 Service
->ProcessId
= ProcessInformation
.dwProcessId
;
741 Service
->ThreadId
= ProcessInformation
.dwThreadId
;
744 ResumeThread(ProcessInformation
.hThread
);
746 /* Connect control pipe */
747 if (ConnectNamedPipe(Service
->ControlPipeHandle
, NULL
))
749 DWORD dwProcessId
= 0;
752 DPRINT("Control pipe connected!\n");
754 /* Read thread id from pipe */
755 if (!ReadFile(Service
->ControlPipeHandle
,
756 (LPVOID
)&dwProcessId
,
761 dwError
= GetLastError();
762 DPRINT1("Reading the service control pipe failed (Error %lu)\n",
767 DPRINT("Received process id %lu\n", dwProcessId
);
769 /* Send start command */
770 dwError
= ScmSendStartCommand(Service
, lpArgs
);
775 dwError
= GetLastError();
776 DPRINT("Connecting control pipe failed!\n");
778 /* Close control pipe */
779 CloseHandle(Service
->ControlPipeHandle
);
780 Service
->ControlPipeHandle
= INVALID_HANDLE_VALUE
;
781 Service
->ProcessId
= 0;
782 Service
->ThreadId
= 0;
785 /* Close process and thread handle */
786 CloseHandle(ProcessInformation
.hThread
);
787 CloseHandle(ProcessInformation
.hProcess
);
794 ScmStartService(PSERVICE Service
, LPWSTR lpArgs
)
796 PSERVICE_GROUP Group
= Service
->lpGroup
;
797 DWORD dwError
= ERROR_SUCCESS
;
799 DPRINT("ScmStartService() called\n");
801 Service
->ControlPipeHandle
= INVALID_HANDLE_VALUE
;
802 DPRINT("Service->Type: %lu\n", Service
->Status
.dwServiceType
);
804 if (Service
->Status
.dwServiceType
& SERVICE_DRIVER
)
807 dwError
= ScmLoadDriver(Service
);
808 if (dwError
== ERROR_SUCCESS
)
809 Service
->Status
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
;
813 /* Start user-mode service */
814 dwError
= ScmStartUserModeService(Service
, lpArgs
);
817 DPRINT("ScmStartService() done (Error %lu)\n", dwError
);
819 if (dwError
== ERROR_SUCCESS
)
823 Group
->ServicesRunning
= TRUE
;
825 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
830 switch (Service
->ErrorControl
)
832 case SERVICE_ERROR_NORMAL
:
833 /* FIXME: Log error */
836 case SERVICE_ERROR_SEVERE
:
837 if (IsLastKnownGood
== FALSE
)
839 /* FIXME: Boot last known good configuration */
843 case SERVICE_ERROR_CRITICAL
:
844 if (IsLastKnownGood
== FALSE
)
846 /* FIXME: Boot last known good configuration */
862 ScmAutoStartServices(VOID
)
864 PLIST_ENTRY GroupEntry
;
865 PLIST_ENTRY ServiceEntry
;
866 PSERVICE_GROUP CurrentGroup
;
867 PSERVICE CurrentService
;
870 /* Clear 'ServiceVisited' flag */
871 ServiceEntry
= ServiceListHead
.Flink
;
872 while (ServiceEntry
!= &ServiceListHead
)
874 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
875 CurrentService
->ServiceVisited
= FALSE
;
876 ServiceEntry
= ServiceEntry
->Flink
;
879 /* Start all services which are members of an existing group */
880 GroupEntry
= GroupListHead
.Flink
;
881 while (GroupEntry
!= &GroupListHead
)
883 CurrentGroup
= CONTAINING_RECORD(GroupEntry
, SERVICE_GROUP
, GroupListEntry
);
885 DPRINT("Group '%S'\n", CurrentGroup
->lpGroupName
);
887 /* Start all services witch have a valid tag */
888 for (i
= 0; i
< CurrentGroup
->TagCount
; i
++)
890 ServiceEntry
= ServiceListHead
.Flink
;
891 while (ServiceEntry
!= &ServiceListHead
)
893 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
895 if ((CurrentService
->lpGroup
== CurrentGroup
) &&
896 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
897 (CurrentService
->ServiceVisited
== FALSE
) &&
898 (CurrentService
->dwTag
== CurrentGroup
->TagArray
[i
]))
900 CurrentService
->ServiceVisited
= TRUE
;
901 ScmStartService(CurrentService
, NULL
);
904 ServiceEntry
= ServiceEntry
->Flink
;
908 /* Start all services which have an invalid tag or which do not have a tag */
909 ServiceEntry
= ServiceListHead
.Flink
;
910 while (ServiceEntry
!= &ServiceListHead
)
912 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
914 if ((CurrentService
->lpGroup
== CurrentGroup
) &&
915 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
916 (CurrentService
->ServiceVisited
== FALSE
))
918 CurrentService
->ServiceVisited
= TRUE
;
919 ScmStartService(CurrentService
, NULL
);
922 ServiceEntry
= ServiceEntry
->Flink
;
925 GroupEntry
= GroupEntry
->Flink
;
928 /* Start all services which are members of any non-existing group */
929 ServiceEntry
= ServiceListHead
.Flink
;
930 while (ServiceEntry
!= &ServiceListHead
)
932 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
934 if ((CurrentService
->lpGroup
!= NULL
) &&
935 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
936 (CurrentService
->ServiceVisited
== FALSE
))
938 CurrentService
->ServiceVisited
= TRUE
;
939 ScmStartService(CurrentService
, NULL
);
942 ServiceEntry
= ServiceEntry
->Flink
;
945 /* Start all services which are not a member of any group */
946 ServiceEntry
= ServiceListHead
.Flink
;
947 while (ServiceEntry
!= &ServiceListHead
)
949 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
951 if ((CurrentService
->lpGroup
== NULL
) &&
952 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
953 (CurrentService
->ServiceVisited
== FALSE
))
955 CurrentService
->ServiceVisited
= TRUE
;
956 ScmStartService(CurrentService
, NULL
);
959 ServiceEntry
= ServiceEntry
->Flink
;
962 /* Clear 'ServiceVisited' flag again */
963 ServiceEntry
= ServiceListHead
.Flink
;
964 while (ServiceEntry
!= &ServiceListHead
)
966 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
967 CurrentService
->ServiceVisited
= FALSE
;
968 ServiceEntry
= ServiceEntry
->Flink
;