教程:创建 Windows 服务应用Tutorial: Create a Windows service app

本文演示了如何在 Visual Studio 中创建可向事件日志中写入消息的 Windows 服务应用程序。This article demonstrates how to create a Windows service app in Visual Studio that writes messages to an event log.

创建服务Create a service

首先,创建项目并设置服务正常运行所必需的值。To begin, create the project and set the values that are required for the service to function correctly.

  1. 从 Visual Studio“文件”菜单中,选择“新建” > “项目”(或按 Ctrl+Shift+N),打开“新建项目”窗口 。From the Visual Studio File menu, select New > Project (or press Ctrl+Shift+N) to open the New Project window.

  2. 导航到并选择“Windows 服务 (.NET Framework)”项目模板 。Navigate to and select the Windows Service (.NET Framework) project template. 若要找到它,请展开“已安装”和 “Visual C#”“Visual Basic” ,然后选择“Windows 桌面” 。To find it, expand Installed and Visual C# or Visual Basic, then select Windows Desktop. 或者,在右上方的搜索框中输入 Windows 服务,然后按 Enter 。Or, enter Windows Service in the search box on the upper right and press Enter.

    Visual Studio“新建项目”对话框中的“Windows 服务”模板

    备注

    如果未看到“Windows 服务”模板,建议安装“.NET 桌面开发”工作负载 :If you don't see the Windows Service template, you may need to install the .NET desktop development workload:

    在“新建项目”对话框中,选择左下方的“打开 Visual Studio 安装程序” 。In the New Project dialog, select Open Visual Studio Installer on the lower left. 选择“.NET 桌面开发”工作负载,然后选择“修改” 。Select the .NET desktop development workload, and then select Modify.

  3. 对于“名称”,请输入 MyNewService,然后选择“确定” 。For Name, enter MyNewService, and then select OK.

    将出现“设计”选项卡(“Service1.cs [Design]”或“Service1.vb [Design]”) 。The Design tab appears (Service1.cs [Design] or Service1.vb [Design]).

    项目模板包括从 System.ServiceProcess.ServiceBase 继承的名为 Service1 的组件类。The project template includes a component class named Service1 that inherits from System.ServiceProcess.ServiceBase. 它包括许多基本服务代码,例如用于启动服务的代码。It includes much of the basic service code, such as the code to start the service.

对服务进行重命名Rename the service

将服务从 Service1 重命名为 MyNewServiceRename the service from Service1 to MyNewService.

  1. 在“解决方案资源管理器”中,选择“Service1.cs”或“Service1.vb”,然后从快捷菜单中选择“重命名” 。In Solution Explorer, select Service1.cs, or Service1.vb, and choose Rename from the shortcut menu. 将文件重命名为“MyNewService.cs”或“MyNewService.vb”,然后按 EnterRename the file to MyNewService.cs, or MyNewService.vb, and then press Enter

    随即将出现一个弹出窗口,询问是否要重命名对代码元素 Service1 的所有引用 。A pop-up window appears asking whether you would like to rename all references to the code element Service1.

  2. 在弹出窗口中,选择“是” 。In the pop-up window, select Yes.

    重命名提示Rename prompt

  3. 在“设计”选项卡中,从快捷菜单中选择“属性” 。In the Design tab, select Properties from the shortcut menu. 在“属性”窗口中,将“ServiceName”值更改为 MyNewService 。From the Properties window, change the ServiceName value to MyNewService.

    服务属性Service properties

  4. 从“文件”菜单中选择“全部保存” 。Select Save All from the File menu.

向服务添加功能Add features to the service

在本节中,你会添加自定义事件日志到 Windows 服务。In this section, you add a custom event log to the Windows service. EventLog 组件是可以添加到 Windows 服务的组件类型的示例。The EventLog component is an example of the type of component you can add to a Windows service.

