在安装时自动启动Windows服务

126

我有一个Windows服务,我使用InstallUtil.exe进行安装。尽管我将启动方式设置为自动,但服务在安装后不会自动启动,我必须手动打开服务并单击启动。是否有通过命令行或服务代码启动它的方法?

13个回答

232

在您的Installer类中,添加一个处理程序用于AfterInstall事件。然后可以在事件处理程序中调用ServiceController来启动服务。

using System.ServiceProcess;
public ServiceInstaller()
{
    //... Installer code here
    this.AfterInstall += new InstallEventHandler(ServiceInstaller_AfterInstall);
}

void ServiceInstaller_AfterInstall(object sender, InstallEventArgs e)
{
    ServiceInstaller serviceInstaller = (ServiceInstaller)sender;

    using (ServiceController sc = new ServiceController(serviceInstaller.ServiceName))
    {
             sc.Start();
    }
}

现在当你在安装程序上运行InstallUtil时,它将自动安装并启动服务。


40
最好使用 serviceInstaller.ServiceName。如果服务名称发生更改,它将使用正确的名称而不需要在代码中进行更改。 - Marc Gravell
3
你是如何获取serviceInstaller的? - Philip Rego
1
serviceInstaller 应该是你类中的 ServiceInstaller 变量。这个类应该实现 System.Configuration.Install.Installer 接口。更多信息请参见此 msdn 指南 - Sergio Basurco
4
@PhilipRego 可能 serviceInstaller 是事件处理程序中 sender 所引用的 ServiceInstaller 对象,通常在 ServiceInstaller() 构造函数中实例化。因此,在 using 语句之前添加 ServiceInstaller serviceInstaller = (ServiceInstaller)sender; - khargoosh
1
这个救了我的一天...只有一个改变..我使用了..this.serviceInstaller.ServiceName - Ziggler
显示剩余4条评论

32

经过一些重构后,这是一个完整的Windows服务安装程序示例,具有自动启动功能:

using System.ComponentModel;
using System.Configuration.Install;
using System.ServiceProcess;

namespace Example.of.name.space
{
[RunInstaller(true)]
public partial class ServiceInstaller : Installer
{
    private readonly ServiceProcessInstaller processInstaller;
    private readonly System.ServiceProcess.ServiceInstaller serviceInstaller;

    public ServiceInstaller()
    {
        InitializeComponent();
        processInstaller = new ServiceProcessInstaller();
        serviceInstaller = new System.ServiceProcess.ServiceInstaller();

        // Service will run under system account
        processInstaller.Account = ServiceAccount.LocalSystem;

        // Service will have Automatic Start Type
        serviceInstaller.StartType = ServiceStartMode.Automatic;

        serviceInstaller.ServiceName = "Windows Automatic Start Service";

        Installers.Add(serviceInstaller);
        Installers.Add(processInstaller);
        serviceInstaller.AfterInstall += ServiceInstaller_AfterInstall;            
    }
    private void ServiceInstaller_AfterInstall(object sender, InstallEventArgs e)
    {
        ServiceController sc = new ServiceController("Windows Automatic Start Service");
        sc.Start();
    }
}
}

2
这段代码给了我以下错误: 在安装阶段发生了异常。 System.InvalidOperationException:在System.ServiceProcess.ServiceInstaller的OnAfterInstall事件处理程序中发生了异常。 内部异常System.InvalidOperationException抛出了以下错误消息:无法在计算机“。”上启动serviceName服务。 内部异常System.ComponentModel.Win32Exception抛出了以下错误消息:配置为运行此服务的可执行程序未实现该服务。 - goamn
2
一旦我注释掉了“InitializeComponent()”这一行,错误就消失了。我认为这一行是重复了所有其他行,因为日志似乎显示在错误之前同时发生了两件完全相同的事情:正在安装服务serviceName... 服务serviceName已成功安装。 在应用程序日志中创建EventLog源serviceName... 正在安装服务serviceName... 在应用程序日志中创建EventLog源serviceName... System.ServiceProcess.ServiceInstaller的OnAfterInstall事件处理程序中发生了异常。 - goamn
你真的救了我的一天 :) 感谢您提供这个有用的评论。在我注释掉InitializeComponent()调用之后,我的服务也完美地启动了。 - Konstantin

