【问题标题】:Install a .NET windows service without InstallUtil.exe在没有 InstallUtil.exe 的情况下安装 .NET windows 服务
【发布时间】:2010-09-20 06:46:33
【问题描述】:

我有一个用 C# 编写的标准 .NET Windows 服务。

是否可以不使用 InstallUtil 自行安装? 我应该使用服务安装程序类吗?我应该如何使用它?

我希望能够调用以下内容:

MyService.exe -install

而且会和调用一样的效果:

InstallUtil MyService.exe

【问题讨论】:

  • 我刚遇到这个问题,但这里的答案有点过时了。现在(至少从 2015 年开始)我们可以简单地使用 SC 命令安装 Windows 服务,如此处所述stackoverflow.com/a/34220957/512993。免责声明:我写了那个答案。

标签: c# .net deployment windows-services installutil


【解决方案1】:
Process QProc = new Process();
QProc.StartInfo.FileName = "cmd";
QProc.StartInfo.Arguments ="/c InstallUtil "+ "\""+ filefullPath +"\"";
QProc.StartInfo.WorkingDirectory = Environment.GetEnvironmentVariable("windir") + @"\Microsoft.NET\Framework\v2.0.50727\";
QProc.StartInfo.UseShellExecute = false;
// QProc.StartInfo.CreateNoWindow = true;
QProc.StartInfo.RedirectStandardOutput = true;
QProc.Start();
// QProc.WaitForExit();
QProc.Close();

