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