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<OsString>).

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 windowsservice::servicedispatcher;

definewindowsservice!(ffiservicemain, myservicemain);

fn myservicemain(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<(), windowsservice::Error> { // Register generated ffi_service_main with the system and start the service, blocking // this thread until the service is stopped. servicedispatcher::start("myservice", ffiservicemain)?; 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 windowsservice::service::ServiceControl; use windowsservice::servicecontrolhandler::{self, ServiceControlHandlerResult};

fn myservicemain(arguments: Vec) { if let Err(e) = runservice(arguments) { // Handle errors in some way. } }

fn runservice(arguments: Vec) -> Result<(), windowsservice::Error> { let eventhandler = move |controlevent| -> 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:\ https://msdn.microsoft.com/en-us/library/windows/desktop/ms685149(v=vs.85).aspx

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 windowsservice::service::{ ServiceControl, ServiceControlAccept, ServiceExitCode, ServiceState, ServiceStatus, ServiceType, }; use windowsservice::servicecontrolhandler::{self, ServiceControlHandlerResult};

fn myservicemain(arguments: Vec) { if let Err(e) = runservice(arguments) { // Handle error in some way. } }

fn runservice(arguments: Vec) -> windowsservice::Result<()> { let eventhandler = move |controlevent| -> 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:\ https://msdn.microsoft.com/en-us/library/windows/desktop/ee126211(v=vs.85).aspx

License: MIT/Apache-2.0