15 мая 2023 года "Исходники.РУ" отмечают своё 23-летие!
Поздравляем всех причастных и неравнодушных с этим событием!
И огромное спасибо всем, кто был и остаётся с нами все эти годы!

Главная Форум Журнал Wiki DRKB Discuz!ML Помощь проекту


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

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