From 69a020df2604c418121b8962cb6e97ea42d1de75 Mon Sep 17 00:00:00 2001 From: Eric Kohl Date: Fri, 19 Feb 2010 20:03:11 +0000 Subject: [PATCH] [SERVICES] Set default status to SERVICE_START_PENDING when starting a service. [SYSSETUP] Wait until PlugPlay service is up. Bug #4142. [UMPNPMGR] Update the service control manager's status information. Patches by Dmitry Gorbachev. svn path=/trunk/; revision=45626 --- reactos/base/services/umpnpmgr/umpnpmgr.c | 188 +++++++++++++++------- reactos/base/system/services/database.c | 2 +- reactos/dll/win32/syssetup/install.c | 84 +++++++++- 3 files changed, 209 insertions(+), 65 deletions(-) diff --git a/reactos/base/services/umpnpmgr/umpnpmgr.c b/reactos/base/services/umpnpmgr/umpnpmgr.c index 8dc8a16e031..75080d583df 100644 --- a/reactos/base/services/umpnpmgr/umpnpmgr.c +++ b/reactos/base/services/umpnpmgr/umpnpmgr.c @@ -51,12 +51,11 @@ /* GLOBALS ******************************************************************/ -static VOID CALLBACK -ServiceMain(DWORD argc, LPTSTR *argv); - -static SERVICE_TABLE_ENTRY ServiceTable[2] = +static VOID CALLBACK ServiceMain(DWORD, LPWSTR *); +static WCHAR ServiceName[] = L"PlugPlay"; +static SERVICE_TABLE_ENTRYW ServiceTable[] = { - {TEXT("PlugPlay"), ServiceMain}, + {ServiceName, ServiceMain}, {NULL, NULL} }; @@ -2446,63 +2445,36 @@ PnpEventThread(LPVOID lpParameter) } -static VOID CALLBACK -ServiceMain(DWORD argc, LPTSTR *argv) +static DWORD WINAPI +ServiceControlHandler(DWORD dwControl, + DWORD dwEventType, + LPVOID lpEventData, + LPVOID lpContext) { - HANDLE hThread; - DWORD dwThreadId; - - UNREFERENCED_PARAMETER(argc); - UNREFERENCED_PARAMETER(argv); - - DPRINT("ServiceMain() called\n"); - - hThread = CreateThread(NULL, - 0, - PnpEventThread, - NULL, - 0, - &dwThreadId); - if (hThread != NULL) - CloseHandle(hThread); - - hThread = CreateThread(NULL, - 0, - RpcServerThread, - NULL, - 0, - &dwThreadId); - if (hThread != NULL) - CloseHandle(hThread); - - hThread = CreateThread(NULL, - 0, - DeviceInstallThread, - NULL, - 0, - &dwThreadId); - if (hThread != NULL) - CloseHandle(hThread); - - DPRINT("ServiceMain() done\n"); + /* FIXME */ + DPRINT1("ServiceControlHandler() called (control code %lu)\n", dwControl); + return ERROR_SUCCESS; } -int -wmain(int argc, WCHAR *argv[]) +static DWORD +ServiceInit(VOID) { - BOOLEAN OldValue; + HANDLE hThread; + DWORD dwThreadId; DWORD dwError; - - UNREFERENCED_PARAMETER(argc); - UNREFERENCED_PARAMETER(argv); - - DPRINT("Umpnpmgr: main() started\n"); + BOOLEAN OldValue; /* We need this privilege for using CreateProcessAsUserW */ - RtlAdjustPrivilege(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE, TRUE, FALSE, &OldValue); + RtlAdjustPrivilege(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE, + TRUE, + FALSE, + &OldValue); - hInstallEvent = CreateEvent(NULL, TRUE, SetupIsActive()/*FALSE*/, NULL); + hInstallEvent = CreateEvent(NULL, + TRUE, + SetupIsActive()/*FALSE*/, + NULL); if (hInstallEvent == NULL) { dwError = GetLastError(); @@ -2510,7 +2482,10 @@ wmain(int argc, WCHAR *argv[]) return dwError; } - hDeviceInstallListNotEmpty = CreateEvent(NULL, FALSE, FALSE, NULL); + hDeviceInstallListNotEmpty = CreateEvent(NULL, + FALSE, + FALSE, + NULL); if (hDeviceInstallListNotEmpty == NULL) { dwError = GetLastError(); @@ -2557,11 +2532,110 @@ wmain(int argc, WCHAR *argv[]) return dwError; } - StartServiceCtrlDispatcher(ServiceTable); + hThread = CreateThread(NULL, + 0, + PnpEventThread, + NULL, + 0, + &dwThreadId); + if (hThread == NULL) + { + return GetLastError(); + } + CloseHandle(hThread); - DPRINT("Umpnpmgr: main() done\n"); + hThread = CreateThread(NULL, + 0, + RpcServerThread, + NULL, + 0, + &dwThreadId); + if (hThread == NULL) + { + return GetLastError(); + } + CloseHandle(hThread); - ExitThread(0); + hThread = CreateThread(NULL, + 0, + DeviceInstallThread, + NULL, + 0, + &dwThreadId); + if (hThread == NULL) + { + return GetLastError(); + } + CloseHandle(hThread); + + return ERROR_SUCCESS; +} + + +static VOID CALLBACK +ServiceMain(DWORD argc, + LPWSTR *argv) +{ + SERVICE_STATUS ServiceStatus; + SERVICE_STATUS_HANDLE ServiceStatusHandle; + DWORD dwError; + + UNREFERENCED_PARAMETER(argc); + UNREFERENCED_PARAMETER(argv); + + DPRINT("ServiceMain() called\n"); + + ServiceStatusHandle = RegisterServiceCtrlHandlerExW(ServiceName, + ServiceControlHandler, + NULL); + if (!ServiceStatusHandle) + { + dwError = GetLastError(); + DPRINT1("RegisterServiceCtrlHandlerW() failed! (Error %lu)\n", dwError); + return; + } + + ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; + ServiceStatus.dwCurrentState = SERVICE_START_PENDING; + ServiceStatus.dwControlsAccepted = 0; + ServiceStatus.dwWin32ExitCode = NO_ERROR; + ServiceStatus.dwServiceSpecificExitCode = 0; + ServiceStatus.dwCheckPoint = 0; + ServiceStatus.dwWaitHint = 2000; + + SetServiceStatus(ServiceStatusHandle, + &ServiceStatus); + + dwError = ServiceInit(); + if (dwError != ERROR_SUCCESS) + { + DPRINT1("Service stopped\n"); + ServiceStatus.dwCurrentState = SERVICE_STOPPED; + } + else + { + ServiceStatus.dwCurrentState = SERVICE_RUNNING; + } + + SetServiceStatus(ServiceStatusHandle, + &ServiceStatus); + + DPRINT("ServiceMain() done\n"); +} + + +int +wmain(int argc, + WCHAR *argv[]) +{ + UNREFERENCED_PARAMETER(argc); + UNREFERENCED_PARAMETER(argv); + + DPRINT1("Umpnpmgr: main() started\n"); + + StartServiceCtrlDispatcherW(ServiceTable); + + DPRINT1("Umpnpmgr: main() done\n"); return 0; } diff --git a/reactos/base/system/services/database.c b/reactos/base/system/services/database.c index d33b23403b5..93a99e52ee7 100644 --- a/reactos/base/system/services/database.c +++ b/reactos/base/system/services/database.c @@ -1054,7 +1054,7 @@ ScmStartService(PSERVICE Service, DWORD argc, LPWSTR *argv) { Group->ServicesRunning = TRUE; } - Service->Status.dwCurrentState = SERVICE_RUNNING; + Service->Status.dwCurrentState = SERVICE_START_PENDING; } #if 0 else diff --git a/reactos/dll/win32/syssetup/install.c b/reactos/dll/win32/syssetup/install.c index a853e8d2c7e..b3bd427cddd 100644 --- a/reactos/dll/win32/syssetup/install.c +++ b/reactos/dll/win32/syssetup/install.c @@ -20,7 +20,7 @@ * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS system libraries * PURPOSE: System setup - * FILE: lib/syssetup/install.c + * FILE: dll/win32/syssetup/install.c * PROGRAMER: Eric Kohl */ @@ -473,30 +473,100 @@ InstallSysSetupInfComponents(VOID) static BOOL EnableUserModePnpManager(VOID) { + SERVICE_STATUS_PROCESS ServiceStatus; SC_HANDLE hSCManager = NULL; SC_HANDLE hService = NULL; + DWORD dwStartTickCount; + DWORD dwOldCheckPoint; + DWORD BytesNeeded = 0; + DWORD dwWaitTime; + DWORD dwMaxWait; BOOL ret = FALSE; hSCManager = OpenSCManager(NULL, NULL, 0); if (hSCManager == NULL) goto cleanup; - hService = OpenServiceW(hSCManager, L"PlugPlay", SERVICE_CHANGE_CONFIG | SERVICE_START); + hService = OpenServiceW(hSCManager, + L"PlugPlay", + SERVICE_CHANGE_CONFIG | SERVICE_START | SERVICE_QUERY_STATUS); if (hService == NULL) goto cleanup; - ret = ChangeServiceConfigW( - hService, - SERVICE_NO_CHANGE, SERVICE_AUTO_START, SERVICE_NO_CHANGE, - NULL, NULL, NULL, NULL, NULL, NULL, NULL); + ret = ChangeServiceConfigW(hService, + SERVICE_NO_CHANGE, + SERVICE_AUTO_START, + SERVICE_NO_CHANGE, + NULL, NULL, NULL, + NULL, NULL, NULL, NULL); if (!ret) goto cleanup; ret = StartServiceW(hService, 0, NULL); + if (!ret) + { + /* If the service is already running, just return TRUE */ + ret = GetLastError() == ERROR_SERVICE_ALREADY_RUNNING; + goto cleanup; + } + + ret = QueryServiceStatusEx(hService, + SC_STATUS_PROCESS_INFO, + (LPBYTE)&ServiceStatus, + sizeof(SERVICE_STATUS_PROCESS), + &BytesNeeded); if (!ret) goto cleanup; - ret = TRUE; + /* We don't want to wait for more than 30 seconds */ + dwMaxWait = 30000; + dwStartTickCount = GetTickCount(); + + /* Loop until it's running */ + while (ServiceStatus.dwCurrentState != SERVICE_RUNNING) + { + dwOldCheckPoint = ServiceStatus.dwCheckPoint; + dwWaitTime = ServiceStatus.dwWaitHint / 10; + + /* Get the latest status info */ + if (!QueryServiceStatusEx(hService, + SC_STATUS_PROCESS_INFO, + (LPBYTE)&ServiceStatus, + sizeof(SERVICE_STATUS_PROCESS), + &BytesNeeded)) + { + /* Something went wrong... */ + break; + } + + /* Is the service making progress? */ + if (ServiceStatus.dwCheckPoint > dwOldCheckPoint) + { + /* It is, get the latest tickcount to reset the max wait time */ + dwStartTickCount = GetTickCount(); + dwOldCheckPoint = ServiceStatus.dwCheckPoint; + } + else + { + /* It's not, make sure we haven't exceeded our wait time */ + if (GetTickCount() >= dwStartTickCount + dwMaxWait) + { + /* We have, give up */ + break; + } + } + + /* Adjust the wait hint times */ + if (dwWaitTime < 200) + dwWaitTime = 200; + else if (dwWaitTime > 10000) + dwWaitTime = 10000; + + /* Wait before trying again */ + Sleep(dwWaitTime); + } + + ret = ServiceStatus.dwCurrentState == SERVICE_RUNNING; cleanup: if (hSCManager != NULL)