Tutorial: Criar uma aplicação do serviço Windows
Aviso
Esta documentação não se aplica à versão mais recente do Serviço Windows. Para obter os conteúdos mais recentes sobre os Serviços Windows que utilizam BackgroundService e o modelo de Serviço de Trabalho, consulte:
Este artigo demonstra como criar uma aplicação do serviço Windows no Visual Studio que escreve mensagens num registo de eventos.
Criar um serviço
Para começar, crie o projeto e defina os valores necessários para que o serviço funcione corretamente.
No menu Ficheiro do Visual Studio, selecione Novo>Projeto (ou prima Ctrl+Shift+N) para abrir a janela Novo Projeto .
Localize e selecione o modelo de projeto do Serviço Windows (.NET Framework).
Nota
Se não vir o modelo do Serviço Windows , poderá ter de instalar a carga de trabalho de desenvolvimento de ambiente de trabalho .NET com o Instalador do Visual Studio.
Em Nome, introduza MyNewService e, em seguida, selecione OK.
É apresentado o separador Estrutura (Service1.cs [Estrutura] ou Service1.vb [Estrutura]).
O modelo de projeto inclui uma classe de componente com o nome
Service1
que herda de System.ServiceProcess.ServiceBase. Inclui grande parte do código de serviço básico, como o código para iniciar o serviço.
Mudar o nome do serviço
Mude o nome do serviço de Service1 para MyNewService.
No Explorador de Soluções, selecione Service1.cs ou Service1.vb e selecione Mudar o Nome no menu de atalho. Mude o nome do ficheiro para MyNewService.cs ou MyNewService.vb e, em seguida, prima Enter
É apresentada uma janela de pop-up a perguntar se pretende mudar o nome de todas as referências para o elemento de código Service1.
Na janela de pop-up, selecione Sim.
de
No separador Estrutura , selecione Propriedades no menu de atalho. Na janela Propriedades , altere o valor ServiceName para MyNewService.
do
Selecione Guardar Tudo no menu Ficheiro .
Adicionar funcionalidades ao serviço
Nesta secção, vai adicionar um registo de eventos personalizado ao serviço Windows. O EventLog componente é um exemplo do tipo de componente que pode adicionar a um serviço Windows.
Adicionar funcionalidade de registo de eventos personalizada
No Explorador de Soluções, no menu de atalho para MyNewService.cs ou MyNewService.vb, selecione Ver Designer.
Na Caixa de Ferramentas, expanda Componentes e, em seguida, arraste o componente EventLog para o separador Service1.cs [Estrutura] ou Service1.vb [Estrutura ].
No Explorador de Soluções, no menu de atalho para MyNewService.cs ou MyNewService.vb, selecione Ver Código.
Definir um registo de eventos personalizado.
Para C#, edite o construtor existente
MyNewService()
, conforme mostrado no fragmento de código seguinte. Para o Visual Basic, adicione oNew()
construtor conforme mostrado no fragmento de código seguinte.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
Adicione uma
using
instrução a MyNewService.cs (se ainda não existir) ou uma instruçãoImports
para MyNewService.vb, para o System.Diagnostics espaço de nomes:using System.Diagnostics;
Imports System.Diagnostics
Selecione Guardar Tudo no menu Ficheiro .
Definir o que ocorre quando o serviço é iniciado
No editor de código de MyNewService.cs ou MyNewService.vb, localize o OnStart método. O Visual Studio criou automaticamente uma definição de método vazia quando criou o projeto. Adicione código que escreve uma entrada no registo de eventos quando o serviço é iniciado:
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
Consultas
Uma vez que uma aplicação de serviço foi concebida para ser de execução prolongada, normalmente consulta ou monitoriza o sistema, que configurou no OnStart método. O OnStart
método tem de regressar ao sistema operativo após o início da operação do serviço para que o sistema não seja bloqueado.
Para configurar um mecanismo de consulta simples, utilize o System.Timers.Timer componente. O temporizador gera um Elapsed evento em intervalos regulares, altura em que o seu serviço pode fazer a respetiva monitorização. Utilize o componente da Timer seguinte forma:
- Defina as propriedades do Timer componente no
MyNewService.OnStart
método . - Inicie o temporizador ao chamar o Start método.
Configurar o mecanismo de consulta
Adicione uma
using
instrução a MyNewService.cs ou uma instruçãoImports
a MyNewService.vb para o System.Timers espaço de nomes:using System.Timers;
Imports System.Timers
Adicione o seguinte código no
MyNewService.OnStart
evento para configurar o mecanismo de consulta:// 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()
MyNewService
Na classe, adicione uma variável de membro. Contém o identificador do evento seguinte para escrever no registo de eventos:private int eventId = 1;
Private eventId As Integer = 1
MyNewService
Na classe, adicione oOnTimer
método para processar o Timer.Elapsed evento: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
Em vez de executar todo o seu trabalho no thread principal, pode executar tarefas com threads de trabalho em segundo plano. Para obter mais informações, consulte System.ComponentModel.BackgroundWorker.
Definir o que ocorre quando o serviço é parado
Insira uma linha de código no OnStop método que adiciona uma entrada ao registo de eventos quando o serviço é parado:
protected override void OnStop()
{
eventLog1.WriteEntry("In OnStop.");
}
Protected Overrides Sub OnStop()
EventLog1.WriteEntry("In OnStop.")
End Sub
Definir outras ações para o serviço
Pode substituir os OnPausemétodos , OnContinuee OnShutdown para definir o processamento adicional para o seu componente.
O código seguinte mostra como pode substituir o OnContinue método na MyNewService
classe:
protected override void OnContinue()
{
eventLog1.WriteEntry("In OnContinue.");
}
Protected Overrides Sub OnContinue()
EventLog1.WriteEntry("In OnContinue.")
End Sub
Definir o estado do serviço
Os serviços comunicam o respetivo estado ao Service Control Manager para que um utilizador possa saber se um serviço está a funcionar corretamente. Por predefinição, um serviço que herda dos ServiceBase relatórios um conjunto limitado de definições de estado, que incluem SERVICE_STOPPED, SERVICE_PAUSED e SERVICE_RUNNING. Se um serviço demorar algum tempo a iniciar, é útil comunicar um estado de SERVICE_START_PENDING.
Pode implementar as definições de estado SERVICE_START_PENDING e SERVICE_STOP_PENDING ao adicionar código que chama a função Windows SetServiceStatus .
Implementar o estado pendente do serviço
Adicione uma
using
instrução a MyNewService.cs ou uma instruçãoImports
a MyNewService.vb para o System.Runtime.InteropServices espaço de nomes:using System.Runtime.InteropServices;
Imports System.Runtime.InteropServices
Adicione o seguinte código a MyNewService.cs ou MyNewService.vb para declarar os
ServiceState
valores e adicionar uma estrutura para o estado, que irá utilizar numa chamada de invocação de plataforma: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
Nota
O Service Control Manager utiliza os
dwWaitHint
membros edwCheckpoint
da estrutura SERVICE_STATUS para determinar quanto tempo esperar que um serviço windows inicie ou encerre. Se os seusOnStart
métodos eOnStop
forem longos, o seu serviço pode pedir mais tempo ao chamarSetServiceStatus
novamente com um valor incrementadodwCheckPoint
.MyNewService
Na classe, declare a função SetServiceStatus com a invocação da plataforma:[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
Para implementar o estado SERVICE_START_PENDING, adicione o seguinte código ao início do OnStart método:
// 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)
Adicione código ao final do
OnStart
método para definir o estado como 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)
(Opcional) Se OnStop for um método de execução prolongada, repita este procedimento no
OnStop
método . Implemente o estado do SERVICE_STOP_PENDING e devolva o estado do SERVICE_STOPPED antes de oOnStop
método sair.Por exemplo:
// 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)
Adicionar instaladores ao serviço
Antes de executar um serviço Windows, tem de instalá-lo, o que o regista no Service Control Manager. Adicione instaladores ao seu projeto para processar os detalhes de registo.
No Explorador de Soluções, no menu de atalho para MyNewService.cs ou MyNewService.vb, selecione Ver Designer.
Na vista Estrutura , selecione a área de fundo e, em seguida, selecione Adicionar Instalador no menu de atalho.
Por predefinição, o Visual Studio adiciona uma classe de componente com o nome
ProjectInstaller
, que contém dois instaladores, ao seu projeto. Estes instaladores destinam-se ao seu serviço e ao processo associado do serviço.Na vista Estrutura do ProjectInstaller, selecione serviceInstaller1 para um projeto Visual C# ou ServiceInstaller1 para um projeto do Visual Basic e, em seguida, selecione Propriedades no menu de atalho.
Na janela Propriedades , verifique se a ServiceName propriedade está definida como MyNewService.
Adicione texto à Description propriedade, como Um serviço de exemplo.
Este texto aparece na coluna Descrição da janela Serviços e descreve o serviço ao utilizador.
Adicione texto à DisplayName propriedade. Por exemplo, Nome a Apresentar MyNewService.
Este texto aparece na coluna Nome a Apresentar da janela Serviços . Este nome pode ser diferente da ServiceName propriedade , que é o nome que o sistema utiliza (por exemplo, o nome que utiliza para o comando iniciar o
net start
serviço).Defina a StartType propriedade como Automatic a partir da lista pendente.
Quando tiver terminado, as janelas Propriedades deverão ter o seguinte aspeto:
Na vista Estrutura do ProjectInstaller, selecione serviceProcessInstaller1 para um projeto visual C# ou ServiceProcessInstaller1 para um projeto do Visual Basic e, em seguida, selecione Propriedades no menu de atalho. Defina a Account propriedade como LocalSystem a partir da lista pendente.
Esta definição instala o serviço e executa-o com a conta do sistema local.
Importante
A LocalSystem conta tem permissões abrangentes, incluindo a capacidade de escrever no registo de eventos. Utilize esta conta com cuidado, uma vez que pode aumentar o risco de ataques de software malicioso. Para outras tarefas, considere utilizar a LocalService conta, que atua como um utilizador sem privilégios no computador local e apresenta credenciais anónimas a qualquer servidor remoto. Este exemplo falha se tentar utilizar a LocalService conta, porque precisa de permissão para escrever no registo de eventos.
Para obter mais informações sobre os instaladores, veja Como: Adicionar instaladores à sua aplicação de serviço.
(Opcional) Definir parâmetros de arranque
Nota
Antes de decidir adicionar parâmetros de arranque, considere se é a melhor forma de transmitir informações ao seu serviço. Embora sejam fáceis de utilizar e analisar e um utilizador possa facilmente substitui-los, poderá ser mais difícil para um utilizador descobrir e utilizar sem documentação. Geralmente, se o seu serviço necessitar de mais do que apenas alguns parâmetros de arranque, deve utilizar o registo ou um ficheiro de configuração.
Um serviço Windows pode aceitar argumentos da linha de comandos ou parâmetros de arranque. Quando adiciona código para processar parâmetros de arranque, um utilizador pode iniciar o seu serviço com os seus próprios parâmetros de arranque personalizados na janela de propriedades do serviço. No entanto, estes parâmetros de arranque não são mantidos da próxima vez que o serviço for iniciado. Para definir parâmetros de arranque permanentemente, defina-os no registo.
Cada serviço Windows tem uma entrada de registo na subchave HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services . Na subchave de cada serviço, utilize a subchave Parameters (Parâmetros ) para armazenar as informações a que o serviço pode aceder. Pode utilizar ficheiros de configuração de aplicações para um serviço Windows da mesma forma que utiliza para outros tipos de programas. Para obter o código de exemplo, consulte ConfigurationManager.AppSettings.
Para adicionar parâmetros de arranque
Selecione Program.cs ou MyNewService.Designer. vb e, em seguida, selecione Ver Código no menu de atalho.
Main
No método , altere o código para adicionar um parâmetro de entrada e transmita-o para o construtor de serviços: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
Em MyNewService.cs ou MyNewService.vb, altere o
MyNewService
construtor para processar o parâmetro de entrada da seguinte forma: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
Este código define a origem do evento e o nome do registo de acordo com os parâmetros de arranque fornecidos pelo utilizador. Se não forem fornecidos argumentos, utiliza valores predefinidos.
Para especificar os argumentos da linha de comandos, adicione o seguinte código à
ProjectInstaller
classe em ProjectInstaller.cs ou 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
Normalmente, este valor contém o caminho completo para o executável do serviço Windows. Para que o serviço seja iniciado corretamente, o utilizador tem de fornecer aspas para o caminho e cada parâmetro individual. Um utilizador pode alterar os parâmetros na entrada de registo ImagePath para alterar os parâmetros de arranque do serviço Windows. No entanto, uma forma melhor é alterar o valor através de programação e expor a funcionalidade de uma forma amigável, como através de um utilitário de gestão ou configuração.
Criar o serviço
No Explorador de Soluções, selecione Propriedades no menu de atalho do projeto MyNewService .
São apresentadas as páginas de propriedades do projeto.
No separador Aplicação , na lista Objeto de arranque , selecione MyNewService.Program ou Sub Main para projetos do Visual Basic.
Para criar o projeto, no Explorador de Soluções, selecione Compilar no menu de atalho do projeto (ou prima Ctrl+Shift+B).
Instalar o serviço
Agora que criou o serviço Windows, pode instalá-lo. Para instalar um serviço Windows, tem de ter credenciais de administrador no computador onde está instalado.
Abra a Linha de Comandos do Programador para Visual Studio com credenciais administrativas.
Na Linha de Comandos do Programador para Visual Studio, navegue para a pasta que contém a saída do projeto (por predefinição, o subdiretório \bin\Debug do projeto).
Introduza o seguinte comando:
installutil MyNewService.exe
Se o serviço for instalado com êxito, o comando comunica com êxito.
Se o sistema não conseguir encontrar installutil.exe, certifique-se de que existe no seu computador. Esta ferramenta é instalada com o .NET Framework para a pasta %windir%\Microsoft.NET\Framework[64]\<framework version>. Por exemplo, o caminho predefinido para a versão de 64 bits é %windir%\Microsoft.NET\Framework64\v4.0.30319\InstallUtil.exe.
Se o processo deinstallutil.exe falhar, verifique o registo de instalação para saber porquê. Por predefinição, o registo está na mesma pasta que o executável do serviço. A instalação pode falhar se:
- A RunInstallerAttribute classe não está presente na
ProjectInstaller
turma. - O atributo não está definido como
true
. - A
ProjectInstaller
classe não está definida comopublic
.
- A RunInstallerAttribute classe não está presente na
Para obter mais informações, veja Como: Instalar e desinstalar serviços.
Iniciar e executar o serviço
No Windows, abra a aplicação Serviços de ambiente de trabalho. Prima Windows+R para abrir a caixa Executar , introduza services.msc e, em seguida, prima Enter ou selecione OK.
Deverá ver o seu serviço listado em Serviços, apresentado alfabeticamente pelo nome a apresentar que definiu para o mesmo.
Para iniciar o serviço, selecione Iniciar no menu de atalho do serviço.
Para parar o serviço, selecione Parar no menu de atalho do serviço.
(Opcional) A partir da linha de comandos, utilize os comandos net start <service name> e net stop <service name> para iniciar e parar o seu serviço.
Verificar a saída do registo de eventos do seu serviço
No Windows, abra a aplicação de ambiente de trabalho Visualizador de Eventos. Introduza Visualizador de Eventos na barra de pesquisa do Windows e, em seguida, selecione Visualizador de Eventos nos resultados da pesquisa.
Dica
No Visual Studio, pode aceder aos registos de eventos ao abrir o Explorador de Servidores no menu Ver (ou premir Ctrl+Alt+S) e expandir o nó Registos de Eventos do computador local.
No Visualizador de Eventos, expanda Registos de Aplicações e Serviços.
Localize a listagem para MyNewLog (ou MyLogFile1 se seguiu o procedimento para adicionar argumentos da linha de comandos) e expanda-a. Deverá ver as entradas das duas ações (iniciar e parar) que o serviço realizou.
Limpar os recursos
Se já não precisar da aplicação do serviço Windows, pode removê-la.
Abra a Linha de Comandos do Programador para Visual Studio com credenciais administrativas.
Na janela Linha de Comandos do Programador para Visual Studio , navegue para a pasta que contém a saída do projeto.
Introduza o seguinte comando:
installutil.exe /u MyNewService.exe
Se o serviço for desinstalado com êxito, o comando comunica que o seu serviço foi removido com êxito. Para obter mais informações, veja Como: Instalar e desinstalar serviços.
Passos seguintes
Agora que criou o serviço, pode:
Crie um programa de configuração autónomo para que outras pessoas utilizem para instalar o seu serviço Windows. Utilize o WiX Toolset para criar um instalador para um serviço Windows. Para outras ideias, consulte Criar um pacote de instalação.
Explore o ServiceController componente, que lhe permite enviar comandos para o serviço que instalou.
Em vez de criar o registo de eventos quando a aplicação é executada, utilize um instalador para criar um registo de eventos quando instalar a aplicação. O registo de eventos é eliminado pelo instalador quando desinstala a aplicação. Para obter mais informações, consulte EventLogInstaller.