1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
use std::ffi::{OsStr, OsString}; use std::{io, ptr}; use widestring::{WideCStr, WideCString}; use winapi::um::winsvc; use crate::{Error, Result}; /// A macro to generate an entry point function (aka "service_main") for Windows service. /// /// The `$function_name` function parses service arguments provided by the system /// and passes them with a call to `$service_main_handler`. /// /// `$function_name` - name of the "service_main" callback. /// /// `$service_main_handler` - function with a signature `fn(Vec<OsString>)` that's called from /// generated `$function_name`. Accepts parsed service arguments as `Vec<OsString>`. Its /// responsibility is to create a `ServiceControlHandler`, start processing control events and /// report the service status to the system. /// /// # Example /// /// ```rust,no_run /// #[macro_use] /// extern crate windows_service; /// /// use std::ffi::OsString; /// /// define_windows_service!(ffi_service_main, my_service_main); /// /// fn my_service_main(arguments: Vec<OsString>) { /// // Service entry point /// } /// /// # fn main() {} /// ``` #[macro_export] macro_rules! define_windows_service { ($function_name:ident, $service_main_handler:ident) => { /// Static callback used by the system to bootstrap the service. /// Do not call it directly. extern "system" fn $function_name( num_service_arguments: u32, service_arguments: *mut *mut u16, ) { let arguments = unsafe { $crate::service_dispatcher::parse_service_arguments( num_service_arguments, service_arguments, ) }; $service_main_handler(arguments); } }; } /// Start service control dispatcher. /// /// Once started the service control dispatcher blocks the current thread execution /// until the service is stopped. /// /// Upon successful initialization, system calls the `service_main` on background thread. /// /// On failure: immediately returns an error, no threads are spawned. /// /// # Example /// /// ```rust,no_run /// #[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<OsString>) { /// // The entry point where execution will start on a background thread after a call to /// // `service_dispatcher::start` from `main`. /// } /// /// fn main() -> windows_service::Result<()> { /// // 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(()) /// } /// ``` pub fn start( service_name: impl AsRef<OsStr>, service_main: extern "system" fn(u32, *mut *mut u16), ) -> Result<()> { let service_name = WideCString::from_os_str(service_name).map_err(Error::InvalidServiceName)?; let service_table: &[winsvc::SERVICE_TABLE_ENTRYW] = &[ winsvc::SERVICE_TABLE_ENTRYW { lpServiceName: service_name.as_ptr(), lpServiceProc: Some(service_main), }, // the last item has to be { null, null } winsvc::SERVICE_TABLE_ENTRYW { lpServiceName: ptr::null(), lpServiceProc: None, }, ]; let result = unsafe { winsvc::StartServiceCtrlDispatcherW(service_table.as_ptr()) }; if result == 0 { Err(Error::Winapi(io::Error::last_os_error())) } else { Ok(()) } } /// Parse raw arguments received in `service_main` into `Vec<OsString>`. /// /// This is an implementation detail and *should not* be called directly! #[doc(hidden)] pub unsafe fn parse_service_arguments(argc: u32, argv: *mut *mut u16) -> Vec<OsString> { (0..argc) .map(|i| { let array_element_ptr: *mut *mut u16 = argv.offset(i as isize); WideCStr::from_ptr_str(*array_element_ptr).to_os_string() }) .collect() }