# windows-service A crate that provides facilities for management and implementation of windows services. ## Implementing windows service This section describes the steps of implementing a program that runs as a windows service, for complete source code of such program take a look at examples folder. ### Basics Each windows service has to implement a service entry function `fn(argc: u32, argv: *mut *mut u16)` and register it with the system from the application's `main`. This crate provides a handy [`define_windows_service!`] macro to generate a low level boilerplate for the service entry function that parses input from the system and delegates handling to user defined higher level function `fn(arguments: Vec)`. This guide references the low level entry function as `ffi_service_main` and higher level function as `my_service_main` but it's up to developer how to call them. ```rust #[macro_use] extern crate windows_service; use std::ffi::OsString; use windows_service::service_dispatcher; define_windows_service!(ffi_service_main, my_service_main); fn my_service_main(arguments: Vec) { // The entry point where execution will start on a background thread after a call to // `service_dispatcher::start` from `main`. } fn main() -> Result<(), windows_service::Error> { // Register generated `ffi_service_main` with the system and start the service, blocking // this thread until the service is stopped. service_dispatcher::start("myservice", ffi_service_main)?; Ok(()) } ``` ### Handling service events The first thing that a windows service should do early in its lifecycle is to subscribe for service events such as stop or pause and many other. ```rust extern crate windows_service; use std::ffi::OsString; use windows_service::service::ServiceControl; use windows_service::service_control_handler::{self, ServiceControlHandlerResult}; fn my_service_main(arguments: Vec) { if let Err(_e) = run_service(arguments) { // Handle errors in some way. } } fn run_service(arguments: Vec) -> Result<(), windows_service::Error> { let event_handler = move |control_event| -> ServiceControlHandlerResult { match control_event { ServiceControl::Stop => { // Handle stop event and return control back to the system. ServiceControlHandlerResult::NoError } // All services must accept Interrogate even if it's a no-op. ServiceControl::Interrogate => ServiceControlHandlerResult::NoError, _ => ServiceControlHandlerResult::NotImplemented, } }; // Register system service event handler let status_handle = service_control_handler::register("myservice", event_handler)?; Ok(()) } ``` Please see the corresponding MSDN article that describes how event handler works internally:\ ### Updating service status When application that implements a windows service is launched by the system, it's automatically put in the [`StartPending`] state. The application needs to complete the initialization, obtain [`ServiceStatusHandle`] (see [`service_control_handler::register`]) and transition to [`Running`] state. If service has a lengthy initialization, it should immediately tell the system how much time it needs to complete it, by sending the [`StartPending`] state, time estimate using [`ServiceStatus::wait_hint`] and increment [`ServiceStatus::checkpoint`] each time the service completes a step in initialization. The system will attempt to kill a service that is not able to transition to [`Running`] state before the proposed [`ServiceStatus::wait_hint`] expired. The same concept applies when transitioning between other pending states and their corresponding target states. Note that it's safe to clone [`ServiceStatusHandle`] and use it from any thread. ```rust extern crate windows_service; use std::ffi::OsString; use std::time::Duration; use windows_service::service::{ ServiceControl, ServiceControlAccept, ServiceExitCode, ServiceState, ServiceStatus, ServiceType, }; use windows_service::service_control_handler::{self, ServiceControlHandlerResult}; fn my_service_main(arguments: Vec) { if let Err(_e) = run_service(arguments) { // Handle error in some way. } } fn run_service(arguments: Vec) -> windows_service::Result<()> { let event_handler = move |control_event| -> ServiceControlHandlerResult { match control_event { ServiceControl::Stop | ServiceControl::Interrogate => { ServiceControlHandlerResult::NoError } _ => ServiceControlHandlerResult::NotImplemented, } }; // Register system service event handler let status_handle = service_control_handler::register("my_service_name", event_handler)?; let next_status = ServiceStatus { // Should match the one from system service registry service_type: ServiceType::OWN_PROCESS, // The new state current_state: ServiceState::Running, // Accept stop events when running controls_accepted: ServiceControlAccept::STOP, // Used to report an error when starting or stopping only, otherwise must be zero exit_code: ServiceExitCode::Win32(0), // Only used for pending states, otherwise must be zero checkpoint: 0, // Only used for pending states, otherwise must be zero wait_hint: Duration::default(), }; // Tell the system that the service is running now status_handle.set_service_status(next_status)?; // Do some work Ok(()) } ``` Please refer to the "Service State Transitions" article on MSDN for more info:\ [`ServiceStatusHandle`]: service_control_handler::ServiceStatusHandle [`ServiceStatus::wait_hint`]: service::ServiceStatus::wait_hint [`ServiceStatus::checkpoint`]: service::ServiceStatus::checkpoint [`StartPending`]: service::ServiceState::StartPending [`Running`]: service::ServiceState::Running License: MIT/Apache-2.0