Остановка службы


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

Следующий код реализует функцию StopService, которая по выбору пытается остановить зависимые службы от указанной службы.

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

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

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

   // Удостоверьтесь, что служба еще не остановлена.
   if ( !QueryServiceStatusEx( 
             hService, 
             SC_STATUS_PROCESS_INFO,
             &ss, 
             sizeof(STATUS_PROCESS_INFO),
             &dwBytesNeeded ) )
      return GetLastError();

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

   // Если останов является задержанным, безусловно ждать
   while ( ss.dwCurrentState == SERVICE_STOP_PENDING ) 
   {
      Sleep( ss.dwWaitHint );
   if ( !QueryServiceStatusEx( 
             hService, 
             SC_STATUS_PROCESS_INFO,
             &ss, 
             sizeof(STATUS_PROCESS_INFO),
             &dwBytesNeeded ) )
         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 ) ) 
      {
         // Если вызов Enum завершает успешно, то нет зависимых
         // служб, которые ничего не делают
      } 
      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 ( !QueryServiceStatusEx( 
                              hDepService, 
                              SC_STATUS_PROCESS_INFO,
                              &ss, 
                              sizeof(STATUS_PROCESS_INFO),
                              &dwBytesNeeded ) )
                        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 ( !QueryServiceStatusEx( 
               hService, 
               SC_STATUS_PROCESS_INFO,
               &ss, 
               sizeof(STATUS_PROCESS_INFO),
               &dwBytesNeeded ) )
         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 );
   }
}

Назад в оглавление
На главную страницу

Hosted by uCoz