using System; using System.Collections; using System.Collections.Generic; using System.Configuration.Install; using System.Reflection; using System.ServiceProcess; namespace PRSServices; // Class to manage the installation of services public class PRSServiceInstaller { public static Assembly Assembly { get; set; } public static bool IsInstalled(string serviceName) { return ServiceController.GetServices().Any(s => s.ServiceName == serviceName); } public static bool IsRunning(string serviceName) { using (var controller = new ServiceController(serviceName)) { if (!IsInstalled(serviceName)) return false; return controller.Status == ServiceControllerStatus.Running; } } private static AssemblyInstaller GetInstaller(string serviceName, string description, string displayName, string? username, string? password) { // The arguments passed here are received by PRSInstaller, which it uses to set service metadata. // /name=servicename is *REQUIRED* because otherwise Windows can't find the service in the executable. var installProperties = new List { "/name=" + serviceName, "/description=" + description, "/displayName=" + displayName }; if(!string.IsNullOrWhiteSpace(username)) { installProperties.Add("/username=" + username); installProperties.Add("/password=" + (password ?? "")); } var installer = new AssemblyInstaller(Assembly, installProperties.ToArray()); installer.UseNewContext = true; return installer; } private static AssemblyInstaller GetUninstaller(string serviceName) { // The argument passed here is received by PRSInstaller. /name=serviceName is used to find the serviceName // in the PRSServer.exe, which can then execute the uninstaller. var installer = new AssemblyInstaller(Assembly, new[] { "/name=" + serviceName }); installer.UseNewContext = true; return installer; } public static void InstallService(string serviceName, string description, string displayName, string? username, string? password) { if (IsInstalled(serviceName)) return; using var installer = GetInstaller(serviceName, description, displayName, username, password); IDictionary state = new Hashtable(); try { installer.Install(state); installer.Commit(state); } catch { try { //installer.Rollback(state); } catch { } throw; } } public static void UninstallService(string serviceName) { if (!IsInstalled(serviceName)) return; using var installer = GetUninstaller(serviceName); IDictionary state = new Hashtable(); installer.Uninstall(state); } public static void ChangeService(string serviceName, string description, string displayName, string? username, string? password) { if (IsInstalled(serviceName)) UninstallService(serviceName); InstallService(serviceName, description, displayName, username, password); /* // Delegate the configuration of the service to sc.exe, and execute. // I haven't found a way to do it without using sc.exe. (Unless we decided to change the registry, which is surely a bad idea.) // Convert quotes and backslashes to escaped quotes and backslashes var newServiceName = serviceName.Replace("\"", "\\\"").Replace("\\", "\\\\"); var newDisplayName = displayName.Replace("\"", "\\\"").Replace("\\", "\\\\"); var newDescription = description.Replace("\"", "\\\"").Replace("\\", "\\\\"); RunCommand("sc.exe", "description \"" + newServiceName + "\" \"" + newDescription + "\""); RunCommand("sc.exe", "config \"" + newServiceName + "\" displayname=\"" + newDisplayName + "\""); */ } public static void StartService(string serviceName) { if (!IsInstalled(serviceName)) return; using var controller = new ServiceController(serviceName); if (controller.Status != ServiceControllerStatus.Running) { controller.Start(); controller.WaitForStatus(ServiceControllerStatus.Running, TimeSpan.FromSeconds(10)); } } public static void StopService(string serviceName) { if (!IsInstalled(serviceName)) return; using var controller = new ServiceController(serviceName); if (controller.Status != ServiceControllerStatus.Stopped) { controller.Stop(); controller.WaitForStatus(ServiceControllerStatus.Stopped, TimeSpan.FromSeconds(10)); } } }