Stopping a Service

Stopping a Service

A service can be stopped with the ControlService function by sending a SERVICE_CONTROL_STOP request. If the SCM receives a SERVICE_CONTROL_STOP request for a service, it instructs the service to stop by forwarding the request to the service's ServiceMain function. However, if the SCM determines that other running services are dependent on the specified service, it will not forward the stop request. Instead, it returns ERROR_DEPENDENT_SERVICES_RUNNING. Therefore, to programmatically stop such a service, you must first enumerate and stop its dependent services.

If a service accepts the SERVICE_CONTROL_STOP control code, it must stop upon receipt, going to either the SERVICE_STOP_PENDING or SERVICE_STOPPED state. After the SCM sends this control code, it will not send other control codes.

Windows XP/2000:  If the service returns NO_ERROR and continues to run, it continues to receive control codes. This behavior changed starting with Windows Server 2003 and Windows XP SP2.

The following code implements a StopService function, which optionally attempts to stop the specified service's dependent services.

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

// This function attempts to stop a service. It allows the caller to 
// specify whether dependent services should also be stopped. It also 
// accepts a timeout value, to prevent a scenario in which a service 
// shutdown hangs, then the application stopping the service hangs.
// 
// Parameters:   
//   hSCM - Handle to the service control manager.
//   hService - Handle to the service to be stopped.
//   fStopDependencies - Indicates whether to stop dependent services.
//   dwTimeout - maximum time (in milliseconds) to wait
// 
// If the operation is successful, returns ERROR_SUCCESS. Otherwise, 
// returns a system error code.

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

   // Make sure the service is not already stopped
   if ( !QueryServiceStatusEx( 
             hService, 
             SC_STATUS_PROCESS_INFO,
             &ss, 
             sizeof(STATUS_PROCESS_INFO),
             &dwBytesNeeded ) )
      return GetLastError();

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

   // If a stop is pending, just wait for it
   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 the service is running, dependencies must be stopped first
   if ( fStopDependencies ) 
   {
      DWORD i;
      DWORD dwBytesNeeded;
      DWORD dwCount;

      LPENUM_SERVICE_STATUS   lpDependencies = NULL;
      ENUM_SERVICE_STATUS     ess;
      SC_HANDLE               hDepService;

      // Pass a zero-length buffer to get the required buffer size
      if ( EnumDependentServices( hService, SERVICE_ACTIVE, 
         lpDependencies, 0, &dwBytesNeeded, &dwCount ) ) 
      {
         // If the Enum call succeeds, then there are no dependent
         // services so do nothing
      } 
      else 
      {
         if ( GetLastError() != ERROR_MORE_DATA )
            return GetLastError(); // Unexpected error

         // Allocate a buffer for the dependencies
         lpDependencies = (LPENUM_SERVICE_STATUS) HeapAlloc( 
               GetProcessHeap(), HEAP_ZERO_MEMORY, dwBytesNeeded );

         if ( !lpDependencies )
            return GetLastError();

         __try {
            // Enumerate the dependencies
            if ( !EnumDependentServices( hService, SERVICE_ACTIVE, 
                  lpDependencies, dwBytesNeeded, &dwBytesNeeded,
                  &dwCount ) )
               return GetLastError();

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

               // Open the service
               hDepService = OpenService( hSCM, ess.lpServiceName, 
                     SERVICE_STOP | SERVICE_QUERY_STATUS );
               if ( !hDepService )
                  return GetLastError();

               __try {
                   // Send a stop code
                  if ( !ControlService( hDepService, 
                           SERVICE_CONTROL_STOP,
                           &ss ) )
                     return GetLastError();

                  // Wait for the service to stop
                  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 
               {
                  // Always release the service handle
                  CloseServiceHandle( hDepService );

               }
            }

         } 
         __finally 
         {
            // Always free the enumeration buffer
            HeapFree( GetProcessHeap(), 0, lpDependencies );
         }
      } 
   }

   // Send a stop code to the main service
   if ( !ControlService( hService, SERVICE_CONTROL_STOP, &ss ) )
      return GetLastError();

   // Wait for the service to stop
   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 success
   return ERROR_SUCCESS;
}

// Helper function to display an error message 

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 );
}

// Entry point for the program. This function contains sample code 
// demonstrating how to use the StopService function implemented 
// above.
// 
// Parameters:   
//   argc - the number of command-line arguments
//   argv[] - an array of command-line arguments

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 
   {
      // Open the SCM database
      hSCM = OpenSCManager( NULL, NULL, SC_MANAGER_CONNECT );
      if ( !hSCM ) 
      {
         DisplayError( TEXT("OpenSCManager()"), GetLastError() );
         __leave;
      }

      // Open the specified service
      hService = OpenService( hSCM, argv[1], SERVICE_STOP
            | SERVICE_QUERY_STATUS | SERVICE_ENUMERATE_DEPENDENTS );
      if ( !hService ) 
      {
         DisplayError( TEXT("OpenService()"), GetLastError() );
         __leave;
      }

      // Try to stop the service, specifying a 30 second timeout
      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 );
   }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值