Как управлять Windows сервисом из программы WinForms [C#]

Возникло у меня задание, управлять сервисом Windows из GUI программы написанной на C# WinForms. Сервис управляет модемным Интернет подкючением. Заказчик захотел иметь возможность управлять сервисом напрямую из программы. Т.е. ему нужна следующая функциональность — Остановить, Запустить, Перезапустить, отобразить текущее состояние.

Для этого я написал простой класс, который делает это при помощи стандартного ServiceController класса.

Полный код класса ниже. Этот класс умеет получать состояние сервиса, запускать, останавливать и перезапускать его.
Для ожидания изменения состояния я написал асинхроную функцию, которая ждет указаное время и если сервис не изменил свое состояние, бросает System.TimeoutException.

Этот класс выполняет все, что мне требуется, но он очень простой.
Его легко можно расширить при необходимости.

ПРИМЕЧАНИЕ: В стандартном классе ServiceController есть метод WaitForStatus. Но мне не удалось заставить его правильно работать в WinForms. Поэтому более быстрым решением было написатьс обственный асинхронный метод.

    public static class ServiceManager
    {
        // ********************************************************************
        public static bool IsServiceExists(string serviceName)
        {
            List<string> services = ServiceController.GetServices().Select(o => o.ServiceName).ToList<string>();

            return services.Contains(serviceName);
        }

        // ********************************************************************
        public static ServiceControllerStatus GetServiceStatus(string serviceName)
        {
            if (!IsServiceExists(serviceName))
                throw new InvalidOperationException(string.Format("Service with specified name [{0}] doesn't exists.", serviceName));

            ServiceController serviceController = new ServiceController(serviceName);

            return serviceController.Status;
        }

        // ********************************************************************
        public static string GetServiceStatusText(ServiceControllerStatus status)
        {
            string text = "Unknown";

            switch (status)
            {
                default:
                    break;

                case ServiceControllerStatus.ContinuePending:
                    text = "Continue Pending";
                    break;
                case ServiceControllerStatus.Paused:
                    text = "Paused";
                    break;
                case ServiceControllerStatus.PausePending:
                    text = "Pause Pending";
                    break;
                case ServiceControllerStatus.Running:
                    text = "Running";
                    break;
                case ServiceControllerStatus.StartPending:
                    text = "Start Pending";
                    break;
                case ServiceControllerStatus.Stopped:
                    text = "Stopped";
                    break;
                case ServiceControllerStatus.StopPending:
                    text = "Stop Pending";
                    break;

            }

            return text;
        }

        // ********************************************************************
        public static async Task StartServiceAsync(string serviceName, int timeoutMs)
        {
            if (!IsServiceExists(serviceName))
                throw new InvalidOperationException(string.Format("Service with specified name [{0}] doesn't exists.", serviceName));

            ServiceController serviceController = new ServiceController(serviceName);

            if (serviceController.Status == ServiceControllerStatus.Running ||
                    serviceController.Status == ServiceControllerStatus.StartPending)
            {
                // Service already started, nothing to do
                return;
            }

            TimeSpan timeout = TimeSpan.FromMilliseconds(timeoutMs);

            serviceController.Start();
            await serviceController.WaitForServiceStateAsync(ServiceControllerStatus.Running, timeout);
        }

        // ********************************************************************
        public static async Task StopServiceAsync(string serviceName, int timeoutMs)
        {
            if (!IsServiceExists(serviceName))
                throw new InvalidOperationException(string.Format("Service with specified name [{0}] doesn't exists.", serviceName));

            ServiceController serviceController = new ServiceController(serviceName);

            if (serviceController.Status == ServiceControllerStatus.Stopped ||
                    serviceController.Status == ServiceControllerStatus.StopPending)
            {
                // Service already stopped, nothing to do
                return;
            }

            TimeSpan timeout = TimeSpan.FromMilliseconds(timeoutMs);

            serviceController.Stop();
            await serviceController.WaitForServiceStateAsync(ServiceControllerStatus.Stopped, timeout);
        }

        // ********************************************************************
        public static async Task RestartServiceAsync(string serviceName, int timeoutMs)
        {
            if (!IsServiceExists(serviceName))
                throw new InvalidOperationException(string.Format("Service with specified name [{0}] doesn't exists.", serviceName));

            ServiceController serviceController = new ServiceController(serviceName);

            if (serviceController.Status == ServiceControllerStatus.Stopped ||
                 serviceController.Status == ServiceControllerStatus.StopPending)
            {
                // Service already stopped, nothing to do
                return;
            }

            TimeSpan timeout = TimeSpan.FromMilliseconds(timeoutMs);

            serviceController.Stop();
            await serviceController.WaitForServiceStateAsync(ServiceControllerStatus.Stopped, timeout);

            serviceController.Start();
            await serviceController.WaitForServiceStateAsync(ServiceControllerStatus.Running, timeout);
        }

        // ********************************************************************
        public static async Task WaitForServiceStateAsync(this ServiceController sc, ServiceControllerStatus desiredStatus, TimeSpan timeoutMs)
        {
            DateTime start = DateTime.Now;
            while (true)
            {
                sc.Refresh();
                if (sc.Status == desiredStatus)
                    break;

                await Task.Delay(250);

                TimeSpan ts = DateTime.Now - start;
                if (ts >= timeoutMs)
                    throw new System.TimeoutException();
            }
        }
    }

Добавить комментарий

Ваш e-mail не будет опубликован.