Convert a C # command line application to a Windows service

I found many partial answers, but nothing really is enough.

Case: An application is a command line application, without user interaction, with the exception of the ability to get a keystroke to log in to stop, it is already written in a way that disables even this when it does not start as Environment.UserInteractive == true.

I am using Visual Studio 2010.

The problem is that I need to convert this application to a Windows service. Is it "just" creating a new class file as a service, and does it invoke methods to start and stop an existing application?

What about the installer (MSI default installer by default), is it possible to update an existing installer project to handle the installation?

I messed up this before and ended up with the installer, who continued to refuse to install, as he continued to detect the already installed service, stopping the installation process, and then quickly rolling back everything. The discovered service was the one it just installed.

+4
source share
3 answers

To start a console application as a Windows application or a console application, write a single console application and use the command line arguments to determine whether to start directly or start the service. Enable the installer / uninstaller to install as a Windows service with the correct command line arguments.

It uses a base class that provides this functionality.

using System; using System.Collections; using System.Configuration.Install; using System.Diagnostics; using System.IO; using System.Reflection; using System.ServiceProcess; using System.Windows.Forms; using Microsoft.Win32; namespace Console40 { public abstract class AbstractService : ServiceBase { public static AbstractService Current { get; private set; } protected virtual string HelpTextPattern { get { #region Help Text return @" USAGE {0} [command] WHERE [command] is one of /console - run as a console application, for debugging /service - run as a windows service /install - install as a windows service /uninstall - uninstall windows service "; #endregion } } public abstract string DisplayName { get; } public ServiceExecutionMode ServiceExecutionMode { get; private set; } protected abstract Guid UninstallGuid { get; } protected virtual string UninstallRegKeyPath { get { return @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"; } } protected AbstractService(string serviceName) { ServiceName = serviceName; if (Current != null) { throw new InvalidOperationException(String.Format( "Service {0} is instantiating but service {1} is already instantiated as current. References to AbstractService.Current will only point to the first service.", GetType().FullName, Current.GetType().FullName)); } Current = this; } public void Run(string[] args) { Environment.CurrentDirectory = AppDomain.CurrentDomain.BaseDirectory; if (args.Length == 0 && Debugger.IsAttached) { args = new[] { "/console" }; } if (args.Length == 0) { Console.WriteLine(HelpTextPattern, Path.GetFileName(GetType().Assembly.CodeBase)); } else { switch (args[0].ToLower()) { case "/service": ServiceExecutionMode = ServiceExecutionMode.Service; Run(new[] { this }); break; case "/console": ServiceExecutionMode = ServiceExecutionMode.Console; Console.WriteLine("Starting Service..."); OnStart(new string[0]); OnStartCommandLine(); OnStop(); break; case "/install": ServiceExecutionMode = ServiceExecutionMode.Install; InstallService(); break; case "/uninstall": ServiceExecutionMode = ServiceExecutionMode.Uninstall; UninstallService(); break; case "/uninstallprompt": ServiceExecutionMode = ServiceExecutionMode.Uninstall; if (ConfirmUninstall()) { UninstallService(); InformUninstalled(); } break; default: if (!OnCustomCommandLine(args)) { Console.WriteLine(HelpTextPattern, Path.GetFileName(GetType().Assembly.CodeBase)); } break; } } } protected override void OnStart(string[] args) { OnStartImpl(args); AppDomain.CurrentDomain.UnhandledException += OnCurrentDomainUnhandledException; } protected virtual void OnStartCommandLine() { Console.WriteLine("Service is running... Hit ENTER to break."); Console.ReadLine(); } protected abstract void OnStartImpl(string[] args); void OnCurrentDomainUnhandledException(object sender, UnhandledExceptionEventArgs e) { // do something useful here, log it.. } protected override void OnShutdown() { Stop(); } protected override void OnStop() { OnStopImpl(); } protected abstract void OnStopImpl(); protected virtual bool OnCustomCommandLine(string[] args) { // for extension return false; } private void InstallService() { GetInstaller(".InstallLog").Install(new Hashtable()); InstallServiceCommandLine(); CreateUninstaller(); } private void InstallServiceCommandLine() { string keyParent = @"SYSTEM\CurrentControlSet\Services\" + ServiceName; const string VALUE_NAME = "ImagePath"; try { using (RegistryKey key = Registry.LocalMachine.OpenSubKey(keyParent, true)) { if (key == null) { throw new InvalidOperationException("Service not found in registry."); } var origPath = key.GetValue(VALUE_NAME) as string; if (origPath == null) { throw new Exception("HKLM\\" + keyParent + "\\" + VALUE_NAME + " does not exist but was expected."); } key.SetValue(VALUE_NAME, origPath.Replace("\"\"", "\"") + " /service"); } } catch (Exception ex) { throw new Exception( "Error updating service command line after installation. Unable to write to HKLM\\" + keyParent, ex); } } private void CreateUninstaller() { using (RegistryKey parent = Registry.LocalMachine.OpenSubKey(UninstallRegKeyPath, true)) { if (parent == null) { throw new Exception(String.Format("Uninstall registry key '{0}' not found.", UninstallRegKeyPath)); } try { RegistryKey key = null; try { string guidText = UninstallGuid.ToString("B"); key = parent.OpenSubKey(guidText, true) ?? parent.CreateSubKey(guidText); if (key == null) { throw new Exception(String.Format("Unable to create uninstaller '{0}\\{1}'", UninstallRegKeyPath, guidText)); } Assembly asm = GetType().Assembly; Version v = asm.GetName().Version; string exe = "\"" + asm.CodeBase.Substring(8).Replace("/", "\\\\") + "\""; key.SetValue("DisplayName", DisplayName); key.SetValue("ApplicationVersion", v.ToString()); key.SetValue("Publisher", "B-Line Medical"); key.SetValue("DisplayIcon", exe); key.SetValue("DisplayVersion", v.ToString(2)); key.SetValue("URLInfoAbout", "http://www.blinemedical.com"); key.SetValue("Contact", " support@blinemedical.com "); key.SetValue("InstallDate", DateTime.Now.ToString("yyyyMMdd")); key.SetValue("UninstallString", exe + " /uninstallprompt"); } finally { if (key != null) { key.Close(); } } } catch (Exception ex) { throw new Exception( "An error occurred writing uninstall information to the registry. The service is fully installed but can only be uninstalled manually through the command line.", ex); } } } private bool ConfirmUninstall() { string title = "Uninstall " + DisplayName; string text = "Are you sure you want to remove " + DisplayName + " from your computer?"; return DialogResult.Yes == MessageBox.Show(text, title, MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2); } private void InformUninstalled() { string title = "Uninstall " + DisplayName; string text = DisplayName + " has been uninstalled."; MessageBox.Show(text, title, MessageBoxButtons.OK, MessageBoxIcon.Information); } private void UninstallService() { GetInstaller(".UninstallLog").Uninstall(null); RemoveUninstaller(); } private TransactedInstaller GetInstaller(string logExtension) { var ti = new TransactedInstaller(); ti.Installers.Add(new ServiceProcessInstaller { Account = ServiceAccount.LocalSystem }); ti.Installers.Add(new ServiceInstaller { DisplayName = DisplayName, ServiceName = ServiceName, StartType = ServiceStartMode.Automatic }); string basePath = Assembly.GetEntryAssembly().Location; String path = String.Format("/assemblypath=\"{0}\"", basePath); ti.Context = new InstallContext(Path.ChangeExtension(basePath, logExtension), new[] { path }); return ti; } private void RemoveUninstaller() { using (RegistryKey key = Registry.LocalMachine.OpenSubKey(UninstallRegKeyPath, true)) { if (key == null) { return; } try { string guidText = UninstallGuid.ToString("B"); RegistryKey child = key.OpenSubKey(guidText); if (child != null) { child.Close(); key.DeleteSubKey(guidText); } } catch (Exception ex) { throw new Exception( "An error occurred removing uninstall information from the registry. The service was uninstalled will still show up in the add/remove program list. To remove it manually delete the entry HKLM\\" + UninstallRegKeyPath + "\\" + UninstallGuid, ex); } } } } public enum ServiceExecutionMode { Unknown, Service, Console, Install, Uninstall, Custom } } 
+11
source

Save C # Application

 public partial class DemoService : ServiceBase { static void Main(string[] args) { DemoService service = new DemoService(); if (Environment.UserInteractive) { service.OnStart(args); Console.WriteLine("Press any key to stop program"); Console.Read(); service.OnStop(); } else { ServiceBase.Run(service); } } 

Check out the link above. I am providing some code as well as a link describing how to use the console to work together as a console and a service. I will use the console project and check UserInteractive before starting as a service. Thus, you can debug as a console, but install it as a service on a production server.

Regarding the installation, I have no experience installing with .msi, but we use a batch script to install the service (using sc.exe), and then just replace the files when updating the code.

+1
source

The best thing you need to do is to start a new project as a Windows service. In this new project you will find Service1.cs, and this is the file that will be launched from the very beginning. The following code will be int file:

 namespace WindowsService1 { public partial class Service1 : ServiceBase { public Service1() { InitializeComponent(); } protected override void OnStart(string[] args) { } protected override void OnStop() { } } } 

It is not so difficult to understand what to do next. Just add your classes to the project and make sure you copy your main code in the OnStart () function. Of course, you may need to slightly edit the code to make sure there are no lines to read.

Now you have to create and install. How you can do this can be found here: http://msdn.microsoft.com/en-us/library/zt39148a%28v=vs.100%29.aspx

Hope this helps: D

Yours faithfully

Roxas city

0
source

Source: https://habr.com/ru/post/1432479/


All Articles