Остановка сервиса.
Сервис можно остановить при помощи функции 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 );
}
}
|