2009-10-20 12 views

Odpowiedz

3

Od macierzystym C++, trzeba będzie:

  1. Otwórz uchwyt do kierownika kontroli usług,
  2. Użyj Menedżera sterowania usługami, aby uzyskać uchwyt serwisową chcesz sterować,
  3. Wyślij kod sterujący lub kody do usługi, a
  4. zamknąć uchwyty otwarty w krokach 1 i 2.

Na przykład ten kod restartuje usługę synchronizacji czasu. Najpierw tworzę klasę opakowania dla uchwytów usług, aby zamknąć je automatycznie po opuszczeniu bloku.

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

Potem otwórz Menedżera sterowania usługami (używając OpenSCManager()), a obsługa chcę kontrolować. Zauważ, że parametr dwDesiredAccess do OpenService() musi zawierać uprawnienia dla każdej kontrolki, którą chcę wysłać, lub odpowiednie funkcje kontrolne zawiedzie.

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; 

Aby zatrzymać usługę, używam ControlService() wysłać kod SERVICE_CONTROL_STOP, a następnie sprawdzić wartość zwracaną, aby upewnić się, zakończyła się sukcesem. Jeśli zgłoszony zostanie błąd inny niż ERROR_SERVICE_NOT_ACTIVE, zakładam, że uruchomienie usługi nie powiedzie się.

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

Po poleceniu usługi zatrzymania oczekuję, aż menedżer serwisowy zgłosi, że usługa została faktycznie zatrzymana. Kod ten ma dwa potencjalne błędy, które mogą chcesz skorygować kodem produkcji:

  1. snu (1000) będzie zawiesić pętlę wiadomość na tym wątku, więc trzeba zastosować inną metodę, aby opóźnić wykonanie jeśli funkcja ta będzie działać w wątku interfejsu użytkownika. Możesz skonstruować odpowiednią pętlę spania z wiadomością, używając MsgWaitForMultipleObjectsEx().
  2. DWORD zwrócony z GetTickCount() zawinie w końcu do zera; jeśli zawija się, gdy ta funkcja czeka, oczekiwanie może ulec szybszemu wcześniej niż zamierzałem.

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

końcu, wiedząc, że usługa jest w stanie zatrzymania, wzywam StartService() uruchomić go ponownie.

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

    return TRUE; 
}