Start services again and call a services main routine.

svn path=/trunk/; revision=12890
This commit is contained in:
Eric Kohl 2005-01-08 18:11:46 +00:00
parent de8627877c
commit 0a7494dd76
2 changed files with 232 additions and 214 deletions

View file

@ -19,7 +19,7 @@
/* TYPES *********************************************************************/
typedef struct
typedef struct _ACTIVE_SERVICE
{
DWORD ThreadId;
UNICODE_STRING ServiceName;
@ -28,31 +28,32 @@ typedef struct
SERVICE_STATUS ServiceStatus;
} ACTIVE_SERVICE, *PACTIVE_SERVICE;
/* GLOBALS *******************************************************************/
static ULONG ActiveServiceCount;
static PACTIVE_SERVICE ActiveServices;
static DWORD dwActiveServiceCount = 0;
static PACTIVE_SERVICE lpActiveServices = NULL;
/* static PHANDLE ActiveServicesThreadHandles; */ /* uncomment when in use */
/* FUNCTIONS *****************************************************************/
/* FUNCTIONS *****************************************************************/
static PACTIVE_SERVICE
ScLookupServiceByServiceName(LPWSTR lpServiceName)
{
DWORD i;
for (i = 0; i < ActiveServiceCount; i++)
for (i = 0; i < dwActiveServiceCount; i++)
{
if (_wcsicmp(ActiveServices[i].ServiceName.Buffer, lpServiceName) == 0)
if (_wcsicmp(lpActiveServices[i].ServiceName.Buffer, lpServiceName) == 0)
{
return(&ActiveServices[i]);
return &lpActiveServices[i];
}
}
SetLastError(ERROR_SERVICE_DOES_NOT_EXIST);
return(NULL);
return NULL;
}
@ -61,17 +62,35 @@ ScLookupServiceByThreadId(DWORD ThreadId)
{
DWORD i;
for (i = 0; i < ActiveServiceCount; i++)
for (i = 0; i < dwActiveServiceCount; i++)
{
if (ActiveServices[i].ThreadId == ThreadId)
if (lpActiveServices[i].ThreadId == ThreadId)
{
return(&ActiveServices[i]);
return &lpActiveServices[i];
}
}
SetLastError(ERROR_SERVICE_DOES_NOT_EXIST);
return(NULL);
return NULL;
}
static DWORD WINAPI
ScServiceMainStub(LPVOID Context)
{
PACTIVE_SERVICE lpService;
lpService = (PACTIVE_SERVICE)Context;
DPRINT("ScServiceMainStub() called\n");
/* FIXME: Send argc and argv (from command line) as arguments */
(lpService->MainFunction)(0, NULL);
return ERROR_SUCCESS;
}
@ -82,25 +101,31 @@ ScConnectControlPipe(HANDLE *hPipe)
DWORD dwProcessId;
DWORD dwState;
WaitNamedPipeW(L"\\\\.\\pipe\\net\\NtControlPipe",
15000);
if (!WaitNamedPipeW(L"\\\\.\\pipe\\net\\NtControlPipe", 15000))
{
DPRINT1("WaitNamedPipe() failed (Error %lu)\n", GetLastError());
return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT;
}
*hPipe = CreateFileW(L"\\\\.\\pipe\\net\\NtControlPipe",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (*hPipe == INVALID_HANDLE_VALUE)
return(ERROR_FAILED_SERVICE_CONTROLLER_CONNECT);
{
DPRINT1("CreateFileW() failed (Error %lu)\n", GetLastError());
return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT;
}
dwState = PIPE_READMODE_MESSAGE;
if (!SetNamedPipeHandleState(*hPipe, &dwState, NULL, NULL))
{
CloseHandle(hPipe);
*hPipe = INVALID_HANDLE_VALUE;
return(ERROR_FAILED_SERVICE_CONTROLLER_CONNECT);
return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT;
}
dwProcessId = GetCurrentProcessId();
@ -110,14 +135,36 @@ ScConnectControlPipe(HANDLE *hPipe)
&dwBytesWritten,
NULL);
return(ERROR_SUCCESS);
DPRINT("Sent process id %lu\n", dwProcessId);
return ERROR_SUCCESS;
}
static VOID
ScServiceDispatcher(HANDLE hPipe, PVOID p1, PVOID p2)
static BOOL
ScServiceDispatcher(HANDLE hPipe,
PUCHAR lpBuffer,
DWORD dwBufferSize)
{
DPRINT1("ScDispatcherLoop() called\n");
PACTIVE_SERVICE lpService;
HANDLE ThreadHandle;
DPRINT("ScDispatcherLoop() called\n");
lpService = &lpActiveServices[0];
ThreadHandle = CreateThread(NULL,
0,
ScServiceMainStub,
lpService,
CREATE_SUSPENDED,
&lpService->ThreadId);
if (ThreadHandle == NULL)
return FALSE;
ResumeThread(ThreadHandle);
CloseHandle(ThreadHandle);
#if 0
while (TRUE)
@ -128,19 +175,8 @@ ScServiceDispatcher(HANDLE hPipe, PVOID p1, PVOID p2)
}
#endif
}
DWORD WINAPI
ScServiceMainStub(LPVOID Context)
{
LPSERVICE_MAIN_FUNCTIONW lpServiceProc = (LPSERVICE_MAIN_FUNCTIONW)Context;
/* FIXME: Send argc and argv (from command line) as arguments */
(lpServiceProc)(0, NULL);
return ERROR_SUCCESS;
return TRUE;
}
@ -161,7 +197,7 @@ RegisterServiceCtrlHandlerA(LPCSTR lpServiceName,
if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ServiceNameU, &ServiceNameA, TRUE)))
{
SetLastError(ERROR_OUTOFMEMORY);
return((SERVICE_STATUS_HANDLE)0);
return (SERVICE_STATUS_HANDLE)0;
}
SHandle = RegisterServiceCtrlHandlerW(ServiceNameU.Buffer,
@ -169,7 +205,7 @@ RegisterServiceCtrlHandlerA(LPCSTR lpServiceName,
RtlFreeUnicodeString(&ServiceNameU);
return(SHandle);
return SHandle;
}
@ -187,12 +223,12 @@ RegisterServiceCtrlHandlerW(LPCWSTR lpServiceName,
Service = ScLookupServiceByServiceName((LPWSTR)lpServiceName);
if (Service == NULL)
{
return((SERVICE_STATUS_HANDLE)NULL);
return (SERVICE_STATUS_HANDLE)NULL;
}
Service->HandlerFunction = lpHandlerProc;
return((SERVICE_STATUS_HANDLE)Service->ThreadId);
return (SERVICE_STATUS_HANDLE)Service->ThreadId;
}
@ -208,7 +244,7 @@ SetServiceBits(SERVICE_STATUS_HANDLE hServiceStatus,
BOOL bUpdateImmediately)
{
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return(FALSE);
return FALSE;
}
@ -242,14 +278,14 @@ SetServiceStatus(SERVICE_STATUS_HANDLE hServiceStatus,
if (!Service)
{
SetLastError(ERROR_INVALID_HANDLE);
return(FALSE);
return FALSE;
}
RtlCopyMemory(&Service->ServiceStatus,
lpServiceStatus,
sizeof(SERVICE_STATUS));
return(TRUE);
return TRUE;
}
@ -261,65 +297,71 @@ SetServiceStatus(SERVICE_STATUS_HANDLE hServiceStatus,
BOOL STDCALL
StartServiceCtrlDispatcherA(LPSERVICE_TABLE_ENTRYA lpServiceStartTable)
{
// FIXME how to deal with diffs between ANSI/UNICODE
#if 0
LPSERVICE_TABLE_ENTRYW ServiceStartTableW;
ANSI_STRING ServiceNameA;
UNICODE_STRING ServiceNameW;
ULONG i, j;
ULONG Count;
BOOL b;
ULONG i;
HANDLE hPipe;
DWORD dwError;
PUCHAR lpMessageBuffer;
DPRINT("StartServiceCtrlDispatcherA() called\n");
i = 0;
while (lpServiceStartTable[i].lpServiceProc != NULL)
{
i++;
}
Count = i;
ServiceStartTableW = RtlAllocateHeap(RtlGetProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof(SERVICE_TABLE_ENTRYW) * Count);
for (i = 0; i < Count; i++)
{
RtlInitAnsiString(
&ServiceNameA,
lpServiceStartTable[i].lpServiceName);
if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(
&ServiceNameW,
&ServiceNameA,
TRUE)))
dwActiveServiceCount = i;
lpActiveServices = RtlAllocateHeap(RtlGetProcessHeap(),
HEAP_ZERO_MEMORY,
dwActiveServiceCount * sizeof(ACTIVE_SERVICE));
if (lpActiveServices == NULL)
{
for (j = 0; j < i; j++)
{
RtlInitUnicodeString(
&ServiceNameW,
ServiceStartTableW[j].lpServiceName);
RtlFreeUnicodeString(&ServiceNameW);
}
RtlFreeHeap(RtlGetProcessHeap(), 0, ServiceStartTableW);
SetLastError(ERROR_OUTOFMEMORY);
return FALSE;
}
ServiceStartTableW[i].lpServiceName = ServiceNameW.Buffer;
ServiceStartTableW[i].lpServiceProc =
lpServiceStartTable[i].lpServiceProc;
}
b = StartServiceCtrlDispatcherW(ServiceStartTableW);
for (i = 0; i < Count; i++)
{
RtlFreeHeap(RtlGetProcessHeap(), 0, ServiceStartTableW[i].lpServiceName);
return FALSE;
}
RtlFreeHeap(RtlGetProcessHeap(), 0, ServiceStartTableW);
/* Copy service names and start procedure */
for (i = 0; i < dwActiveServiceCount; i++)
{
RtlCreateUnicodeStringFromAsciiz(&lpActiveServices[i].ServiceName,
lpServiceStartTable[i].lpServiceName);
lpActiveServices[i].MainFunction = (LPSERVICE_MAIN_FUNCTIONW)lpServiceStartTable[i].lpServiceProc;
}
return b;
#else
UNIMPLEMENTED;
return 0;
#endif
dwError = ScConnectControlPipe(&hPipe);
if (dwError != ERROR_SUCCESS)
{
/* Free the service table */
RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
lpActiveServices = NULL;
dwActiveServiceCount = 0;
return FALSE;
}
lpMessageBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
HEAP_ZERO_MEMORY,
256);
if (lpMessageBuffer == NULL)
{
/* Free the service table */
RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
lpActiveServices = NULL;
dwActiveServiceCount = 0;
CloseHandle(hPipe);
return FALSE;
}
ScServiceDispatcher(hPipe, lpMessageBuffer, 256);
CloseHandle(hPipe);
/* Free the message buffer */
RtlFreeHeap(RtlGetProcessHeap(), 0, lpMessageBuffer);
/* Free the service table */
RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
lpActiveServices = NULL;
dwActiveServiceCount = 0;
return TRUE;
}
@ -334,6 +376,7 @@ StartServiceCtrlDispatcherW(LPSERVICE_TABLE_ENTRYW lpServiceStartTable)
ULONG i;
HANDLE hPipe;
DWORD dwError;
PUCHAR lpMessageBuffer;
DPRINT("StartServiceCtrlDispatcherW() called\n");
@ -343,99 +386,58 @@ StartServiceCtrlDispatcherW(LPSERVICE_TABLE_ENTRYW lpServiceStartTable)
i++;
}
ActiveServiceCount = i;
ActiveServices = RtlAllocateHeap(RtlGetProcessHeap(),
HEAP_ZERO_MEMORY,
ActiveServiceCount * sizeof(ACTIVE_SERVICE));
if (ActiveServices == NULL)
dwActiveServiceCount = i;
lpActiveServices = RtlAllocateHeap(RtlGetProcessHeap(),
HEAP_ZERO_MEMORY,
dwActiveServiceCount * sizeof(ACTIVE_SERVICE));
if (lpActiveServices == NULL)
{
return(FALSE);
return FALSE;
}
/* Copy service names and start procedure */
for (i = 0; i < ActiveServiceCount; i++)
for (i = 0; i < dwActiveServiceCount; i++)
{
RtlCreateUnicodeString(&ActiveServices[i].ServiceName,
RtlCreateUnicodeString(&lpActiveServices[i].ServiceName,
lpServiceStartTable[i].lpServiceName);
ActiveServices[i].MainFunction = lpServiceStartTable[i].lpServiceProc;
lpActiveServices[i].MainFunction = lpServiceStartTable[i].lpServiceProc;
}
dwError = ScConnectControlPipe(&hPipe);
if (dwError == ERROR_SUCCESS)
if (dwError != ERROR_SUCCESS)
{
/* FIXME: free the service table */
return(FALSE);
/* Free the service table */
RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
lpActiveServices = NULL;
dwActiveServiceCount = 0;
return FALSE;
}
ScServiceDispatcher(hPipe, NULL, NULL);
lpMessageBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
HEAP_ZERO_MEMORY,
256);
if (lpMessageBuffer == NULL)
{
/* Free the service table */
RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
lpActiveServices = NULL;
dwActiveServiceCount = 0;
CloseHandle(hPipe);
return FALSE;
}
ScServiceDispatcher(hPipe, lpMessageBuffer, 256);
CloseHandle(hPipe);
/* FIXME: free the service table */
/* Free the message buffer */
RtlFreeHeap(RtlGetProcessHeap(), 0, lpMessageBuffer);
return(TRUE);
/* Free the service table */
RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
lpActiveServices = NULL;
dwActiveServiceCount = 0;
#if 0
ActiveServicesThreadHandles = RtlAllocateHeap(RtlGetProcessHeap(),
HEAP_ZERO_MEMORY,
(ActiveServiceCount + 1) * sizeof(HANDLE));
if (!ActiveServicesThreadHandles)
{
RtlFreeHeap(RtlGetProcessHeap(), 0, ActiveServices);
ActiveServices = NULL;
return(FALSE);
}
for (i = 0; i<ActiveServiceCount; i++)
{
h = CreateThread(
NULL,
0,
ScServiceMainStub,
lpServiceStartTable[i].lpServiceProc,
0,
&Tid);
if (h == INVALID_HANDLE_VALUE)
{
RtlFreeHeap(RtlGetProcessHeap(), 0, ActiveServicesThreadHandles);
ActiveServicesThreadHandles = NULL;
RtlFreeHeap(RtlGetProcessHeap(), 0, ActiveServices);
ActiveServices = NULL;
return(FALSE);
}
ActiveServicesThreadHandles[i + 1] = h;
ActiveServices[i].ThreadId = Tid;
}
while (ActiveServiceCount > 0)
{
r = WaitForMultipleObjects(
ActiveServiceCount + 1,
ActiveServicesThreadHandles,
FALSE,
INFINITE);
if (r == WAIT_OBJECT_0)
{
/* Received message from the scm */
}
else if (r > WAIT_OBJECT_0 && r < (WAIT_OBJECT_0 + ActiveServiceCount))
{
/* A service died */
ActiveServiceCount--;
ActiveServicesThreadHandles[r - WAIT_OBJECT_0 - 1] =
ActiveServicesThreadHandles[ActiveServiceCount + 1];
RtlCopyMemory(
&ActiveServices[r - WAIT_OBJECT_0 - 2],
&ActiveServices[ActiveServiceCount],
sizeof(ACTIVE_SERVICE));
}
else
{
/* Bail */
}
}
return TRUE;
#endif
}
/* EOF */

