Comment puis-je envoyer une commande à un service Windows à partir de C++? code .NET est équivalent:Envoyer la commande au service à partir de C++
ServiceController sc = new ServiceController("MyService");
sc.ExecuteCommand(255);
Comment puis-je envoyer une commande à un service Windows à partir de C++? code .NET est équivalent:Envoyer la commande au service à partir de C++
ServiceController sc = new ServiceController("MyService");
sc.ExecuteCommand(255);
De C++ natif, vous devez:
Par exemple, ce code redémarre le service de synchronisation horaire. Tout d'abord, je crée une classe wrapper pour les handles de service, pour les fermer automatiquement en quittant le bloc.
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;
};
Ensuite, j'ouvre le gestionnaire de contrôle de service (en utilisant OpenSCManager()) et le service que je veux contrôler. Notez que le paramètre dwDesiredAccess à OpenService() doit inclure des autorisations pour chaque contrôle que je veux envoyer ou les fonctions de contrôle pertinentes échoueront.
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;
Pour arrêter le service, j'utilise ControlService() pour envoyer le code SERVICE_CONTROL_STOP, puis vérifier la valeur de retour pour vous assurer que la commande a réussi. Si une erreur autre que ERROR_SERVICE_NOT_ACTIVE est signalée, je suppose que le démarrage du service n'aboutira pas.
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;
}
}
Après avoir demandé au service d'arrêter, j'attends le gestionnaire de services pour signaler que le service est en fait arrêté. Ce code a deux bugs potentiels, que vous voudrez peut-être corriger le code de production:
Le DWORD retourné à partir de GetTickCount() finira à zéro par la suite; Si elle est enroulée pendant que cette fonction est en attente, l'attente peut être abandonnée plus tôt que prévu.
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;
}
Enfin, sachant que le service est dans un état arrêté, je l'appelle StartService() exécuter à nouveau.
success = ::StartService(hW32Time, 0, NULL);
if (!success) return FALSE;
return TRUE;
}
Vous utilisez ControlService, voir Service Control Requests.