reactos/base/applications/mscutils/servman/start.c
Kyle Katarn b3947d5283
[SERVMAN] UI update and Error Management (#2653)
Purpose
=======
- Current design does not warn user nor logs DEBUG traces when Service Start/Stop command fails or reach timeout.
- Current Service Start/Stop progress window are WS_EX_TOOLWINDOW which reduce lisibility, is a ReactOS specificity without good reason.

Proposed changes
================
- DPRINT1 traces added on failure cases.
- Error Message box presented to user upon failure with explicit root cause identification.
- Change Dialog definition to standard window.
2020-05-01 19:01:59 +02:00

220 lines
6.3 KiB
C

/*
* PROJECT: ReactOS Services
* LICENSE: GPL - See COPYING in the top level directory
* FILE: base/applications/mscutils/servman/start.c
* PURPOSE: Start a service
* COPYRIGHT: Copyright 2005-2015 Ged Murphy <gedmurphy@reactos.org>
*
*/
#include "precomp.h"
#define NDEBUG
#include <debug.h>
#define MAX_WAIT_TIME 30000
DWORD
DoStartService(LPWSTR ServiceName,
HANDLE hProgress,
LPWSTR lpStartParams)
{
SC_HANDLE hSCManager;
SC_HANDLE hService;
SERVICE_STATUS_PROCESS ServiceStatus;
DWORD BytesNeeded = 0;
DWORD StartTickCount;
DWORD OldCheckPoint;
DWORD WaitTime;
DWORD MaxWait;
BOOL Result = FALSE;
BOOL bWhiteSpace = TRUE;
LPWSTR lpChar;
DWORD dwArgsCount = 0;
DWORD dwResult = ERROR_SUCCESS;
LPCWSTR *lpArgsVector = NULL;
if (lpStartParams != NULL)
{
/* Count the number of arguments */
lpChar = lpStartParams;
while (*lpChar != 0)
{
if (iswspace(*lpChar))
{
bWhiteSpace = TRUE;
}
else
{
if (bWhiteSpace != FALSE)
{
dwArgsCount++;
bWhiteSpace = FALSE;
}
}
lpChar++;
}
/*
* Allocate the arguments vector.
* Do not add the service name here because services.exe does it for us!
*/
lpArgsVector = LocalAlloc(LMEM_FIXED, dwArgsCount * sizeof(LPCWSTR));
if (!lpArgsVector)
return GetLastError();
/* Fill the arguments vector */
dwArgsCount = 0;
bWhiteSpace = TRUE;
lpChar = lpStartParams;
while (*lpChar != 0)
{
if (iswspace(*lpChar))
{
*lpChar = 0;
bWhiteSpace = TRUE;
}
else
{
if (bWhiteSpace != FALSE)
{
lpArgsVector[dwArgsCount] = lpChar;
dwArgsCount++;
bWhiteSpace = FALSE;
}
}
lpChar++;
}
}
hSCManager = OpenSCManagerW(NULL,
NULL,
SC_MANAGER_CONNECT);
if (!hSCManager)
{
dwResult = GetLastError();
if (lpArgsVector)
LocalFree((LPVOID)lpArgsVector);
return dwResult;
}
hService = OpenServiceW(hSCManager,
ServiceName,
SERVICE_START | SERVICE_QUERY_STATUS);
if (!hService)
{
dwResult = GetLastError();
CloseServiceHandle(hSCManager);
if (lpArgsVector)
LocalFree((LPVOID)lpArgsVector);
return dwResult;
}
/* Start the service */
Result = StartServiceW(hService,
dwArgsCount,
lpArgsVector);
if (!Result && GetLastError() == ERROR_SERVICE_ALREADY_RUNNING)
{
/* If it's already running, just return TRUE */
Result = TRUE;
}
else if (Result)
{
if (hProgress)
{
/* Increment the progress bar */
IncrementProgressBar(hProgress, DEFAULT_STEP);
}
/* Get the service status to check if it's running */
Result = QueryServiceStatusEx(hService,
SC_STATUS_PROCESS_INFO,
(LPBYTE)&ServiceStatus,
sizeof(SERVICE_STATUS_PROCESS),
&BytesNeeded);
if (Result)
{
Result = FALSE;
MaxWait = MAX_WAIT_TIME;
OldCheckPoint = ServiceStatus.dwCheckPoint;
StartTickCount = GetTickCount();
/* Loop until it's running */
while (ServiceStatus.dwCurrentState != SERVICE_RUNNING)
{
int i;
/* Fixup the wait time */
WaitTime = ServiceStatus.dwWaitHint / 10;
if (WaitTime < 1000) WaitTime = 1000;
else if (WaitTime > 10000) WaitTime = 10000;
/* We don't wanna wait for up to 10 secs without incrementing */
for (i = WaitTime / 1000; i > 0; i--)
{
Sleep(1000);
if (hProgress)
{
/* Increment the progress bar */
IncrementProgressBar(hProgress, DEFAULT_STEP);
}
}
/* Get the latest status info */
if (!QueryServiceStatusEx(hService,
SC_STATUS_PROCESS_INFO,
(LPBYTE)&ServiceStatus,
sizeof(SERVICE_STATUS_PROCESS),
&BytesNeeded))
{
/* Something went wrong... */
dwResult = GetLastError();
DPRINT1("QueryServiceStatusEx failed: %d\n", dwResult);
break;
}
/* Is the service making progress? */
if (ServiceStatus.dwCheckPoint > OldCheckPoint)
{
/* It is, get the latest tickcount to reset the max wait time */
StartTickCount = GetTickCount();
OldCheckPoint = ServiceStatus.dwCheckPoint;
}
else
{
/* It's not, make sure we haven't exceeded our wait time */
if (GetTickCount() >= StartTickCount + MaxWait)
{
/* We have, give up */
DPRINT1("Timeout\n");
dwResult = ERROR_SERVICE_REQUEST_TIMEOUT;
break;
}
}
}
}
else
{
dwResult = GetLastError();
}
if (ServiceStatus.dwCurrentState == SERVICE_RUNNING)
{
dwResult = ERROR_SUCCESS;
}
}
CloseServiceHandle(hService);
CloseServiceHandle(hSCManager);
if (lpArgsVector)
LocalFree((LPVOID)lpArgsVector);
return dwResult;
}