View file

@ -81,7 +81,7 @@ LIST_ENTRY ServiceListHead;
/* FUNCTIONS *****************************************************************/
static NTSTATUS STDCALL
static NTSTATUS STDCALL
CreateGroupOrderListRoutine(PWSTR ValueName,
ULONG ValueType,
PVOID ValueData,
@ -127,6 +127,7 @@ CreateGroupOrderListRoutine(PWSTR ValueName,
return STATUS_SUCCESS;
}
static NTSTATUS STDCALL
CreateGroupListRoutine(PWSTR ValueName,
ULONG ValueType,
@ -148,15 +149,15 @@ CreateGroupListRoutine(PWSTR ValueName,
sizeof(SERVICE_GROUP));
if (Group == NULL)
{
return(STATUS_INSUFFICIENT_RESOURCES);
return STATUS_INSUFFICIENT_RESOURCES;
}
if (!RtlCreateUnicodeString(&Group->GroupName,
(PWSTR)ValueData))
{
return(STATUS_INSUFFICIENT_RESOURCES);
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(&QueryTable, sizeof(QueryTable));
QueryTable[0].Name = (PWSTR)ValueData;
QueryTable[0].QueryRoutine = CreateGroupOrderListRoutine;
@ -173,7 +174,7 @@ CreateGroupListRoutine(PWSTR ValueName,
&Group->GroupListEntry);
}
return(STATUS_SUCCESS);
return STATUS_SUCCESS;
}
@ -191,7 +192,7 @@ CreateServiceListEntry(PUNICODE_STRING ServiceName)
sizeof(SERVICE));
if (Service == NULL)
{
return(STATUS_INSUFFICIENT_RESOURCES);
return STATUS_INSUFFICIENT_RESOURCES;
}
/* Copy service name */
@ -202,8 +203,9 @@ CreateServiceListEntry(PUNICODE_STRING ServiceName)
if (Service->ServiceName.Buffer == NULL)
{
HeapFree(GetProcessHeap(), 0, Service);
return(STATUS_INSUFFICIENT_RESOURCES);
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlCopyMemory(Service->ServiceName.Buffer,
ServiceName->Buffer,
ServiceName->Length);
@ -217,8 +219,9 @@ CreateServiceListEntry(PUNICODE_STRING ServiceName)
{
HeapFree(GetProcessHeap(), 0, Service->ServiceName.Buffer);
HeapFree(GetProcessHeap(), 0, Service);
return(STATUS_INSUFFICIENT_RESOURCES);
return STATUS_INSUFFICIENT_RESOURCES;
}
wcscpy(Service->RegistryPath.Buffer,
L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
wcscat(Service->RegistryPath.Buffer,
@ -260,7 +263,7 @@ CreateServiceListEntry(PUNICODE_STRING ServiceName)
RtlFreeUnicodeString(&Service->RegistryPath);
RtlFreeUnicodeString(&Service->ServiceName);
HeapFree(GetProcessHeap(), 0, Service);
return(Status);
return Status;
}
DPRINT("ServiceName: '%wZ'\n", &Service->ServiceName);
@ -273,7 +276,7 @@ CreateServiceListEntry(PUNICODE_STRING ServiceName)
InsertTailList(&ServiceListHead,
&Service->ServiceListEntry);
return(STATUS_SUCCESS);
return STATUS_SUCCESS;
}
@ -311,7 +314,7 @@ ScmCreateServiceDataBase(VOID)
NULL,
NULL);
if (!NT_SUCCESS(Status))
return(Status);
return Status;
RtlRosInitUnicodeStringFromLiteral(&ServicesKeyName,
L"\\Registry\\Machine\\System\\CurrentControlSet\\Services");
@ -327,7 +330,7 @@ ScmCreateServiceDataBase(VOID)
&ObjectAttributes,
0);
if (!NT_SUCCESS(Status))
return(Status);
return Status;
/* Allocate key info buffer */
KeyInfoLength = sizeof(KEY_BASIC_INFORMATION) + MAX_PATH * sizeof(WCHAR);
@ -335,7 +338,7 @@ ScmCreateServiceDataBase(VOID)
if (KeyInfo == NULL)
{
NtClose(ServicesKey);
return(STATUS_INSUFFICIENT_RESOURCES);
return STATUS_INSUFFICIENT_RESOURCES;
}
Index = 0;
@ -379,7 +382,7 @@ ScmCreateServiceDataBase(VOID)
DPRINT("ScmCreateServiceDataBase() done\n");
return(STATUS_SUCCESS);
return STATUS_SUCCESS;
}
@ -421,7 +424,7 @@ ScmCheckDriver(PSERVICE Service)
&ObjectAttributes);
if (!NT_SUCCESS(Status))
{
return(Status);
return Status;
}
BufferLength = sizeof(OBJECT_DIRECTORY_INFORMATION) +
@ -485,7 +488,7 @@ ScmCheckDriver(PSERVICE Service)
DirInfo);
NtClose(DirHandle);
return(STATUS_SUCCESS);
return STATUS_SUCCESS;
}
@ -521,14 +524,12 @@ static NTSTATUS
ScmStartService(PSERVICE Service,
PSERVICE_GROUP Group)
{
#if 0
RTL_QUERY_REGISTRY_TABLE QueryTable[3];
PROCESS_INFORMATION ProcessInformation;
STARTUPINFOW StartupInfo;
UNICODE_STRING ImagePath;
ULONG Type;
BOOL Result;
#endif
NTSTATUS Status;
DPRINT("ScmStartService() called\n");
@ -546,7 +547,6 @@ ScmStartService(PSERVICE Service,
}
else
{
#if 0
RtlInitUnicodeString(&ImagePath, NULL);
/* Get service data */
@ -614,7 +614,7 @@ ScmStartService(PSERVICE Service,
CloseHandle(Service->ControlPipeHandle);
Service->ControlPipeHandle = INVALID_HANDLE_VALUE;
DPRINT("Starting '%S' failed!\n", Service->ServiceName.Buffer);
DPRINT1("Starting '%S' failed!\n", Service->ServiceName.Buffer);
Status = STATUS_UNSUCCESSFUL;
}
else
@ -633,15 +633,35 @@ ScmStartService(PSERVICE Service,
/* Resume Thread */
ResumeThread(ProcessInformation.hThread);
/* FIXME: connect control pipe */
/* Connect control pipe */
if (ConnectNamedPipe(Service->ControlPipeHandle, NULL))
{
DWORD dwProcessId = 0;
DWORD dwRead = 0;
DPRINT("Control pipe connected!\n");
Status = STATUS_SUCCESS;
/* FIXME: Read thread id from pipe */
if (!ReadFile(Service->ControlPipeHandle,
(LPVOID)&dwProcessId,
sizeof(DWORD),
&dwRead,
NULL))
{
DPRINT1("Reading the service control pipe failed (Error %lu)\n", GetLastError());
}
else
{
DPRINT("Received process id %lu\n", dwProcessId);
/* FIXME: Send start command */
Status = STATUS_SUCCESS;
}
}
else
{
DPRINT1("Connecting control pipe failed!\n");
DPRINT("Connecting control pipe failed!\n");
/* Close control pipe */
CloseHandle(Service->ControlPipeHandle);
@ -656,13 +676,11 @@ ScmStartService(PSERVICE Service,
CloseHandle(ProcessInformation.hProcess);
}
}
#endif
Status = STATUS_SUCCESS;
}
#if 0
Done:
#endif
DPRINT("ScmStartService() done (Status %lx)\n", Status);
if (NT_SUCCESS(Status))
{
if (Group != NULL)
@ -674,36 +692,34 @@ Done:
#if 0
else
{
if (CurrentService->ErrorControl == 1)
switch (Service->ErrorControl)
{
/* Log error */
case SERVICE_ERROR_NORMAL:
/* FIXME: Log error */
break;
}
else if (CurrentService->ErrorControl == 2)
{
if (IsLastKnownGood == FALSE)
{
/* Boot last known good configuration */
case SERVICE_ERROR_SEVERE:
if (IsLastKnownGood == FALSE)
{
/* FIXME: Boot last known good configuration */
}
break;
}
}
else if (CurrentService->ErrorControl == 3)
{
if (IsLastKnownGood == FALSE)
{
/* Boot last known good configuration */
}
else
{
/* BSOD! */
}
case SERVICE_ERROR_CRITICAL:
if (IsLastKnownGood == FALSE)
{
/* FIXME: Boot last known good configuration */
}
else
{
/* FIXME: BSOD! */
}
break;
}
}
#endif
return(STATUS_SUCCESS);
return Status;
}