【问题标题】:How to change a Windows service installation directory at install time?如何在安装时更改 Windows 服务安装目录?
【发布时间】:2016-12-09 18:08:59
【问题描述】:

我构建了一个 Windows 服务(在 Visual Studio 2015 中),我需要用户选择要安装的目录,但在安装时我需要在提供的目录中添加一个子文件夹。通常我使用System.Reflection.Assembly.GetExecutingAssembly().Location 获取安装目录,但我无法更改它。例如,我可以在BeforeInstall 方法中更改任何方法或属性吗?

【问题讨论】:

    标签: c# windows service visual-studio-2015 installation


    【解决方案1】:

    我花了几天时间搜索,但实际上很容易。 为此,您需要

    • 右键单击您的设置项目并选择View->File System
    • 右击application folder并选择Add->Folder
    • 为您的新文件夹命名。
    • 将所有需要的文件从application folder 移到您的新文件夹中。

    差不多了。

    这里有一些代码可以帮助您使用一个安装程序两次安装相同的服务。安装程序设置服务恢复模式、服务权限、访问权限、重写一些配置文件并启动这两个服务。卸载部分卸载这两个服务。

    using System;
    using System.Collections;
    using System.Configuration.Install;
    using System.Diagnostics;
    using System.IO;
    using System.Security.AccessControl;
    using System.Security.Principal;
    using System.ServiceProcess;
    
    namespace MyService
    {
        partial class ProjectInstaller
        {
            /// <summary>
            /// Required designer variable.
            /// </summary>
            private System.ComponentModel.IContainer components = null;
    
            /// <summary> 
            /// Clean up any resources being used.
            /// </summary>
            /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
            protected override void Dispose(bool disposing)
            {
                if (disposing && (components != null))
                {
                    components.Dispose();
                }
                base.Dispose(disposing);
            }
    
            #region Component Designer generated code
    
            /// <summary>
            /// Required method for Designer support - do not modify
            /// the contents of this method with the code editor.
            /// </summary>
            private void InitializeComponent()
            {
                this.MyServiceProcessInstaller = new ServiceProcessInstaller();
                this.MyServiceInstaller = new ServiceInstaller();
                // 
                // MyServiceProcessInstaller
                // 
                this.MyServiceProcessInstaller.Account = ServiceAccount.LocalService;
                this.MyServiceProcessInstaller.Password = null;
                this.MyServiceProcessInstaller.Username = null;
                // 
                // MyServiceInstaller
                // 
                this.MyServiceInstaller.Description = "First instance of my service.";
                this.MyServiceInstaller.DisplayName = "My Service - Instance 1";
                this.MyServiceInstaller.ServiceName = "MyService-1";
                this.MyServiceInstaller.StartType = ServiceStartMode.Automatic;
                this.MyServiceInstaller.Committed += new InstallEventHandler(this.ServiceInstaller_Committed);
                this.MyServiceInstaller.AfterInstall += new InstallEventHandler(this.ServiceInstaller_AfterInstall);
                this.MyServiceInstaller.AfterUninstall += new InstallEventHandler(this.ServiceInstaller_AfterUnInstall);
    
                // 
                // ProjectInstaller
                // 
                this.Installers.AddRange(new Installer[] {
                    this.MyServiceProcessInstaller,
                    this.MyServiceInstaller
                });
    
            }
    
            public override void Install(IDictionary stateSaver)
            {// This gets the named parameters passed in from your custom action
                string EXEFullPath = System.Reflection.Assembly.GetExecutingAssembly().Location;
                string path = Path.GetDirectoryName(EXEFullPath);   // get installation path
    
                try
                {
                    SetAccess(path);
    
                    string path2 = Path.Combine(Directory.GetParent(path).FullName, "instance2");
                    string EXEFullPath2 = Path.Combine(path2, Path.GetFileName(System.Reflection.Assembly.GetExecutingAssembly().Location));
    
                    if (!Directory.Exists(path2))
                    {
                        Directory.CreateDirectory(path2);
                    }
    
                    SetAccess(path2);
    
                    // Get the file contents of the directory to copy.
                    FileInfo[] files = (new DirectoryInfo(path)).GetFiles();
    
                    foreach (FileInfo file in files)
                    {
                        string temppath;
    
                        // Create the path to the new copy of the file.
                        temppath = Path.Combine(path2, file.Name);
    
                        // Copy the file.
                        file.CopyTo(temppath, true);
                    }
    
                    string Instance = "1";
    
                    string Alltext = File.ReadAllText(EXEFullPath + ".config");
                    // Rewrite config file - instance 1
                    Alltext = Alltext.Replace("{Instance}", Instance);
                    File.WriteAllText(EXEFullPath + ".config", Alltext);
    
                    Instance = "2";
    
                    Alltext = File.ReadAllText(EXEFullPath2 + ".config");
                    // Rewrite config file - instance 2
                    Alltext = Alltext.Replace("{Instance}", Instance);
                    File.WriteAllText(EXEFullPath2 + ".config", Alltext);
                }
                catch
                {
                }
    
                base.Install(stateSaver);
            }
    
            void SetAccess(string dir)
            {
                // Create security identifier for Local Service user; Local Service is used for the service at installation
                SecurityIdentifier sid = new SecurityIdentifier(WellKnownSidType.LocalServiceSid, null);
                DirectoryInfo di = new DirectoryInfo(dir);
                DirectorySecurity ds = di.GetAccessControl();
                // add a new file access rule w/ write/modify for all users to the directory security object
    
                ds.AddAccessRule(new FileSystemAccessRule(sid,
                                                      FileSystemRights.Write | FileSystemRights.Modify,
                                                      InheritanceFlags.ObjectInherit | InheritanceFlags.ContainerInherit,   // all sub-dirs to inherit
                                                      PropagationFlags.None,
                                                      AccessControlType.Allow));                                            // Turn write and modify on
                                                                                                                            // Apply the directory security to the directory
                di.SetAccessControl(ds);
            }
    
            void ServiceInstaller_AfterInstall(object sender, InstallEventArgs e)
            {// This gets the named parameters passed in from your custom action
                using (ServiceController sc = new ServiceController(MyServiceInstaller.ServiceName))
                {
                    sc.Start();     // start the service (instance 1) after installation
                }
    
                int exitCode;
    
                using (var process = new Process())
                {
                    var startInfo = process.StartInfo;
                    startInfo.FileName = "sc";
                    startInfo.WindowStyle = ProcessWindowStyle.Hidden;
    
                    string EXEFullPath = System.Reflection.Assembly.GetExecutingAssembly().Location;
                    string path = Path.GetDirectoryName(EXEFullPath);   // get installation path
    
                    string path2 = Path.Combine(Directory.GetParent(path).FullName, "instance2");
                    string EXEFullPath2 = Path.Combine(path2, Path.GetFileName(System.Reflection.Assembly.GetExecutingAssembly().Location));
    
                    // tell Windows that the service should restart if it fails
                    startInfo.Arguments = string.Format("create {0} start= auto binPath= \"{1}\" obj= \"{2}\" DisplayName= \"{3}\"", "MyService-2", EXEFullPath2, "NT AUTHORITY\\LocalService", "My Service - Instance 2");
    
                    process.Start();
                    process.WaitForExit();
    
                    exitCode = process.ExitCode;
                }
    
                if (exitCode != 0)
                    throw new InvalidOperationException();
                else
                {
                    using (var process = new Process())
                    {
                        var startInfo = process.StartInfo;
                        startInfo.FileName = "sc";
                        startInfo.WindowStyle = ProcessWindowStyle.Hidden;
    
                        // Set the service description
                        startInfo.Arguments = string.Format("description {0} \"{1}\"", "MyService-2", "Second instance of My Service.");
    
                        process.Start();
                        process.WaitForExit();
    
                        exitCode = process.ExitCode;
                    }
    
                    if (exitCode != 0)
                        throw new InvalidOperationException();
                }
    
                if (exitCode == 0)
                {
                    using (ServiceController sc = new ServiceController("MyService-2"))
                    {
                        sc.Start();     // start the service (instance 2) after installation
                    }
                }
            }
    
            // right after service is installed, we set Recovery to restart after failures.
            void ServiceInstaller_Committed(object sender, InstallEventArgs e)
            {
                int exitCode;
    
                using (var process = new Process())
                {
                    var startInfo = process.StartInfo;
                    startInfo.FileName = "sc";
                    startInfo.WindowStyle = ProcessWindowStyle.Hidden;
    
                    // tell Windows that the service should restart if it fails
                    startInfo.Arguments = string.Format("failure \"{0}\" reset= 0 actions= restart/0", MyServiceInstaller.ServiceName);
    
                    process.Start();
                    process.WaitForExit();
    
                    exitCode = process.ExitCode;
                }
    
                if (exitCode != 0)
                    throw new InvalidOperationException();
                else
                {
                    using (var process = new Process())
                    {
                        var startInfo = process.StartInfo;
                        startInfo.FileName = "sc";
                        startInfo.WindowStyle = ProcessWindowStyle.Hidden;
    
                        // tell Windows that the service should restart if it fails
                        startInfo.Arguments = string.Format("failure \"{0}\" reset= 0 actions= restart/0", "MyService-2");
    
                        process.Start();
                        process.WaitForExit();
    
                        exitCode = process.ExitCode;
                    }
                }
    
                if (exitCode != 0)
                    throw new InvalidOperationException();
                else
                {
                    using (var process = new Process())
                    {
                        var startInfo = process.StartInfo;
                        startInfo.FileName = "sc";
                        startInfo.WindowStyle = ProcessWindowStyle.Hidden;
    
                        // reset Manager 1 service permissions
                        startInfo.Arguments = string.Format("sdset {0} \"{1}\"", "MyService-1", "D:(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWLOCRRC;;;IU)(A;;CCLCSWLOCRRC;;;SU)(A;;CCLCSWLOCRRCRPWP;;;LS)S:(AU;FA;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;WD)");
    
                        process.Start();
                        process.WaitForExit();
    
                        exitCode = process.ExitCode;
                    }
    
                    if (exitCode != 0)
                        throw new InvalidOperationException();
                }
    
                if (exitCode != 0)
                    throw new InvalidOperationException();
                else
                {
                    using (var process = new Process())
                    {
                        var startInfo = process.StartInfo;
                        startInfo.FileName = "sc";
                        startInfo.WindowStyle = ProcessWindowStyle.Hidden;
    
                        // reset Manager 2 service permissions
                        startInfo.Arguments = string.Format("sdset {0} \"{1}\"", "MyService-2", "D:(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWLOCRRC;;;IU)(A;;CCLCSWLOCRRC;;;SU)(A;;CCLCSWLOCRRCRPWP;;;LS)S:(AU;FA;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;WD)");
    
                        process.Start();
                        process.WaitForExit();
    
                        exitCode = process.ExitCode;
                    }
    
                    if (exitCode != 0)
                        throw new InvalidOperationException();
                }
            }
    
            void ServiceInstaller_AfterUnInstall(object sender, InstallEventArgs e)
            {// This gets the named parameters passed in from your custom action
                try
                {
                    using (ServiceController sc = new ServiceController("MyService-2"))
                    {
                        sc.Stop();     // stop the service (instance 2) after uninstallation
                    }
                }
                catch
                {
                }
    
                try
                {
                    int exitCode;
    
                    using (var process = new Process())
                    {
                        var startInfo = process.StartInfo;
                        startInfo.FileName = "sc";
                        startInfo.WindowStyle = ProcessWindowStyle.Hidden;
    
                        // tell Windows that the service should restart if it fails
                        startInfo.Arguments = string.Format("delete MyService-2");
    
                        process.Start();
                        process.WaitForExit();
    
                        exitCode = process.ExitCode;
                    }
                }
                catch
                {
                }
    
                try
                {
                    string EXEFullPath = System.Reflection.Assembly.GetExecutingAssembly().Location;
                    string path = Path.GetDirectoryName(EXEFullPath);   // get installation path
    
                    string path2 = Path.Combine(Directory.GetParent(path).FullName, "instance2");
                    string EXEFullPath2 = Path.Combine(path2, Path.GetFileName(System.Reflection.Assembly.GetExecutingAssembly().Location));
    
                    Directory.Delete(path2, true);
                }
                catch
                {
                }
            }
    
            #endregion
    
            private System.ServiceProcess.ServiceProcessInstaller MyServiceProcessInstaller;
            private System.ServiceProcess.ServiceInstaller MyServiceInstaller;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-01-27
      • 2018-09-27
      • 1970-01-01
      • 2011-09-15
      • 1970-01-01
      • 1970-01-01
      • 2016-10-11
      相关资源
      最近更新 更多