添加自定义事件日志功能Add custom event log functionality

  1. 在“解决方案资源管理器”中,从“MyNewService.cs”或“MyNewService.vb”的快捷菜单中,选择“查看设计器” 。In Solution Explorer, from the shortcut menu for MyNewService.cs, or MyNewService.vb, choose View Designer.

  2. 在“工具箱”中,展开“组件”,然后将“EventLog”组件拖到“Service1.cs [Design]”或“Service1.vb [Design]”标签 。In Toolbox, expand Components, and then drag the EventLog component to the Service1.cs [Design], or Service1.vb [Design] tab.

  3. 在“解决方案资源管理器”中,从“MyNewService.cs”或“MyNewService.vb”的快捷菜单中,选择“查看代码” 。In Solution Explorer, from the shortcut menu for MyNewService.cs, or MyNewService.vb, choose View Code.

  4. 定义自定义事件日志。Define a custom event log. 对于 C#,编辑现有的 MyNewService() 构造函数;对于 Visual Basic,添加 New() 构造函数:For C#, edit the existing MyNewService() constructor; for Visual Basic, add the New() constructor:

    public MyNewService()
    {
        InitializeComponent();
        eventLog1 = new System.Diagnostics.EventLog();
        if (!System.Diagnostics.EventLog.SourceExists("MySource"))
        {
            System.Diagnostics.EventLog.CreateEventSource(
                "MySource","MyNewLog");
        }
        eventLog1.Source = "MySource";
        eventLog1.Log = "MyNewLog";
    }
    
    ' To access the constructor in Visual Basic, select New from the
    ' method name drop-down list. 
    Public Sub New()
        MyBase.New()
        InitializeComponent()
        Me.EventLog1 = New System.Diagnostics.EventLog
        If Not System.Diagnostics.EventLog.SourceExists("MySource") Then
            System.Diagnostics.EventLog.CreateEventSource("MySource",
            "MyNewLog")
        End If
        EventLog1.Source = "MySource"
        EventLog1.Log = "MyNewLog"
    End Sub
    
  5. using 语句添加到“MyNewService.cs”(如果它尚不存在)或者,对于 System.Diagnostics 命名空间,将 Imports 语句添加到“MyNewService.vb” :Add a using statement to MyNewService.cs (if it doesn't already exist), or an Imports statement MyNewService.vb, for the System.Diagnostics namespace:

    using System.Diagnostics;
    
    Imports System.Diagnostics
    
  6. 从“文件”菜单中选择“全部保存” 。Select Save All from the File menu.

定义服务启动时发生的情况Define what occurs when the service starts

在“MyNewService.cs”或“MyNewService.vb”的代码编辑器中,找到 OnStart 方法;创建项目时,Visual Studio 会自动创建一个空方法定义 。In the code editor for MyNewService.cs or MyNewService.vb, locate the OnStart method; Visual Studio automatically created an empty method definition when you created the project. 添加代码,以在服务启动时向事件日志写入一个条目:Add code that writes an entry to the event log when the service starts:

protected override void OnStart(string[] args)
{
    eventLog1.WriteEntry("In OnStart.");
}
' To access the OnStart in Visual Basic, select OnStart from the
' method name drop-down list. 
Protected Overrides Sub OnStart(ByVal args() As String)
    EventLog1.WriteEntry("In OnStart")
End Sub

轮询Polling

由于服务应用程序设计为长时间运行,因此它通常会轮询或监视你在 OnStart 方法中设置的系统。Because a service application is designed to be long-running, it usually polls or monitors the system, which you set up in the OnStart method. 在服务操作开始后,OnStart 方法必须返回操作系统,以便不阻止系统。The OnStart method must return to the operating system after the service's operation has begun so that the system isn't blocked.

若要设置简单的轮询机制,请使用 System.Timers.Timer 组件。To set up a simple polling mechanism, use the System.Timers.Timer component. 计时器定期引发 Elapsed 事件,此时你的服务可以进行监视。The timer raises an Elapsed event at regular intervals, at which time your service can do its monitoring. 可按如下方式使用 Timer 组件:You use the Timer component as follows:

  • MyNewService.OnStart 方法中设置 Timer 组件的属性。Set the properties of the Timer component in the MyNewService.OnStart method.
  • 通过调用 Start 方法启动计时器。Start the timer by calling the Start method.
设置轮询机制。Set up the polling mechanism.
  1. MyNewService.OnStart 事件中添加以下代码以设置轮询机制:Add the following code in the MyNewService.OnStart event to set up the polling mechanism:

    // Set up a timer that triggers every minute.
    Timer timer = new Timer();
    timer.Interval = 60000; // 60 seconds
    timer.Elapsed += new ElapsedEventHandler(this.OnTimer);
    timer.Start();
    
    ' Set up a timer that triggers every minute.
    Dim timer As Timer = New Timer()
    timer.Interval = 60000 ' 60 seconds
    AddHandler timer.Elapsed, AddressOf Me.OnTimer
    timer.Start()
    
  2. using 语句添加到“MyNewService.cs”,或者,对于 System.Timers 命名空间,将 Imports 语句添加到“MyNewService.vb” :Add a using statement to MyNewService.cs, or an Imports statement to MyNewService.vb, for the System.Timers namespace:

    using System.Timers;
    
    Imports System.Timers
    
  3. MyNewService 类中,添加 OnTimer 方法来处理 Timer.Elapsed 事件:In the MyNewService class, add the OnTimer method to handle the Timer.Elapsed event:

    public void OnTimer(object sender, ElapsedEventArgs args)
    {
        // TODO: Insert monitoring activities here.
        eventLog1.WriteEntry("Monitoring the System", EventLogEntryType.Information, eventId++);
    }
    
    Private Sub OnTimer(sender As Object, e As Timers.ElapsedEventArgs)
       ' TODO: Insert monitoring activities here.
       eventLog1.WriteEntry("Monitoring the System", EventLogEntryType.Information, eventId)
       eventId = eventId + 1
    End Sub
    
  4. MyNewService 类中,添加成员变量。In the MyNewService class, add a member variable. 它包含下一个要写入事件日志的事件的标识符:It contains the identifier of the next event to write into the event log:

    private int eventId = 1;
    
    Private eventId As Integer = 1
    

可以使用后台工作线程来运行任务,而不是在主线程上运行所有工作。Instead of running all your work on the main thread, you can run tasks by using background worker threads. 有关详细信息,请参阅 System.ComponentModel.BackgroundWorkerFor more information, see System.ComponentModel.BackgroundWorker.

定义服务停止时发生的情况Define what occurs when the service is stopped

OnStop 方法插入代码行,以在服务停止时向事件日志添加一个条目:Insert a line of code in the OnStop method that adds an entry to the event log when the service is stopped:

protected override void OnStop()
{
    eventLog1.WriteEntry("In OnStop.");
}
Protected Overrides Sub OnStop()
    EventLog1.WriteEntry("In OnStop.")
End Sub

定义服务的其他操作Define other actions for the service

可以重写 OnPauseOnContinueOnShutdown 方法来定义对组件的其他处理。You can override the OnPause, OnContinue, and OnShutdown methods to define additional processing for your component.

以下代码显示了如何替代 MyNewService 类中的 OnContinue 方法:The following code shows how you to override the OnContinue method in the MyNewService class:

protected override void OnContinue()
{
    eventLog1.WriteEntry("In OnContinue.");
}
Protected Overrides Sub OnContinue()
    EventLog1.WriteEntry("In OnContinue.")
End Sub

设置服务状态Set service status

服务向服务控制管理器报告其状态,以便用户可以判断服务是否运行正常。Services report their status to the Service Control Manager so that a user can tell whether a service is functioning correctly. 默认情况下,从 ServiceBase 继承的服务会报告一组有限的状态设置,包括 SERVICE_STOPPED、SERVICE_PAUSED 和 SERVICE_RUNNING。By default, a service that inherits from ServiceBase reports a limited set of status settings, which include SERVICE_STOPPED, SERVICE_PAUSED, and SERVICE_RUNNING. 如果服务需要一段时间才能启动,则报告 SERVICE_START_PENDING 状态非常有用。If a service takes a while to start up, it's useful to report a SERVICE_START_PENDING status.

可以通过添加调用 Windows SetServiceStatus 函数的代码来实现 SERVICE_START_PENDING 和 SERVICE_STOP_PENDING 状态设置。You can implement the SERVICE_START_PENDING and SERVICE_STOP_PENDING status settings by adding code that calls the Windows SetServiceStatus function.

实现服务挂起状态Implement service pending status

  1. using 语句添加到“MyNewService.cs”,或者,对于 System.Runtime.InteropServices 命名空间,将 Imports 语句添加到“MyNewService.vb” :Add a using statement to MyNewService.cs, or an Imports statement to MyNewService.vb, for the System.Runtime.InteropServices namespace:

    using System.Runtime.InteropServices;
    
    Imports System.Runtime.InteropServices
    
  2. 将以下代码添加到 MyNewService.cs 或 MyNewService.vb,声明 ServiceState 值和添加你将在平台调用中使用的状态结构 :Add the following code to MyNewService.cs, or MyNewService.vb, to declare the ServiceState values and to add a structure for the status, which you'll use in a platform invoke call:

    public enum ServiceState
    {
        SERVICE_STOPPED = 0x00000001,
        SERVICE_START_PENDING = 0x00000002,
        SERVICE_STOP_PENDING = 0x00000003,
        SERVICE_RUNNING = 0x00000004,
        SERVICE_CONTINUE_PENDING = 0x00000005,
        SERVICE_PAUSE_PENDING = 0x00000006,
        SERVICE_PAUSED = 0x00000007,
    }
    
    [StructLayout(LayoutKind.Sequential)]
    public struct ServiceStatus
    {
        public int dwServiceType;
        public ServiceState dwCurrentState;
        public int dwControlsAccepted;
        public int dwWin32ExitCode;
        public int dwServiceSpecificExitCode;
        public int dwCheckPoint;
        public int dwWaitHint;
    };
    
    Public Enum ServiceState
        SERVICE_STOPPED = 1
        SERVICE_START_PENDING = 2
        SERVICE_STOP_PENDING = 3
        SERVICE_RUNNING = 4
        SERVICE_CONTINUE_PENDING = 5
        SERVICE_PAUSE_PENDING = 6
        SERVICE_PAUSED = 7
    End Enum
    
    <StructLayout(LayoutKind.Sequential)>
    Public Structure ServiceStatus
        Public dwServiceType As Long
        Public dwCurrentState As ServiceState
        Public dwControlsAccepted As Long
        Public dwWin32ExitCode As Long
        Public dwServiceSpecificExitCode As Long
        Public dwCheckPoint As Long
        Public dwWaitHint As Long
    End Structure
    

    备注

    服务控制管理器使用 SERVICE_STATUS 结构dwWaitHintdwCheckpoint 成员来确定等待 Windows 服务启动或关闭所需的时间。The Service Control Manager uses the dwWaitHint and dwCheckpoint members of the SERVICE_STATUS structure to determine how much time to wait for a Windows service to start or shut down. 如果 OnStartOnStop 方法运行时间较长,服务可以使用递增的 dwCheckPoint 值再次调用 SetServiceStatus 来请求更多时间。If your OnStart and OnStop methods run long, your service can request more time by calling SetServiceStatus again with an incremented dwCheckPoint value.

  3. MyNewService 类中,使用平台调用声明 SetServiceStatus 函数In the MyNewService class, declare the SetServiceStatus function by using platform invoke:

    [DllImport("advapi32.dll", SetLastError = true)]
    private static extern bool SetServiceStatus(System.IntPtr handle, ref ServiceStatus serviceStatus);
    
    Declare Auto Function SetServiceStatus Lib "advapi32.dll" (ByVal handle As IntPtr, ByRef serviceStatus As ServiceStatus) As Boolean
    
  4. 若要实现“SERVICE_START_PENDING”状态,请将以下代码添加到 OnStart 方法的开头:To implement the SERVICE_START_PENDING status, add the following code to the beginning of the OnStart method:

    // Update the service state to Start Pending.
    ServiceStatus serviceStatus = new ServiceStatus();
    serviceStatus.dwCurrentState = ServiceState.SERVICE_START_PENDING;
    serviceStatus.dwWaitHint = 100000;
    SetServiceStatus(this.ServiceHandle, ref serviceStatus);
    
    ' Update the service state to Start Pending.
    Dim serviceStatus As ServiceStatus = New ServiceStatus()
    serviceStatus.dwCurrentState = ServiceState.SERVICE_START_PENDING
    serviceStatus.dwWaitHint = 100000
    SetServiceStatus(Me.ServiceHandle, serviceStatus)
    
  5. 将代码添加到 OnStart 方法的末尾,可将状态设置为 SERVICE_RUNNING:Add code to the end of the OnStart method to set the status to SERVICE_RUNNING:

    // Update the service state to Running.
    serviceStatus.dwCurrentState = ServiceState.SERVICE_RUNNING;
    SetServiceStatus(this.ServiceHandle, ref serviceStatus);
    
    ' Update the service state to Running.
    serviceStatus.dwCurrentState = ServiceState.SERVICE_RUNNING
    SetServiceStatus(Me.ServiceHandle, serviceStatus)
    
  6. (可选)如果 OnStop 是长时间运行的方法,请在 OnStop 方法中重复此过程。(Optional) If OnStop is a long-running method, repeat this procedure in the OnStop method. 实现 SERVICE_STOP_PENDING 状态并在 OnStop 方法退出之前返回 SERVICE_STOPPED 状态。Implement the SERVICE_STOP_PENDING status and return the SERVICE_STOPPED status before the OnStop method exits.

    例如:For example:

    // Update the service state to Stop Pending.
    ServiceStatus serviceStatus = new ServiceStatus();
    serviceStatus.dwCurrentState = ServiceState.SERVICE_STOP_PENDING;
    serviceStatus.dwWaitHint = 100000;
    SetServiceStatus(this.ServiceHandle, ref serviceStatus);
    
    // Update the service state to Stopped.
    serviceStatus.dwCurrentState = ServiceState.SERVICE_STOPPED;
    SetServiceStatus(this.ServiceHandle, ref serviceStatus);
    
    ' Update the service state to Stop Pending.
    Dim serviceStatus As ServiceStatus = New ServiceStatus()
    serviceStatus.dwCurrentState = ServiceState.SERVICE_STOP_PENDING
    serviceStatus.dwWaitHint = 100000
    SetServiceStatus(Me.ServiceHandle, serviceStatus)
    
    ' Update the service state to Stopped.
    serviceStatus.dwCurrentState = ServiceState.SERVICE_STOPPED
    SetServiceStatus(Me.ServiceHandle, serviceStatus)
    

向服务添加安装程序Add installers to the service

需要先安装 Windows 服务然后才能运行,这会将其注册到服务控制管理器。Before you run a Windows service, you need to install it, which registers it with the Service Control Manager. 将安装程序添加到项目以处理注册详细信息。Add installers to your project to handle the registration details.

  1. 在“解决方案资源管理器”中,从“MyNewService.cs”或“MyNewService.vb”的快捷菜单中,选择“查看设计器” 。In Solution Explorer, from the shortcut menu for MyNewService.cs, or MyNewService.vb, choose View Designer.

  2. 在“设计”视图中,选择背景区域,然后从快捷菜单中选择“添加安装程序” 。In the Design view, select the background area, then choose Add Installer from the shortcut menu.

    默认情况下,Visual Studio 会向项目中添加一个名为 ProjectInstaller 的组件类,其中包含两个安装程序。By default, Visual Studio adds a component class named ProjectInstaller, which contains two installers, to your project. 这些安装程序是为你的服务以及服务的相关过程准备的。These installers are for your service and for the service's associated process.

  3. 在“ProjectInstaller”的“设计”视图中,为 Visual C# 项目选择“serviceInstaller1”,或为 Visual Basic 项目选择“ServiceInstaller1”,然后选择快捷菜单中的“属性” 。In the Design view for ProjectInstaller, select serviceInstaller1 for a Visual C# project, or ServiceInstaller1 for a Visual Basic project, then choose Properties from the shortcut menu.

  4. 在“属性”窗口中,验证 ServiceName 属性是否已设置为“MyNewService” 。In the Properties window, verify the ServiceName property is set to MyNewService.

  5. 将文本添加到 Description 属性,例如“一个示例服务” 。Add text to the Description property, such as A sample service.

    此文本显示在“服务”窗口的“说明”列中,并向用户说明了该服务 。This text appears in the Description column of the Services window and describes the service to the user.

    “服务”窗口中的服务说明。Service description in the Services window.

  6. 将文本添加到 DisplayName 属性。Add text to the DisplayName property. 例如,“MyNewService 显示名称” 。For example, MyNewService Display Name.

    此文本显示在“服务”窗口的“显示名称”列中 。This text appears in the Display Name column of the Services window. 此名称可以不同于 ServiceName 属性,它是系统使用的名称(例如,用于启动服务的 net start 命令的名称)。This name can be different from the ServiceName property, which is the name the system uses (for example, the name you use for the net start command to start your service).

  7. 从下拉列表中将 StartType 属性设置为 AutomaticSet the StartType property to Automatic from the drop-down list.

  8. 完成后,“属性”窗口应如下图所示 :When you're finished, the Properties windows should look like the following figure:

    Windows 服务的安装程序属性Installer Properties for a Windows service

  9. 在“ProjectInstaller”的“设计”视图中,为 Visual C# 项目选择“serviceProcessInstaller1”,或为 Visual Basic 项目选择“serviceProcessInstaller1”,然后选择快捷菜单中的“属性” 。In the Design view for ProjectInstaller, choose serviceProcessInstaller1 for a Visual C# project, or ServiceProcessInstaller1 for a Visual Basic project, then choose Properties from the shortcut menu. 从下拉列表中将 Account 属性设置为 LocalSystemSet the Account property to LocalSystem from the drop-down list.

    此设置将安装服务并使用本地系统帐户运行它。This setting installs the service and runs it by using the local system account.

    重要

    LocalSystem 帐户具有广泛的权限,包括能够写入事件日志。The LocalSystem account has broad permissions, including the ability to write to the event log. 使用此帐户时要特别小心,因为它会增加你受到恶意软件攻击的风险。Use this account with caution, because it might increase your risk of attacks from malicious software. 对于其他任务,请考虑使用 LocalService 帐户,该帐户用作本地计算机上的非特权用户,并向任意远程服务器提供匿名凭据。For other tasks, consider using the LocalService account, which acts as a non-privileged user on the local computer and presents anonymous credentials to any remote server. 如果你尝试使用 LocalService 账户,此例子将失败,因为它需要写入事件日志的权限。This example fails if you try to use the LocalService account, because it needs permission to write to the event log.

有关安装程序的详细信息,请参阅如何:将安装程序添加到服务应用程序For more information about installers, see How to: Add installers to your service application.

(可选)设置启动参数(Optional) Set startup parameters

备注

在决定添加启动参数前,请考虑这是否是向你的服务传递信息的最好办法。Before you decide to add startup parameters, consider whether it's the best way to pass information to your service. 虽然它们易于使用和分析,而且用户可以轻松地替代它们,但是如果没有相关的文档说明,用户可能较难发现和使用它们。Although they're easy to use and parse, and a user can easily override them, they might be harder for a user to discover and use without documentation. 通常情况下,如果服务需要不止几个启动参数,则应改用注册表或配置文件。Generally, if your service requires more than just a few startup parameters, you should use the registry or a configuration file instead.

Windows 服务可以接受命令行参数或启动参数。A Windows service can accept command-line arguments, or startup parameters. 将代码添加到进程启动参数后,用户可以在服务属性窗口中使用自己的自定义启动参数启动服务。When you add code to process startup parameters, a user can start your service with their own custom startup parameters in the service properties window. 但是,这些启动参数不会保留到下一次服务启动。However, these startup parameters aren't persisted the next time the service starts. 若要永久设置启动参数,请在注册表中设置它们。To set startup parameters permanently, set them in the registry.

每个 Windows 服务在“HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services”子项下都有一个注册表项 。Each Windows service has a registry entry under the HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services subkey. 在每个服务的子项下,使用“参数”子项存储服务可以访问的信息 。Under each service's subkey, use the Parameters subkey to store information that your service can access. 你可以使用 Windows 服务的应用程序配置文件,与使用其他类型的程序一样。You can use application configuration files for a Windows service the same way you do for other types of programs. 有关示例代码,请参阅 ConfigurationManager.AppSettingsFor sample code, see ConfigurationManager.AppSettings.

添加启动参数To add startup parameters

  1. 选择“Program.cs”或“MyNewService.Designer.vb”,然后从快捷菜单中选择“查看代码” 。Select Program.cs, or MyNewService.Designer.vb, then choose View Code from the shortcut menu. Main 方法中,更改代码以添加输入参数并将其传递给服务构造函数:In the Main method, change the code to add an input parameter and pass it to the service constructor:

    static void Main(string[] args)
    {
        ServiceBase[] ServicesToRun;
        ServicesToRun = new ServiceBase[]
        {
            new MyNewService(args)
        };
        ServiceBase.Run(ServicesToRun);
    }
    
    Shared Sub Main(ByVal cmdArgs() As String)
        Dim ServicesToRun() As System.ServiceProcess.ServiceBase = New System.ServiceProcess.ServiceBase() {New MyNewService(cmdArgs)}
        System.ServiceProcess.ServiceBase.Run(ServicesToRun)
    End Sub
    
  2. 在“MyNewService.cs”或“MyNewService.vb”中,更改 MyNewService 构造函数以处理输入参数,如下所示 :In MyNewService.cs, or MyNewService.vb, change the MyNewService constructor to process the input parameter as follows:

    using System.Diagnostics;
    
    public MyNewService(string[] args)
    {
        InitializeComponent();
    
        string eventSourceName = "MySource";
        string logName = "MyNewLog";
    
        if (args.Length > 0)
        {
           eventSourceName = args[0];
        }
    
        if (args.Length > 1)
        {
            logName = args[1];
        }
    
        eventLog1 = new EventLog();
    
        if (!EventLog.SourceExists(eventSourceName))
        {
            EventLog.CreateEventSource(eventSourceName, logName);
        }
    
        eventLog1.Source = eventSourceName;
        eventLog1.Log = logName;
    }
    
    Imports System.Diagnostics
    
    Public Sub New(ByVal cmdArgs() As String)
        InitializeComponent()
        Dim eventSourceName As String = "MySource"
        Dim logName As String = "MyNewLog"
        If (cmdArgs.Count() > 0) Then
            eventSourceName = cmdArgs(0)
        End If
        If (cmdArgs.Count() > 1) Then
            logName = cmdArgs(1)
        End If
        eventLog1 = New EventLog()
        If (Not EventLog.SourceExists(eventSourceName)) Then
            EventLog.CreateEventSource(eventSourceName, logName)
        End If
        eventLog1.Source = eventSourceName
        eventLog1.Log = logName
    End Sub
    

    此代码根据用户提供的启动参数设置事件源和日志名称。This code sets the event source and log name according to the startup parameters that the user supplies. 如果未提供参数,则使用默认值。If no arguments are supplied, it uses default values.

  3. 若要指定命令行参数,请将以下代码添加到“ProjectInstaller.cs”或“ProjectInstaller.vb”中的 ProjectInstaller 类 :To specify the command-line arguments, add the following code to the ProjectInstaller class in ProjectInstaller.cs, or ProjectInstaller.vb:

    protected override void OnBeforeInstall(IDictionary savedState)
    {
        string parameter = "MySource1\" \"MyLogFile1";
        Context.Parameters["assemblypath"] = "\"" + Context.Parameters["assemblypath"] + "\" \"" + parameter + "\"";
        base.OnBeforeInstall(savedState);
    }
    
    Protected Overrides Sub OnBeforeInstall(ByVal savedState As IDictionary)
        Dim parameter As String = "MySource1"" ""MyLogFile1"
        Context.Parameters("assemblypath") = """" + Context.Parameters("assemblypath") + """ """ + parameter + """"
        MyBase.OnBeforeInstall(savedState)
    End Sub
    

    通常,此值包含 Windows 服务的可执行文件的完整路径。Typically, this value contains the full path to the executable for the Windows service. 要使服务正确启动,用户必须为路径和每个参数提供引号。For the service to start up correctly, the user must supply quotation marks for the path and each individual parameter. 用户可以更改“ImagePath”注册表项中的参数,以更改 Windows 服务的启动参数 。A user can change the parameters in the ImagePath registry entry to change the startup parameters for the Windows service. 但是,更好的方法是以编程方式更改值,并以用户友好的方式公开功能,例如使用管理或配置实用程序。However, a better way is to change the value programmatically and expose the functionality in a user-friendly way, such as by using a management or configuration utility.

生成服务Build the service

  1. 在“解决方案资源管理器”中,从“MyNewService”项目的快捷菜单中选择“属性” 。In Solution Explorer, choose Properties from the shortcut menu for the MyNewService project.

    项目的属性页面会显示出来。The property pages for your project appear.

  2. 在“应用程序”选项卡上,在“启动对象”列表中,为 Visual Basic 项目选择 “MyNewService.Program”“Sub Main”On the Application tab, in the Startup object list, choose MyNewService.Program, or Sub Main for Visual Basic projects.

  3. 要在“解决方案资源管理器”中生成项目,请从项目的快捷菜单中选择“生成”(或按 Ctrl+Shift+B) 。To build the project, in Solution Explorer, choose Build from the shortcut menu for your project (or press Ctrl+Shift+B).

安装服务Install the service

由于已经生成了 Windows 服务,你现在可以安装它。Now that you've built the Windows service, you can install it. 要安装 Windows 服务,必须在安装它的计算机上拥有管理员凭据。To install a Windows service, you must have administrator credentials on the computer where it's installed.

  1. 使用管理凭据打开“Visual Studio 开发人员命令提示”Open Developer Command Prompt for Visual Studio with administrative credentials. 从 Windows“开始”菜单中,在 Visual Studio 文件夹中选择“VS 2017 的开发人员命令提示”,然后从快捷菜单中选择“更多” > “以管理员身份运行” 。From the Windows Start menu, select Developer Command Prompt for VS 2017 in the Visual Studio folder, then select More > Run as Administrator from the shortcut menu.

  2. 在“Visual Studio 的开发人员命令提示”窗口中,导航到包含项目输出的文件夹(默认情况下,它是项目的 \bin\Debug 子目录) 。In the Developer Command Prompt for Visual Studio window, navigate to the folder that contains your project's output (by default, the \bin\Debug subdirectory of your project).

  3. 输入以下命令:Enter the following command:

    installutil MyNewService.exe
    

    如果服务成功安装,该命令将报告成功。If the service installs successfully, the command reports success.

    如果系统找不到 installutil.exe,请确保你的计算机上存在该安装程序 。If the system can't find installutil.exe, make sure that it exists on your computer. 此工具随 .NET Framework 安装在 %windir%\Microsoft.NET\Framework[64]\<framework version> 文件夹下 。This tool is installed with the .NET Framework to the folder %windir%\Microsoft.NET\Framework[64]\<framework version>. 例如,64 位版本的默认路径是 %windir%\Microsoft.NET\Framework64\v4.0.30319\InstallUtil.exe 。For example, the default path for the 64-bit version is %windir%\Microsoft.NET\Framework64\v4.0.30319\InstallUtil.exe.

    如果“installutil.exe”进程失败,请查看安装日志以找出原因 。If the installutil.exe process fails, check the install log to find out why. 默认情况下,该日志与服务可执行文件位于同一文件夹中。By default, the log is in the same folder as the service executable. 在以下情况下安装可能会失败:The installation can fail if:

    • ProjectInstaller 类中不存在 RunInstallerAttribute 类。The RunInstallerAttribute class isn't present on the ProjectInstaller class.
    • 该属性未设置为 trueThe attribute isn't set to true.
    • ProjectInstaller 类未定义为 publicThe ProjectInstaller class isn't defined as public.

有关详细信息,请参阅如何:安装和卸载服务For more information, see How to: Install and uninstall services.

启动并运行服务Start and run the service

  1. 在 Windows 中,打开 “服务”桌面应用程序。In Windows, open the Services desktop app. 按“Windows 徽标键+R”以打开“运行”框,然后输入 services.msc 并按 Enter 或单击“确定” 。Press Windows+R to open the Run box, enter services.msc, and then press Enter or select OK.

    你会看到 “服务”中列出的服务按其设置的显示名称的字母顺序显示。You should see your service listed in Services, displayed alphabetically by the display name that you set for it.

    服务窗口中的 MyNewService

  2. 若要启动该服务,请从服务的快捷菜单中选择“启动” 。To start the service, choose Start from the service's shortcut menu.

  3. 若要停止该服务,请从服务的快捷菜单中选择“停止” 。To stop the service, choose Stop from the service's shortcut menu.

  4. (可选)可在命令行使用“net start<服务名称>”和“net stop<服务名称>”来启动和停止服务 。(Optional) From the command line, use the commands net start <service name> and net stop <service name> to start and stop your service.

验证服务的事件日志输出Verify the event log output of your service

  1. 在 Windows 中,打开“事件查看器”桌面应用 。In Windows, open the Event Viewer desktop app. 在 Windows 搜索栏中输入事件查看器,然后从搜索结果中选择“事件查看器” 。Enter Event Viewer in the Windows search bar, and then select Event Viewer from the search results.

    提示

    在 Visual Studio 中,可通过从“查看”菜单(或按 Ctrl+Alt+S)打开“服务器资源管理器”并展开本地计算机的“事件日志”节点来访问事件日志 。In Visual Studio, you can access event logs by opening Server Explorer from the View menu (or press Ctrl+Alt+S) and expanding the Event Logs node for the local computer.

  2. 在 “事件查看器”中,展开“应用程序和服务日志” 。In Event Viewer, expand Applications and Services Logs.

  3. 找到“MyNewLog”(如果按照过程来添加命令行参数,则找到“MyLogFile1”)列表并将其展开 。Locate the listing for MyNewLog (or MyLogFile1 if you followed the procedure to add command-line arguments) and expand it. 你会看到你的服务所执行的两个操作(启动和停止)的条目。You should see the entries for the two actions (start and stop) that your service performed.

    使用事件查看器查看事件日志条目

清理资源Clean up resources

如果不再需要 Windows 服务应用,则可以将其删除。If you no longer need the Windows service app, you can remove it.

  1. 使用管理凭据打开 “Visual Studio 开发人员命令提示”Open Developer Command Prompt for Visual Studio with administrative credentials.

  2. 在“Visual Studio 的开发人员命令提示”窗口中,导航到包含项目输出的文件夹 。In the Developer Command Prompt for Visual Studio window, navigate to the folder that contains your project's output.

  3. 输入以下命令:Enter the following command:

    installutil.exe /u MyNewService.exe
    

    如果服务成功卸载,该命令将报告已成功删除服务。If the service uninstalls successfully, the command reports that your service was successfully removed. 有关详细信息,请参阅如何:安装和卸载服务For more information, see How to: Install and uninstall services.

后续步骤Next steps

创建服务后,现在可以:Now that you've created the service, you can:

  • 为其他人创建一个独立的安装程序,用于安装 Windows 服务。Create a standalone setup program for others to use to install your Windows service. 使用 WiX 工具集为 Windows 服务创建安装程序。Use the WiX Toolset to create an installer for a Windows service. 有关其他提示,请参阅创建安装程序包For other ideas, see Create an installer package.

  • 探索 ServiceController 组件,以便将命令发送到已安装的服务。Explore the ServiceController component, which enables you to send commands to the service you've installed.

  • 不是在应用程序运行时创建事件日志,而是在安装应用程序时使用安装程序创建事件日志。Instead of creating the event log when the application runs, use an installer to create an event log when you install the application. 卸载应用程序时,安装程序将删除事件日志。The event log is deleted by the installer when you uninstall the application. 有关详细信息,请参阅 EventLogInstallerFor more information, see EventLogInstaller.

请参阅See also