2009-10-20 4 views

risposta

3

Da nativo C++, è necessario:

  1. aprire un handle al gestore di controllo del servizio,
  2. Utilizzare il gestore di controllo del servizio per ottenere un handle servizio per il servizio che si desidera controllare,
  3. Invia un codice di controllo o di codici per il servizio, e
  4. Chiudere le maniglie aperte nei passaggi 1 e 2.

Ad esempio, questo codice riavvia il servizio di sincronizzazione dell'ora. Innanzitutto, creo una classe wrapper per gli handle di servizio, per chiuderli automaticamente quando si esce dal blocco.

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

Poi, apro la Gestione controllo servizi (utilizzando OpenSCManager()) e il servizio che voglio controllare. Si noti che il parametro dwDesiredAccess su OpenService() deve includere le autorizzazioni per ciascun controllo che si desidera inviare o le funzioni di controllo pertinenti non riusciranno.

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; 

Per interrompere il servizio, io uso ControlService() per inviare il codice SERVICE_CONTROL_STOP, e quindi controllare il valore di ritorno per assicurarsi che il comando è riuscito. Se viene segnalato un errore diverso da ERROR_SERVICE_NOT_ACTIVE, suppongo che l'avvio del servizio non abbia esito positivo.

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

Dopo istruire il servizio di smettere, io aspetto il responsabile del servizio di segnalare che il servizio è di fatto interrotto. Questo codice ha due potenziali bug, che si potrebbe desiderare di correggere il codice di produzione:

  1. sonno (1000) sospende il ciclo di messaggi su questo thread, così si dovrebbe utilizzare un altro metodo per ritardare l'esecuzione se questa funzione verrà eseguito su un thread dell'interfaccia utente. È possibile costruire un ciclo sleep-with-message appropriato utilizzando MsgWaitForMultipleObjectsEx().
  2. Il DWORD restituito da GetTickCount() si concluderà a zero alla fine; se si avvolge mentre questa funzione è in attesa, l'attesa potrebbe arrendersi prima di quanto 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; 
    } 
    

Infine, sapendo che il servizio è in uno stato di interruzione, io lo chiamo StartService() eseguirlo nuovamente.

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

    return TRUE; 
}