2009-10-20 188 views

回答

3

從本地C++,你將需要:

  1. 打開的句柄服務控制管理器,
  2. 使用服務控制管理器來獲得某項服務句柄要控制服務,
  3. 發送的控制碼或代碼,以該服務,
  4. 關閉手柄中的步驟1中打開和2

例如,此代碼重新啓動時間同步服務。首先,我爲服務句柄創建一個包裝類,在離開塊時自動關閉它們。

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

於是,我打開服務控制管理器(使用OpenSCManager()),我想控制服務。請注意,OpenService()的dwDesiredAccess參數必須包含我要發送的每個控件的權限,否則相關控制功能將失敗。

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; 

要停止該服務,我用ControlService()發送SERVICE_CONTROL_STOP代碼,然後檢查返回值,以確保該命令成功。如果報告ERROR_SERVICE_NOT_ACTIVE以外的任何錯誤,我認爲啓動服務不會成功。

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

指示服務停止後,我等待服務管理器報告服務實際上已停止。這段代碼有兩個潛在的bug,你不妨以糾正產品代碼:

  1. 睡眠(1000)將暫停在此線程的消息循環,所以你應該使用另外一種方法來延遲執行的,如果這個功能將運行在UI線程上。你可以使用MsgWaitForMultipleObjectsEx()構建一個合適的睡眠消息循環。
  2. GetTickCount()返回的DWORD最終將回到零;如果它在這個函數等待的時候迴繞,等待可能會比我預期的更早放棄。

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

最後,知道服務處於停止狀態,我稱之爲StartService()再次運行。

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

    return TRUE; 
}