【讨论】:

    【解决方案2】:

    上面的例子对我来说真的不起作用,作为#1 解决方案的论坛链接很难挖掘。这是我写的一个类(部分),另一部分是从this link I found buried somewhere合并而来的

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    using System.ServiceProcess;
    using System.Runtime.InteropServices;
    
    namespace SystemControl {
        class Services {
    
    #region "Environment Variables"
            public static string GetEnvironment(string name, bool ExpandVariables=true) {
                if ( ExpandVariables ) {
                    return System.Environment.GetEnvironmentVariable( name );
                } else {
                    return (string)Microsoft.Win32.Registry.LocalMachine.OpenSubKey( @"SYSTEM\CurrentControlSet\Control\Session Manager\Environment\" ).GetValue( name, "", Microsoft.Win32.RegistryValueOptions.DoNotExpandEnvironmentNames );
                }
            }
    
            public static void SetEnvironment( string name, string value ) {
                System.Environment.SetEnvironmentVariable(name, value);
            }
    #endregion
    
    #region "ServiceCalls Native"
            public static ServiceController[] List { get { return ServiceController.GetServices(); } }
    
            public static void Start( string serviceName, int timeoutMilliseconds ) {
                ServiceController service=new ServiceController( serviceName );
                try {
                    TimeSpan timeout=TimeSpan.FromMilliseconds( timeoutMilliseconds );
    
                    service.Start();
                    service.WaitForStatus( ServiceControllerStatus.Running, timeout );
                } catch {
                    // ...
                }
            }
    
            public static void Stop( string serviceName, int timeoutMilliseconds ) {
                ServiceController service=new ServiceController( serviceName );
                try {
                    TimeSpan timeout=TimeSpan.FromMilliseconds( timeoutMilliseconds );
    
                    service.Stop();
                    service.WaitForStatus( ServiceControllerStatus.Stopped, timeout );
                } catch {
                    // ...
                }
            }
    
            public static void Restart( string serviceName, int timeoutMilliseconds ) {
                ServiceController service=new ServiceController( serviceName );
                try {
                    int millisec1=Environment.TickCount;
                    TimeSpan timeout=TimeSpan.FromMilliseconds( timeoutMilliseconds );
    
                    service.Stop();
                    service.WaitForStatus( ServiceControllerStatus.Stopped, timeout );
    
                    // count the rest of the timeout
                    int millisec2=Environment.TickCount;
                    timeout=TimeSpan.FromMilliseconds( timeoutMilliseconds-( millisec2-millisec1 ) );
    
                    service.Start();
                    service.WaitForStatus( ServiceControllerStatus.Running, timeout );
                } catch {
                    // ...
                }
            }
    
            public static bool IsInstalled( string serviceName ) {
                // get list of Windows services
                ServiceController[] services=ServiceController.GetServices();
    
                // try to find service name
                foreach ( ServiceController service in services ) {
                    if ( service.ServiceName==serviceName )
                        return true;
                }
                return false;
            }
    #endregion
    
    #region "ServiceCalls API"
            private const int STANDARD_RIGHTS_REQUIRED = 0xF0000;
            private const int SERVICE_WIN32_OWN_PROCESS = 0x00000010;
    
            [Flags]
            public enum ServiceManagerRights {
                Connect = 0x0001,
                CreateService = 0x0002,
                EnumerateService = 0x0004,
                Lock = 0x0008,
                QueryLockStatus = 0x0010,
                ModifyBootConfig = 0x0020,
                StandardRightsRequired = 0xF0000,
                AllAccess = (StandardRightsRequired | Connect | CreateService |
                EnumerateService | Lock | QueryLockStatus | ModifyBootConfig)
            }
    
            [Flags]
            public enum ServiceRights {
                QueryConfig = 0x1,
                ChangeConfig = 0x2,
                QueryStatus = 0x4,
                EnumerateDependants = 0x8,
                Start = 0x10,
                Stop = 0x20,
                PauseContinue = 0x40,
                Interrogate = 0x80,
                UserDefinedControl = 0x100,
                Delete = 0x00010000,
                StandardRightsRequired = 0xF0000,
                AllAccess = (StandardRightsRequired | QueryConfig | ChangeConfig |
                QueryStatus | EnumerateDependants | Start | Stop | PauseContinue |
                Interrogate | UserDefinedControl)
            }
    
            public enum ServiceBootFlag {
                Start = 0x00000000,
                SystemStart = 0x00000001,
                AutoStart = 0x00000002,
                DemandStart = 0x00000003,
                Disabled = 0x00000004
            }
    
            public enum ServiceState {
                Unknown = -1, // The state cannot be (has not been) retrieved.
                NotFound = 0, // The service is not known on the host server.
                Stop = 1, // The service is NET stopped.
                Run = 2, // The service is NET started.
                Stopping = 3,
                Starting = 4,
            }
    
            public enum ServiceControl {
                Stop = 0x00000001,
                Pause = 0x00000002,
                Continue = 0x00000003,
                Interrogate = 0x00000004,
                Shutdown = 0x00000005,
                ParamChange = 0x00000006,
                NetBindAdd = 0x00000007,
                NetBindRemove = 0x00000008,
                NetBindEnable = 0x00000009,
                NetBindDisable = 0x0000000A
            }
    
            public enum ServiceError {
                Ignore = 0x00000000,
                Normal = 0x00000001,
                Severe = 0x00000002,
                Critical = 0x00000003
            }
    
            [StructLayout(LayoutKind.Sequential)]
            private class SERVICE_STATUS {
                public int dwServiceType = 0;
                public ServiceState dwCurrentState = 0;
                public int dwControlsAccepted = 0;
                public int dwWin32ExitCode = 0;
                public int dwServiceSpecificExitCode = 0;
                public int dwCheckPoint = 0;
                public int dwWaitHint = 0;
            }
    
            [DllImport("advapi32.dll", EntryPoint = "OpenSCManagerA")]
            private static extern IntPtr OpenSCManager(string lpMachineName, string lpDatabaseName, ServiceManagerRights dwDesiredAccess);
            [DllImport("advapi32.dll", EntryPoint = "OpenServiceA", CharSet = CharSet.Ansi)]
            private static extern IntPtr OpenService(IntPtr hSCManager, string lpServiceName, ServiceRights dwDesiredAccess);
            [DllImport("advapi32.dll", EntryPoint = "CreateServiceA")]
            private static extern IntPtr CreateService(IntPtr hSCManager, string lpServiceName, string lpDisplayName, ServiceRights dwDesiredAccess, int dwServiceType, ServiceBootFlag dwStartType, ServiceError dwErrorControl, string lpBinaryPathName, string lpLoadOrderGroup, IntPtr lpdwTagId, string lpDependencies, string lp, string lpPassword);
            [DllImport("advapi32.dll")]
            private static extern int CloseServiceHandle(IntPtr hSCObject);
            [DllImport("advapi32.dll")]
            private static extern int QueryServiceStatus(IntPtr hService, SERVICE_STATUS lpServiceStatus);
            [DllImport("advapi32.dll", SetLastError = true)]
            private static extern int DeleteService(IntPtr hService);
            [DllImport("advapi32.dll")]
            private static extern int ControlService(IntPtr hService, ServiceControl dwControl, SERVICE_STATUS lpServiceStatus);
            [DllImport("advapi32.dll", EntryPoint = "StartServiceA")]
            private static extern int StartService(IntPtr hService, int dwNumServiceArgs, int lpServiceArgVectors);
    
            /// <summary>
            /// Takes a service name and tries to stop and then uninstall the windows serviceError
            /// </summary>
            /// <param name="ServiceName">The windows service name to uninstall</param>
            public static void Uninstall(string ServiceName)
            {
                IntPtr scman = OpenSCManager(ServiceManagerRights.Connect);
                try
                {
                    IntPtr service = OpenService(scman, ServiceName, ServiceRights.StandardRightsRequired | ServiceRights.Stop | ServiceRights.QueryStatus);
                    if (service == IntPtr.Zero)
                    {
                        throw new ApplicationException("Service not installed.");
                    }
                    try
                    {
                        StopService(service);
                        int ret = DeleteService(service);
                        if (ret == 0)
                        {
                            int error = Marshal.GetLastWin32Error();
                            throw new ApplicationException("Could not delete service " + error);
                        }
                    }
                    finally
                    {
                        CloseServiceHandle(service);
                    }
                }
                finally
                {
                    CloseServiceHandle(scman);
                }
            }
    
            /// <summary>
            /// Accepts a service name and returns true if the service with that service name exists
            /// </summary>
            /// <param name="ServiceName">The service name that we will check for existence</param>
            /// <returns>True if that service exists false otherwise</returns>
            public static bool ServiceIsInstalled(string ServiceName)
            {
                IntPtr scman = OpenSCManager(ServiceManagerRights.Connect);
                try
                {
                    IntPtr service = OpenService(scman, ServiceName,
                    ServiceRights.QueryStatus);
                    if (service == IntPtr.Zero) return false;
                    CloseServiceHandle(service);
                    return true;
                }
                finally
                {
                    CloseServiceHandle(scman);
                }
            }
    
            /// <summary>
            /// Takes a service name, a service display name and the path to the service executable and installs / starts the windows service.
            /// </summary>
            /// <param name="ServiceName">The service name that this service will have</param>
            /// <param name="DisplayName">The display name that this service will have</param>
            /// <param name="FileName">The path to the executable of the service</param>
            public static void InstallAndStart(string ServiceName, string DisplayName,
            string FileName)
            {
                IntPtr scman = OpenSCManager(ServiceManagerRights.Connect |
                ServiceManagerRights.CreateService);
                try
                {
                    IntPtr service = OpenService(scman, ServiceName,
                    ServiceRights.QueryStatus | ServiceRights.Start);
                    if (service == IntPtr.Zero)
                    {
                        service = CreateService(scman, ServiceName, DisplayName,
                        ServiceRights.QueryStatus | ServiceRights.Start, SERVICE_WIN32_OWN_PROCESS,
                        ServiceBootFlag.AutoStart, ServiceError.Normal, FileName, null, IntPtr.Zero,
                        null, null, null);
                    }
                    if (service == IntPtr.Zero)
                    {
                        throw new ApplicationException("Failed to install service.");
                    }
                    try
                    {
                        StartService(service);
                    }
                    finally
                    {
                        CloseServiceHandle(service);
                    }
                }
                finally
                {
                    CloseServiceHandle(scman);
                }
            }
    
            /// <summary>
            /// Takes a service name and starts it
            /// </summary>
            /// <param name="Name">The service name</param>
            public static void StartService(string Name)
            {
                IntPtr scman = OpenSCManager(ServiceManagerRights.Connect);
                try
                {
                    IntPtr hService = OpenService(scman, Name, ServiceRights.QueryStatus |
                    ServiceRights.Start);
                    if (hService == IntPtr.Zero)
                    {
                        throw new ApplicationException("Could not open service.");
                    }
                    try
                    {
                        StartService(hService);
                    }
                    finally
                    {
                        CloseServiceHandle(hService);
                    }
                }
                finally
                {
                    CloseServiceHandle(scman);
                }
            }
    
            /// <summary>
            /// Stops the provided windows service
            /// </summary>
            /// <param name="Name">The service name that will be stopped</param>
            public static void StopService(string Name)
            {
                IntPtr scman = OpenSCManager(ServiceManagerRights.Connect);
                try
                {
                    IntPtr hService = OpenService(scman, Name, ServiceRights.QueryStatus |
                    ServiceRights.Stop);
                    if (hService == IntPtr.Zero)
                    {
                        throw new ApplicationException("Could not open service.");
                    }
                    try
                    {
                        StopService(hService);
                    }
                    finally
                    {
                        CloseServiceHandle(hService);
                    }
                }
                finally
                {
                    CloseServiceHandle(scman);
                }
            }
    
            /// <summary>
            /// Stars the provided windows service
            /// </summary>
            /// <param name="hService">The handle to the windows service</param>
            private static void StartService(IntPtr hService)
            {
                SERVICE_STATUS status = new SERVICE_STATUS();
                StartService(hService, 0, 0);
                WaitForServiceStatus(hService, ServiceState.Starting, ServiceState.Run);
            }
    
            /// <summary>
            /// Stops the provided windows service
            /// </summary>
            /// <param name="hService">The handle to the windows service</param>
            private static void StopService(IntPtr hService)
            {
                SERVICE_STATUS status = new SERVICE_STATUS();
                ControlService(hService, ServiceControl.Stop, status);
                WaitForServiceStatus(hService, ServiceState.Stopping, ServiceState.Stop);
            }
    
            /// <summary>
            /// Takes a service name and returns the <code>ServiceState</code> of the corresponding service
            /// </summary>
            /// <param name="ServiceName">The service name that we will check for his <code>ServiceState</code></param>
            /// <returns>The ServiceState of the service we wanted to check</returns>
            public static ServiceState GetServiceStatus(string ServiceName)
            {
                IntPtr scman = OpenSCManager(ServiceManagerRights.Connect);
                try
                {
                    IntPtr hService = OpenService(scman, ServiceName,
                    ServiceRights.QueryStatus);
                    if (hService == IntPtr.Zero)
                    {
                        return ServiceState.NotFound;
                    }
                    try
                    {
                        return GetServiceStatus(hService);
                    }
                    finally
                    {
                        CloseServiceHandle(scman);
                    }
                }
                finally
                {
                    CloseServiceHandle(scman);
                }
            }
    
            /// <summary>
            /// Gets the service state by using the handle of the provided windows service
            /// </summary>
            /// <param name="hService">The handle to the service</param>
            /// <returns>The <code>ServiceState</code> of the service</returns>
            private static ServiceState GetServiceStatus(IntPtr hService)
            {
                SERVICE_STATUS ssStatus = new SERVICE_STATUS();
                if (QueryServiceStatus(hService, ssStatus) == 0)
                {
                    throw new ApplicationException("Failed to query service status.");
                }
                return ssStatus.dwCurrentState;
            }
    
            /// <summary>
            /// Returns true when the service status has been changes from wait status to desired status
            /// ,this method waits around 10 seconds for this operation.
            /// </summary>
            /// <param name="hService">The handle to the service</param>
            /// <param name="WaitStatus">The current state of the service</param>
            /// <param name="DesiredStatus">The desired state of the service</param>
            /// <returns>bool if the service has successfully changed states within the allowed timeline</returns>
            private static bool WaitForServiceStatus(IntPtr hService, ServiceState
            WaitStatus, ServiceState DesiredStatus)
            {
                SERVICE_STATUS ssStatus = new SERVICE_STATUS();
                int dwOldCheckPoint;
                int dwStartTickCount;
    
                QueryServiceStatus(hService, ssStatus);
                if (ssStatus.dwCurrentState == DesiredStatus) return true;
                dwStartTickCount = Environment.TickCount;
                dwOldCheckPoint = ssStatus.dwCheckPoint;
    
                while (ssStatus.dwCurrentState == WaitStatus)
                {
                    // Do not wait longer than the wait hint. A good interval is
                    // one tenth the wait hint, but no less than 1 second and no
                    // more than 10 seconds.
    
                    int dwWaitTime = ssStatus.dwWaitHint / 10;
    
                    if (dwWaitTime < 1000) dwWaitTime = 1000;
                    else if (dwWaitTime > 10000) dwWaitTime = 10000;
    
                    System.Threading.Thread.Sleep(dwWaitTime);
    
                    // Check the status again.
    
                    if (QueryServiceStatus(hService, ssStatus) == 0) break;
    
                    if (ssStatus.dwCheckPoint > dwOldCheckPoint)
                    {
                        // The service is making progress.
                        dwStartTickCount = Environment.TickCount;
                        dwOldCheckPoint = ssStatus.dwCheckPoint;
                    }
                    else
                    {
                        if (Environment.TickCount - dwStartTickCount > ssStatus.dwWaitHint)
                        {
                            // No progress made within the wait hint
                            break;
                        }
                    }
                }
                return (ssStatus.dwCurrentState == DesiredStatus);
            }
    
            /// <summary>
            /// Opens the service manager
            /// </summary>
            /// <param name="Rights">The service manager rights</param>
            /// <returns>the handle to the service manager</returns>
            private static IntPtr OpenSCManager(ServiceManagerRights Rights)
            {
                IntPtr scman = OpenSCManager(null, null, Rights);
                if (scman == IntPtr.Zero)
                {
                    throw new ApplicationException("Could not connect to service control manager.");
                }
                return scman;
            }
    
    #endregion
    
        }
    }
    

    要安装服务,请按如下方式运行 InstallAndStart 命令:

      SystemControl.InstallAndStart(
                                     "apache",
                                     "Apache Web Server",
                                     @"""c:\apache\bin\httpd.exe"" -k runservice"
      );
    

    确保运行程序的帐户具有安装服务的权限。您始终可以在程序上“以管理员身份运行”。

    我还包含了几个用于非 api 访问的命令,它们不会安装或删除服务,但您可以列出它们并控制几个(启动、停止、重新启动)。您实际上只需要提升安装或删除服务的权限。

    还有一些用于获取和设置环境变量的命令,例如OPENSSL_CONFTEMP。在大多数情况下,参数和方法名称应该是不言自明的。

    【讨论】:

    • ServiceState 枚举有错别字。应该是:Unknown = -1, NotFound = 0, Stopped = 1, StartPending = 2, StopPending = 3, Running = 4
    【解决方案3】:

    是的,这是完全可能的(即我就是这样做的);您只需要引用正确的 dll (System.ServiceProcess.dll) 并添加一个安装程序类...

    Here's an example:

    [RunInstaller(true)]
    public sealed class MyServiceInstallerProcess : ServiceProcessInstaller
    {
        public MyServiceInstallerProcess()
        {
            this.Account = ServiceAccount.NetworkService;
        }
    }
    
    [RunInstaller(true)]
    public sealed class MyServiceInstaller : ServiceInstaller
    {
        public MyServiceInstaller()
        {
            this.Description = "Service Description";
            this.DisplayName = "Service Name";
            this.ServiceName = "ServiceName";
            this.StartType = System.ServiceProcess.ServiceStartMode.Automatic;
        }
    }
    
    static void Install(bool undo, string[] args)
    {
        try
        {
            Console.WriteLine(undo ? "uninstalling" : "installing");
            using (AssemblyInstaller inst = new AssemblyInstaller(typeof(Program).Assembly, args))
            {
                IDictionary state = new Hashtable();
                inst.UseNewContext = true;
                try
                {
                    if (undo)
                    {
                        inst.Uninstall(state);
                    }
                    else
                    {
                        inst.Install(state);
                        inst.Commit(state);
                    }
                }
                catch
                {
                    try
                    {
                        inst.Rollback(state);
                    }
                    catch { }
                    throw;
                }
            }
        }
        catch (Exception ex)
        {
            Console.Error.WriteLine(ex.Message);
        }
    }
    

    【讨论】:

    • @MarcGravell 您可能应该在此处包含代码,因为没有它,这个答案不是很有用。
    • @MarcGravell 在您的链接示例中,在类(等)定义之外有一个static void Install(bool undo, string[] args)。你能澄清一下你是如何实现的吗?
    【解决方案4】:

    如果尝试将命令行应用程序安装为 Windows 服务,请尝试使用“NSSM”实用程序。找到相关的 ServerFault 详细信息here

    【讨论】:

      【解决方案5】:

      尽管涉及的工作量很大,但您始终可以回退到良好的旧 WinAPI 调用。没有要求通过 .NET 感知机制安装 .NET 服务。

      安装:

      • 通过OpenSCManager打开服务管理器。
      • 拨打CreateService注册服务。
      • 可以选择调用ChangeServiceConfig2 来设置描述。
      • 使用CloseServiceHandle关闭服务和服务管理器句柄。

      卸载:

      • 通过OpenSCManager打开服务管理器。
      • 使用OpenService打开服务。
      • OpenService返回的句柄上调用DeleteService删除服务。
      • 使用CloseServiceHandle 关闭服务和服务管理器句柄。

      我更喜欢使用 ServiceInstaller/ServiceProcessInstaller 的主要原因是您可以使用自己的自定义命令行参数注册服务。例如,您可以将其注册为 "MyApp.exe -service",然后如果用户在没有任何参数的情况下运行您的应用程序,您可以为他们提供一个 UI 来安装/删除服务。

      ServiceInstaller 上运行 Reflector 可以填补这个简短说明中缺少的细节。

      附:显然,这不会产生“与调用 InstallUtil MyService.exe 相同的效果”——特别是,您将无法使用 InstallUtil 进行卸载。但看起来这对你来说可能并不是一个真正的严格要求。

      【讨论】:

      • 您的步骤实际上非常容易遵循。在MSDN WIN API documentation 上进行一些额外的谷歌搜索,这实际上是自己写的!
      【解决方案6】:

      看一下ManagedInstaller 类的InstallHelper 方法。您可以使用以下方式安装服务:

      string[] args;
      ManagedInstallerClass.InstallHelper(args);
      

      这正是 InstallUtil 所做的。参数与 InstallUtil 相同。

      这种方法的好处是它不会弄乱注册表,并且它使用与 InstallUtil 相同的机制。

      【讨论】:

      • 当文档说这不应该由用户代码调用时,您为什么建议这样做?
      • 我使用这种方法是因为 1. 它很简单 2. 这正是 InstallUtil 所做的 3. 在 x86/x64 上您不需要更改安装程序 4. 它没有在 .Net 的几个版本中进行了更改 - 如果确实如此,它将在测试中被选中,然后我会修复它。
      【解决方案7】:

      这是我在编写服务时使用的一个类。我通常会在未调用服务时出现一个交互式屏幕。从那里我根据需要使用该课程。它允许在同一台机器上存在多个命名实例 - 因此 InstanceID 字段

      示例调用

        IntegratedServiceInstaller Inst = new IntegratedServiceInstaller();
        Inst.Install("MySvc", "My Sample Service", "Service that executes something",
                          _InstanceID,
      // System.ServiceProcess.ServiceAccount.LocalService,      // this is more secure, but only available in XP and above and WS-2003 and above
        System.ServiceProcess.ServiceAccount.LocalSystem,       // this is required for WS-2000
        System.ServiceProcess.ServiceStartMode.Automatic);
        if (controller == null)
        {
          controller = new System.ServiceProcess.ServiceController(String.Format("MySvc_{0}", _InstanceID), ".");
                      }
                      if (controller.Status == System.ServiceProcess.ServiceControllerStatus.Running)
                      {
                          Start_Stop.Text = "Stop Service";
                          Start_Stop_Debugging.Enabled = false;
                      }
                      else
                      {
                          Start_Stop.Text = "Start Service";
                          Start_Stop_Debugging.Enabled = true;
                      }
      

      类本身

      using System;
      using System.Collections.Generic;
      using System.Text;
      using System.Diagnostics;
      using Microsoft.Win32;
      
      namespace MySvc
      {
          class IntegratedServiceInstaller
          {
              public void Install(String ServiceName, String DisplayName, String Description,
                  String InstanceID,
                  System.ServiceProcess.ServiceAccount Account, 
                  System.ServiceProcess.ServiceStartMode StartMode)
              {
                  //http://www.theblacksparrow.com/
                  System.ServiceProcess.ServiceProcessInstaller ProcessInstaller = new System.ServiceProcess.ServiceProcessInstaller();
                  ProcessInstaller.Account = Account;
      
                  System.ServiceProcess.ServiceInstaller SINST = new System.ServiceProcess.ServiceInstaller();
      
                  System.Configuration.Install.InstallContext Context = new System.Configuration.Install.InstallContext();
                  string processPath = Process.GetCurrentProcess().MainModule.FileName;
                  if (processPath != null && processPath.Length > 0)
                  {
                      System.IO.FileInfo fi = new System.IO.FileInfo(processPath);
      
                      String path = String.Format("/assemblypath={0}", fi.FullName);
                      String[] cmdline = { path };
                      Context = new System.Configuration.Install.InstallContext("", cmdline);
                  }
      
                  SINST.Context = Context;
                  SINST.DisplayName = String.Format("{0} - {1}", DisplayName, InstanceID);
                  SINST.Description = String.Format("{0} - {1}", Description, InstanceID);
                  SINST.ServiceName = String.Format("{0}_{1}", ServiceName, InstanceID);
                  SINST.StartType = StartMode;
                  SINST.Parent = ProcessInstaller;
      
                  // http://bytes.com/forum/thread527221.html
                  SINST.ServicesDependedOn = new String[] { "Spooler", "Netlogon", "Netman" };
      
                  System.Collections.Specialized.ListDictionary state = new System.Collections.Specialized.ListDictionary();
                  SINST.Install(state);
      
                  // http://www.dotnet247.com/247reference/msgs/43/219565.aspx
                  using (RegistryKey oKey = Registry.LocalMachine.OpenSubKey(String.Format(@"SYSTEM\CurrentControlSet\Services\{0}_{1}", ServiceName, InstanceID), true))
                  {
                      try
                      {
                          Object sValue = oKey.GetValue("ImagePath");
                          oKey.SetValue("ImagePath", sValue);
                      }
                      catch (Exception Ex)
                      {
                          System.Windows.Forms.MessageBox.Show(Ex.Message);
                      }
                  }
      
              }
              public void Uninstall(String ServiceName, String InstanceID)
              {
                  //http://www.theblacksparrow.com/
                  System.ServiceProcess.ServiceInstaller SINST = new System.ServiceProcess.ServiceInstaller();
      
                  System.Configuration.Install.InstallContext Context = new System.Configuration.Install.InstallContext("c:\\install.log", null);
                  SINST.Context = Context;
                  SINST.ServiceName = String.Format("{0}_{1}", ServiceName, InstanceID);
                  SINST.Uninstall(null);
              }
          }
      }
      

      【讨论】:

      • 这也可以用来“被动”注册不同的可执行文件,我用参数替换了GetCurrentProcess部分并成功使用。效果很好!
      • 什么是_InstanceID?
      • 我有一个应用程序,我使用同一服务的多个副本,指向不同的数据库。我使用存储在配置文件中的实例 ID 来区分它们。服务的多租户...
      猜你喜欢
      • 1970-01-01
      • 2011-02-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多