2009-10-20 8 views

Respuesta

3

De nativo de C++, tendrá que:

  1. abierto un identificador para el administrador de control de servicios,
  2. Utilice el administrador de control de servicios para obtener un identificador de servicio para el servicio que desea controlar,
  3. Enviar un código de control o códigos para el servicio, y
  4. Cerrar los identificadores abiertos en los pasos 1 y 2.

Por ejemplo, este código reinicia el servicio de sincronización de tiempo. Primero, creo una clase contenedora para los identificadores de servicio, para cerrarlos automáticamente al salir del bloque.

class CSC_HANDLE 
{ 
public: 
CSC_HANDLE(SC_HANDLE h) : m_h(h) { } 
~CSC_HANDLE() { ::CloseServiceHandle(m_h); } 
operator SC_HANDLE() { return m_h; } 
private: 
SC_HANDLE m_h; 
}; 

Entonces, abro el Administrador de control de servicios (utilizando OpenSCManager()) y el servicio que desea controlar. Tenga en cuenta que el parámetro dwDesiredAccess a OpenService() debe incluir permisos para cada control que deseo enviar, o las funciones de control relevantes fallarán.

BOOL RestartTimeService() 
{ 
    CSC_HANDLE hSCM(::OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, GENERIC_READ)); 
    if (NULL == hSCM) return FALSE; 

    CSC_HANDLE hW32Time(::OpenService(hSCM, L"W32Time", SERVICE_START | SERVICE_STOP | SERVICE_QUERY_STATUS)); 
    if (NULL == hW32Time) return FALSE; 

Para detener el servicio, yo uso ControlService() para enviar el código SERVICE_CONTROL_STOP, y después comprobar el valor de retorno para asegurarse de que el comando tuvo éxito. Si se informa algún error que no sea ERROR_SERVICE_NOT_ACTIVE, supongo que el inicio del servicio no tendrá éxito.

SERVICE_STATUS ss = { 0 }; 
    ::SetLastError(0); 
    BOOL success = ::ControlService(hW32Time, SERVICE_CONTROL_STOP, &ss); 
    if (!success) 
    { 
     DWORD le = ::GetLastError(); 
     switch (le) 
     { 
     case ERROR_ACCESS_DENIED: 
     case ERROR_DEPENDENT_SERVICES_RUNNING: 
     case ERROR_INVALID_HANDLE: 
     case ERROR_INVALID_PARAMETER: 
     case ERROR_INVALID_SERVICE_CONTROL: 
     case ERROR_SERVICE_CANNOT_ACCEPT_CTRL: 
     case ERROR_SERVICE_REQUEST_TIMEOUT: 
     case ERROR_SHUTDOWN_IN_PROGRESS: 
      return FALSE; 

     case ERROR_SERVICE_NOT_ACTIVE: 
     default: 
      break; 
     } 
    } 

Después de instruir el servicio de parar, espero el gerente de servicio para informar que el servicio es, de hecho, se detuvo. Este código tiene dos errores potenciales, que tal vez desee para corregir el código de producción:

  1. del sueño (1000) suspenderá el bucle de mensaje en este hilo, por lo que debe utilizar otro método para retrasar la ejecución si esta función se ejecutará en un hilo de interfaz de usuario. Puede construir un bucle sleep-with-message adecuado utilizando MsgWaitForMultipleObjectsEx().
  2. El DWORD devuelto desde GetTickCount() se ajustará eventualmente a cero; si se enrolla mientras esta función está esperando, la espera puede ceder antes de lo previsto.

    DWORD waitstart(::GetTickCount()); 
    while (true) 
    { 
        ZeroMemory(&ss, sizeof(ss)); 
        ::QueryServiceStatus(hW32Time, &ss); 
        if (SERVICE_STOPPED == ss.dwCurrentState) break; 
        ::Sleep(1000); 
        DWORD tick(::GetTickCount()); 
        if ((tick < waitstart) || (tick > (waitstart + 30000))) return FALSE; 
    } 
    

Por último, sabiendo que el servicio está en un estado detenido, me llaman StartService() ejecutarlo de nuevo.

success = ::StartService(hW32Time, 0, NULL); 
    if (!success) return FALSE; 

    return TRUE; 
} 
Cuestiones relacionadas