2009-10-20 13 views

Antwort

3

Von native C++, müssen Sie:

  1. Öffnen Sie einen Griff an den Dienststeuerungs-Manager,
  2. den Dienststeuerungs-Manager verwenden, einen Dienst Handle für den Dienst, den Sie steuern möchten
  3. zu erhalten
  4. einen Steuercode oder Codes an den Dienst senden, und
  5. Schließen der Griffe geöffnet in den Schritten 1 und 2.

Beispielsweise startet dieser Code den Zeitsynchronisierungsdienst neu. Zuerst erstelle ich eine Wrapper-Klasse für die Service-Handles, um sie beim Verlassen des Blocks automatisch zu schließen.

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

Dann öffne ich die Dienststeuerungs-Manager (mit OpenSCManager()) und den Service, den ich steuern möchten. Beachten Sie, dass der DwDesiredAccess-Parameter zu OpenService() Berechtigungen für jedes Steuerelement enthalten muss, das ich senden möchte, oder die relevanten Steuerfunktionen werden fehlschlagen.

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; 

den Dienst zu beenden, ich ControlService() verwenden, um den SERVICE_CONTROL_STOP Code zu senden, und dann den Rückgabewert überprüfen, um der Befehl erfolgreich war sicher. Wenn ein anderer Fehler als ERROR_SERVICE_NOT_ACTIVE gemeldet wird, gehe ich davon aus, dass der Start des Dienstes nicht erfolgreich ist.

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

Nachdem ich den Dienst angewiesen habe, anzuhalten, warte ich, bis der Dienstmanager meldet, dass der Dienst tatsächlich gestoppt wurde. Dieser Code hat zwei mögliche Fehler, die Sie wünschen können für die Produktion Code zu beheben:

  1. Sleep (1000) wird unterbrechen die Nachrichtenschleife auf diesen Thread, so dass Sie eine andere Methode verwenden sollte die Ausführung zu verzögern, wenn diese Funktion ausgeführt werden soll auf einem UI-Thread. Mit MsgWaitForMultipleObjectsEx() können Sie eine passende Sleep-with-message-Schleife erstellen.
  2. Das von GetTickCount() zurückgegebene DWORD wird schließlich auf Null umbrechen; Wenn es sich während der Wartezeit dieser Funktion umwickelt, kann die Wartezeit früher als geplant abbrechen.

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

Schließlich wissen, dass der Dienst in einem gestoppten Zustand ist, nenne ich StartService() laufen sie wieder.

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

    return TRUE; 
}