using System; using System.Collections; using System.Collections.Generic; using System.Configuration.Install; using System.ServiceProcess; namespace PRSServer { // Class to manage the installation of services public class PRSServiceInstaller { private static bool IsInstalled(string serviceName) { using (var controller = new ServiceController(serviceName)) { try { var status = controller.Status; } catch { return false; } return true; } } private 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( typeof(App).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( typeof(App).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)); } } } } }