Pregunta

¿Cómo puedo enviar comandos a un servicio de Windows de C ++? NET equivalente es:

ServiceController sc = new ServiceController("MyService");
sc.ExecuteCommand(255);
¿Fue útil?

Solución

A partir de C ++ nativo, tendrá que:

  1. Abrir un identificador para el administrador de control de servicios,
  2. Utilice el gestor de control de servicios para obtener un identificador de servicio para el servicio que desea controlar,
  3. enviar un código de control o códigos para el servicio, y
  4. cerrar los identificadores abiertos en los pasos 1 y 2.

Por ejemplo, este código se reinicia el servicio de sincronización de tiempo. En primer lugar, crear una clase contenedora para las manijas de servicios, para cerrar automáticamente al salir del bloque.

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

A continuación, abro el Administrador de control de servicios (utilizando OpenSCManager () ) y el servicio que desea controlar. Tenga en cuenta que el parámetro dwDesiredAccess a OpenService () debe incluir permisos para cada control que quiero enviar, o de las funciones de control relevantes a fallar.

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;

Para detener el servicio, yo uso ControlService () para enviar el código SERVICE_CONTROL_STOP, y después comprobar el valor de retorno para asegurarse de que el comando tuvo éxito. Si se informa de cualquier error que no sea ERROR_SERVICE_NOT_ACTIVE, supongo que a partir de que el servicio no va a tener éxito.

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

Después de instruir el servicio de parada, espero el gerente de servicio al informe que el servicio es, de hecho, se detuvo. Este código tiene dos errores potenciales, que puede que desee correcta para el código de producción:

  1. Sleep (1000) suspenderá el bucle de mensaje en este hilo, por lo que debe utilizar otro método para la ejecución retraso si esta función se ejecutará en un hilo de interfaz de usuario. Se puede construir un sueño-con-mensaje de bucle adecuado utilizando MsgWaitForMultipleObjectsEx () .
  2. El DWORD volvió de GetTickCount () envolverá a cero con el tiempo; si se envuelve alrededor mientras esta función está a la espera, la espera puede renunciar antes de lo que pretendía.

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

Por último, sabiendo que el servicio está en un estado detenido, llamo StartService () correr de nuevo.

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

    return TRUE;
}

Otros consejos

Aquí es un pequeño programa que se conectará con un servicio llamado "MYSERVICE" a continuación, enviar un comando 141 (que se define por el servicio)

// ServiceCommunicator.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <Windows.h>
#include <iostream>

using namespace std;

int main()
{
    SC_HANDLE managerHandle;
    SC_HANDLE serviceHandle;

    SERVICE_STATUS   controlParms;
    DWORD retStatus;

    managerHandle = OpenSCManager(NULL, NULL, GENERIC_READ);
    if (NULL != managerHandle)
    {
        serviceHandle = OpenService(managerHandle, L"MYSERVICE", SERVICE_USER_DEFINED_CONTROL | SERVICE_QUERY_STATUS);

        if (NULL != serviceHandle)
        {
            cout << "connected to Service" << endl;
            retStatus = ControlService(serviceHandle, 141, &controlParms);

            if (retStatus)
            {
                //Get the return code from the service
                cout << "For command 141, return code from service was " << controlParms.dwWin32ExitCode << endl;
            }
            else
                cout << "Sending command 141 failed" << endl;

            CloseServiceHandle(serviceHandle);
        }
        else
        {
            cout << "could not connect to Service" << endl;
        }

        CloseServiceHandle(managerHandle);
    }
    else
    {
        cout << "could not open service manager" << endl;
    }
    return 0;
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top