9
以下是相关命令,您可以参考:

如下是相关命令:

net start "<service name>"
net stop "<service name>"

很好。我在安装批处理文件中写了这个,在安装完成后立即执行。 - M. Fawad Surosh

5

控制服务的编程选项:

  • 可以使用本机代码,“启动服务”。最大的控制力和最少的依赖,但需要付出更多的工作。
  • WMI: Win32_Service 有一个 StartService 方法。这适用于需要执行其他处理(例如选择哪个服务)的情况。
  • PowerShell:通过RunspaceInvoke 执行 Start-Service 或创建自己的 Runspace 并使用其CreatePipeline 方法执行。这适用于需要执行其他处理(例如选择哪个服务)且编码模型比 WMI 容易得多的情况,但需要安装 PSH。
  • .NET 应用程序可以使用ServiceController

4
您可以使用以下命令行启动服务:
net start *servicename*

4
这里是一个在Visual Studio中使用生成的ProjectInstaller过程和代码示例:
  1. 在Visual Studio中创建Windows服务项目
  2. 为服务生成安装程序
  3. 在设计编辑器中打开ProjectInstaller(安装程序创建时应该会自动打开),设置生成的serviceProcessInstaller1(例如账户:LocalSystem)和serviceInstaller1(例如启动类型:自动)的属性。
  4. 在代码编辑器中打开ProjectInstaller(在设计编辑器中按下F7),并添加ServiceInstaller.AfterInstall事件处理程序,参见以下代码。它将在安装后启动服务。

ProjectInstaller类:

using System.ServiceProcess;


[RunInstaller(true)]
public partial class ProjectInstaller : System.Configuration.Install.Installer
{
    public ProjectInstaller()
    {
        InitializeComponent(); //generated code including property settings from previous steps
        this.serviceInstaller1.AfterInstall += Autorun_AfterServiceInstall; //use your ServiceInstaller name if changed from serviceInstaller1
    }

    void Autorun_AfterServiceInstall(object sender, InstallEventArgs e)
    {
        ServiceInstaller serviceInstaller = (ServiceInstaller)sender;
        using (ServiceController sc = new ServiceController(serviceInstaller.ServiceName))
        {
            sc.Start();
        }
    }
}

这个对我很有帮助,因为我正在使用ProjectInstaller。谢谢! - HadidM
这个对我很有帮助,因为我正在使用ProjectInstaller。谢谢! - undefined
我尝试了一样的方法,但是没有起作用。 - Lê Vũ Huy

2

使用ServiceController从代码中启动您的服务。

更新:从命令行启动服务的更正确的方法是使用“sc”(服务控制器)命令,而不是“net”。


6
为什么“sc”是“更正确”的方式?“net start”(以及start-service PSH cmdlet)有什么问题? - Richard
1
由于sc可以从远程机器调用,因此它总是有效的。 - Entree

1

尽管我完全按照所接受的答案操作,但我仍然无法启动服务——在安装过程中,我收到了一个失败消息,指出刚刚安装的服务无法启动,因为它不存在,尽管使用了this.serviceInstaller.ServiceName而不是文字...

最终,我找到了一种替代方案,利用命令行:

private void serviceInstaller_AfterInstall(object sender, InstallEventArgs e) {
        ProcessStartInfo startInfo = new ProcessStartInfo();
        startInfo.WindowStyle = ProcessWindowStyle.Hidden;
        startInfo.FileName = "cmd.exe";
        startInfo.Arguments = "/C sc start " + this.serviceInstaller.ServiceName;

        Process process = new Process();
        process.StartInfo = startInfo;
        process.Start();
    }

0

你的设计师出现了问题。重新添加你的安装程序组件。它应该有一个serviceInstaller和一个serviceProcessInstaller。将Startup Method属性设置为Automatic的serviceInstaller将在安装后和每次重启后启动。


0

注意:您可能已经使用表单界面设置了不同的服务安装程序和项目安装程序。在这种情况下,将serviceInstaller.ServiceName替换为“设计师名称”。ServiceName。

在这种情况下,您也不需要私有成员。

感谢您的帮助。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接