come posso inviare il comando a un servizio Windows da C++? codice equivalente NET è:Invia il comando al servizio da C++
ServiceController sc = new ServiceController("MyService");
sc.ExecuteCommand(255);
come posso inviare il comando a un servizio Windows da C++? codice equivalente NET è:Invia il comando al servizio da C++
ServiceController sc = new ServiceController("MyService");
sc.ExecuteCommand(255);
Da nativo C++, è necessario:
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:
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;
}
Si utilizza ControlService, vedere Service Control Requests.