Остановка сервиса

Сервис можно остановить при помощи функции ControlService отправив запрос SERVICE_CONTROL_STOP. Если SCM получает запрос SERVICE_CONTROL_STOP для сервиса, он начинает процедуру остановки сервиса, перенаправив запрос в функцию сервиса ServiceMain. Однако, если SCM определит, что другой запущенный сервис зависит от указанного, то он не будет перенаправлять запрос на остановку сервиса, а вместо этого вернёт ERROR_DEPENDENT_SERVICES_RUNNING. Поэтому, чтобы программно остановить сервис, надо сперва узнать все зависимые сервисы и предварительно остановить их.

 

#include <windows.h>
#include <tchar.h>
#include <stdio.h>

// Основная задача функции - остановить сервис. Так же она попытается
// остановить зависимые сервисы. Функция позволяет задавать величину
// таймаута.
//
// Параметры:
// hSCM - Дескриптор менеджера управления сервисами (SCM).
// hService - Дескриптор останавливаемого сервиса.
// fStopDependencies - Останавливать или нет зависимые сервисы.
// dwTimeout - максимальное время (в миллисекундах) ожидания
//
// В случае успеха, функция возвращает ERROR_SUCCESS. Иначе,
// возвращается код системной ошибки.

DWORD StopService( SC_HANDLE hSCM, SC_HANDLE hService,
BOOL fStopDependencies, DWORD dwTimeout )
{
SERVICE_STATUS ss;
DWORD dwStartTime = GetTickCount();

// Убеждаемся, что сервис уже не остановлен
if ( !QueryServiceStatus( hService, &ss ) )
return GetLastError();

if ( ss.dwCurrentState == SERVICE_STOPPED )
return ERROR_SUCCESS;

// Если скрвис находится в процессе остановки, то подождём
while ( ss.dwCurrentState == SERVICE_STOP_PENDING )
{
Sleep( ss.dwWaitHint );
if ( !QueryServiceStatus( hService, &ss ) )
return GetLastError();

if ( ss.dwCurrentState == SERVICE_STOPPED )
return ERROR_SUCCESS;

if ( GetTickCount() - dwStartTime > dwTimeout )
return ERROR_TIMEOUT;
}

// Если сервис запущен, то сперва необходимо остановить зависимые сервисы
if ( fStopDependencies )
{
DWORD i;
DWORD dwBytesNeeded;
DWORD dwCount;

LPENUM_SERVICE_STATUS lpDependencies = NULL;
ENUM_SERVICE_STATUS ess;
SC_HANDLE hDepService;

// Передаём буфер нулевого размера, чтобы узнать требуемый размер
if ( EnumDependentServices( hService, SERVICE_ACTIVE,
lpDependencies, 0, &dwBytesNeeded, &dwCount ) )
{
// Нет зависимых сервисов
}
else
{
if ( GetLastError() != ERROR_MORE_DATA )
return GetLastError(); // Неустранимая ошибка

// Выделяем буфер для зависимых сервисов
lpDependencies = (LPENUM_SERVICE_STATUS) HeapAlloc(
GetProcessHeap(), HEAP_ZERO_MEMORY, dwBytesNeeded );

if ( !lpDependencies )
return GetLastError();

__try {
// Начинаем перечислять зависимые сервисы
if ( !EnumDependentServices( hService, SERVICE_ACTIVE,
lpDependencies, dwBytesNeeded, &dwBytesNeeded,
&dwCount ) )
return GetLastError();

for ( i = 0; i < dwCount; i++ )
{
ess = *(lpDependencies + i);

// Открываем сервис
hDepService = OpenService( hSCM, ess.lpServiceName,
SERVICE_STOP | SERVICE_QUERY_STATUS );
if ( !hDepService )
return GetLastError();

__try {
// Посылаем код остановки
if ( !ControlService( hDepService,
SERVICE_CONTROL_STOP,
&ss ) )
return GetLastError();

// Ждём, пока сервис остановится
while ( ss.dwCurrentState != SERVICE_STOPPED )
{
Sleep( ss.dwWaitHint );
if ( !QueryServiceStatus( hDepService, &ss ) )
return GetLastError();

if ( ss.dwCurrentState == SERVICE_STOPPED )
break;

if ( GetTickCount() - dwStartTime > dwTimeout )
return ERROR_TIMEOUT;
}

}
__finally
{
// Всегда освобождаем дескриптор сервиса
CloseServiceHandle( hDepService );

}
}

}
__finally
{
// Так же всегда освобождаем буфер
HeapFree( GetProcessHeap(), 0, lpDependencies );
}
}
}

// Посылаем код остановки главному сервису
if ( !ControlService( hService, SERVICE_CONTROL_STOP, &ss ) )
return GetLastError();

// Ждём, пока сервис остановится
while ( ss.dwCurrentState != SERVICE_STOPPED )
{
Sleep( ss.dwWaitHint );
if ( !QueryServiceStatus( hService, &ss ) )
return GetLastError();

if ( ss.dwCurrentState == SERVICE_STOPPED )
break;

if ( GetTickCount() - dwStartTime > dwTimeout )
return ERROR_TIMEOUT;
}

// Возвращаем успешный результат
return ERROR_SUCCESS;
}

// Вспомогательная функция для отображения сообщений об ошибках

void DisplayError( LPTSTR szAPI, DWORD dwError )
{
LPTSTR lpBuffer = NULL;

FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpBuffer, 0, NULL );

_tprintf( TEXT("%s failed:\n"), szAPI );
_tprintf( TEXT(" error code = %u\n"), dwError );
_tprintf( TEXT(" message = %s\n"), lpBuffer );

LocalFree( lpBuffer );
}

// Основная функция программы, которая использует функцию StopService,
// приведённую выше.
//
// Параметры:
// argc - количество аргументов в командной строке
// argv[] - массив аргументов командной строки

void _tmain( int argc, TCHAR *argv[] )
{
SC_HANDLE hSCM;
SC_HANDLE hService;
DWORD dwError;

if ( argc < 2 )
{
_tprintf( TEXT("usage: \"%s\" <ServiceName>\n"), argv[0] );
return;
}

__try
{
// Открываем базу SCM
hSCM = OpenSCManager( NULL, NULL, SC_MANAGER_CONNECT );
if ( !hSCM )
{
DisplayError( TEXT("OpenSCManager()"), GetLastError() );
__leave;
}

// Открываем указанный сервис
hService = OpenService( hSCM, argv[1], SERVICE_STOP
| SERVICE_QUERY_STATUS | SERVICE_ENUMERATE_DEPENDENTS );
if ( !hService )
{
DisplayError( TEXT("OpenService()"), GetLastError() );
__leave;
}

// Пытаемся остановить сервис в течение 30 секунд
dwError = StopService( hSCM, hService, TRUE, 30000 ) ;
if ( dwError == ERROR_SUCCESS )
_tprintf( TEXT("Service stopped.\n") );
else
DisplayError( TEXT("StopService()"), dwError );

}
__finally
{
if ( hService )
CloseServiceHandle( hService );

if ( hSCM )
CloseServiceHandle( hSCM );
}
 
« Предыдущая статья   Следующая статья »