use std::ffi::{OsStr, OsString};
use std::{io, ptr};
use widestring::{WideCStr, WideCString};
use windows_sys::Win32::System::Services;
use crate::{Error, Result};
#[macro_export]
macro_rules! define_windows_service {
($function_name:ident, $service_main_handler:ident) => {
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);
}
};
}
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::ArgumentHasNulByte("service name"))?;
let service_table: &[Services::SERVICE_TABLE_ENTRYW] = &[
Services::SERVICE_TABLE_ENTRYW {
lpServiceName: service_name.as_ptr() as _,
lpServiceProc: Some(service_main),
},
Services::SERVICE_TABLE_ENTRYW {
lpServiceName: ptr::null_mut(),
lpServiceProc: None,
},
];
let result = unsafe { Services::StartServiceCtrlDispatcherW(service_table.as_ptr()) };
if result == 0 {
Err(Error::Winapi(io::Error::last_os_error()))
} else {
Ok(())
}
}
#[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()
}