4

部分的な回答がたくさん見つかりましたが、本当に十分なものはありませんでした。

ケース: アプリは、Enter キーを押して停止する機能を除いて、ユーザー インタラクションのない動作中のコマンド ライン アプリです。真実。

Visual Studio 2010 を使用しています。

問題は、このアプリを Windows サービスに変換する必要があることです。新しいクラス ファイルをサービスとして作成し、既存のアプリケーションで start メソッドと stop メソッドを呼び出すだけですか?

インストーラー (VS のデフォルトの msi インストーラー) はどうですか? 既存のインストーラー プロジェクトを「アップグレード」して、サービスのインストールも処理できますか?

私は以前これをいじって、サービスが既にインストールされていることを検出し続け、すぐにすべてをロールバックしてインストールプロセスを停止したため、インストールを拒否し続けるインストーラーになりました。検出されたサービスは、インストールしたばかりのサービスでした。

4

3 に答える 3

11

コンソール アプリを Windows サービスまたはコンソール アプリケーションとして実行するには、単一のコンソール アプリケーションを作成し、コマンド ライン引数を使用して、サービスを直接実行するか開始するかを決定します。適切なコマンド ライン引数を使用して Windows サービスとしてインストールするインストーラー/アンインストーラーを含めます。

この機能を提供するために使用する基本クラスを次に示します。

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
    }
}
于 2012-09-05T13:09:10.233 に答える
1

C#アプリケーションを実行し続ける

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

上記のリンクを確認してください。私はいくつかのコードと、コンソールとサービスとしての二重の義務のためのコンソールの使用を説明するリンクを提供します。コンソールプロジェクトを使用して、サービスとして実行する前にUserInteractiveを確認します。このようにして、コンソールのようにデバッグできますが、運用サーバーにサービスとしてインストールします。

インストールに関しては、.msiからのインストールの経験はありませんが、バッチスクリプトを使用してサービスをインストールし(sc.exeを使用)、コードを更新する場合はファイルを置き換えるだけです。

于 2012-09-05T13:11:50.987 に答える
0

最善の方法は、新しいプロジェクトを Windows サービスとして開始することです。この新しいプロジェクトには Service1.cs があり、これが最初から実行されるファイルです。次のコードはファイルの int になります。

namespace WindowsService1
{
    public partial class Service1 : ServiceBase
    {
        public Service1()
        {
        InitializeComponent();
        }

        protected override void OnStart(string[] args)
        {
        }

        protected override void OnStop()
        {
        }
    }
}

ここから何をすべきかを理解するのはそれほど難しくありません。クラスをプロジェクトに追加し、メイン コードを OnStart() 関数にコピーするだけです。もちろん、コードに readlines が含まれていないことを確認するために、コードを少し編集する必要があるかもしれません。

次に、作成してインストーラーを作成する必要があります。これを行う方法については、http: //msdn.microsoft.com/en-us/library/zt39148a%28v=vs.100%29.aspxを参照してください。

これがお役に立てば幸いです:D

敬具

ロクサス

于 2012-09-05T13:08:49.290 に答える