1use std::fmt::Display;
6use widestring::U16CString;
7use windows_sys::Win32::{
8 Foundation::{ERROR_INSUFFICIENT_BUFFER, FALSE},
9 Security::SC_HANDLE,
10 System::Services::{
11 ChangeServiceConfigW, CloseServiceHandle, ControlService, DeleteService,
12 QueryServiceConfigW, QueryServiceStatus, StartServiceW, QUERY_SERVICE_CONFIGW,
13 SERVICE_ADAPTER, SERVICE_AUTO_START, SERVICE_BOOT_START, SERVICE_CONTINUE_PENDING,
14 SERVICE_CONTROL_PAUSE, SERVICE_CONTROL_STOP, SERVICE_DEMAND_START, SERVICE_DISABLED,
15 SERVICE_FILE_SYSTEM_DRIVER, SERVICE_KERNEL_DRIVER, SERVICE_PAUSED, SERVICE_PAUSE_PENDING,
16 SERVICE_RECOGNIZER_DRIVER, SERVICE_RUNNING, SERVICE_START_PENDING, SERVICE_STATUS,
17 SERVICE_STOPPED, SERVICE_STOP_PENDING, SERVICE_SYSTEM_START, SERVICE_WIN32_OWN_PROCESS,
18 SERVICE_WIN32_SHARE_PROCESS,
19 },
20};
21
22use crate::{
23 common::get_last_error,
24 error::{ControlServiceError, DeleteServiceError, QueryServiceError, UpdateServiceError},
25 service_manager::ServiceConfig,
26};
27
28#[derive(Default, Debug)]
30pub struct ServiceHandle {
31 handle: Option<SC_HANDLE>,
32}
33
34#[repr(u32)]
36#[derive(Default, Clone, Copy, Debug, PartialEq)]
37pub enum ServiceErrorControl {
38 ErrorCritical = 0x00000003,
39 ErrorIgnore = 0x00000000,
40 #[default]
41 ErrorNormal = 0x00000001,
42 ErrorSevere = 0x00000002,
43}
44
45#[repr(u32)]
47#[derive(Default, Clone, Copy, Debug, PartialEq)]
48pub enum ServiceStartType {
49 AutoStart = 0x00000002,
50 BootStart = 0x00000000,
51 #[default]
52 DemandStart = 0x00000003,
53 Disabled = 0x00000004,
54 SystemStart = 0x00000001,
55}
56
57#[repr(u32)]
59#[derive(Default, Clone, Copy, Debug, PartialEq)]
60pub enum ServiceType {
61 Adapter = 0x00000004,
62 FileSystemDriver = 0x00000002,
63 #[default]
64 KernelDriver = 0x00000001,
65 RecognizerDriver = 0x00000008,
66 Win32OwnProcess = 0x00000010,
67 Win32ShareProcess = 0x00000020,
68}
69
70#[repr(u32)]
72#[derive(Debug, Clone, PartialEq)]
73pub enum ServiceState {
74 Stopped = 1,
75 StartPending,
76 StopPending,
77 Running,
78 ContinuePending,
79 PausePending,
80 Paused,
81}
82
83impl Display for ServiceType {
84 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
85 match *self {
86 Self::Adapter => write!(f, "Adapter"),
87 Self::FileSystemDriver => write!(f, "FileSystemDriver"),
88 Self::KernelDriver => write!(f, "KernelDriver"),
89 Self::RecognizerDriver => write!(f, "RecognizerDriver"),
90 Self::Win32OwnProcess => write!(f, "Win32OwnProcess"),
91 Self::Win32ShareProcess => write!(f, "Win32ShareProcess"),
92 }
93 }
94}
95
96impl Display for ServiceState {
97 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
98 match *self {
99 Self::Stopped => write!(f, "Stopped"),
100 Self::StartPending => write!(f, "StartPending"),
101 Self::StopPending => write!(f, "StopPending"),
102 Self::Running => write!(f, "Running"),
103 Self::ContinuePending => write!(f, "ContinuePending"),
104 Self::PausePending => write!(f, "PausePending"),
105 Self::Paused => write!(f, "Paused"),
106 }
107 }
108}
109
110impl Display for ServiceHandle {
111 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
112 let _ = writeln!(f, "StartType: {:?}", self.get_start_type());
113 let _ = writeln!(f, "State: {:?}", self.state());
114 Ok(())
115 }
116}
117
118impl TryFrom<u32> for ServiceType {
119 type Error = QueryServiceError;
120
121 fn try_from(value: u32) -> Result<Self, Self::Error> {
122 match value {
123 SERVICE_ADAPTER => Ok(ServiceType::Adapter),
124 SERVICE_FILE_SYSTEM_DRIVER => Ok(ServiceType::FileSystemDriver),
125 SERVICE_KERNEL_DRIVER => Ok(ServiceType::KernelDriver),
126 SERVICE_RECOGNIZER_DRIVER => Ok(ServiceType::RecognizerDriver),
127 SERVICE_WIN32_OWN_PROCESS => Ok(ServiceType::Win32OwnProcess),
128 SERVICE_WIN32_SHARE_PROCESS => Ok(ServiceType::Win32ShareProcess),
129 _ => Err(QueryServiceError::from((
130 0,
131 "invalid service type".to_string(),
132 ))),
133 }
134 }
135}
136
137impl TryFrom<u32> for ServiceStartType {
138 type Error = QueryServiceError;
139
140 fn try_from(value: u32) -> Result<Self, Self::Error> {
141 match value {
142 SERVICE_AUTO_START => Ok(Self::AutoStart),
143 SERVICE_BOOT_START => Ok(Self::BootStart),
144 SERVICE_DEMAND_START => Ok(Self::DemandStart),
145 SERVICE_DISABLED => Ok(Self::Disabled),
146 SERVICE_SYSTEM_START => Ok(Self::SystemStart),
147 _ => Err(QueryServiceError::from((
148 0,
149 "invalid service start type".to_string(),
150 ))),
151 }
152 }
153}
154
155impl TryFrom<u32> for ServiceState {
156 type Error = QueryServiceError;
157
158 fn try_from(value: u32) -> Result<Self, Self::Error> {
159 match value {
160 SERVICE_STOPPED => Ok(ServiceState::Stopped),
161 SERVICE_START_PENDING => Ok(ServiceState::StartPending),
162 SERVICE_STOP_PENDING => Ok(ServiceState::StopPending),
163 SERVICE_RUNNING => Ok(ServiceState::Running),
164 SERVICE_CONTINUE_PENDING => Ok(ServiceState::ContinuePending),
165 SERVICE_PAUSE_PENDING => Ok(ServiceState::PausePending),
166 SERVICE_PAUSED => Ok(ServiceState::Paused),
167 _ => Err(QueryServiceError::from((
168 0,
169 "invalid service state".to_string(),
170 ))),
171 }
172 }
173}
174
175impl Drop for ServiceHandle {
176 fn drop(&mut self) {
177 if let Some(handle) = self.handle {
178 unsafe {
179 CloseServiceHandle(handle);
180 }
181 }
182 }
183}
184
185impl ServiceHandle {
186 pub fn new(handle: SC_HANDLE) -> Self {
188 Self {
189 handle: Some(handle),
190 }
191 }
192
193 pub fn state(&self) -> Result<ServiceState, QueryServiceError> {
199 let status = self.get_status()?;
200
201 ServiceState::try_from(status.dwCurrentState)
202 }
203
204 pub fn update_config(&self, options: ServiceConfig) -> Result<(), UpdateServiceError> {
210 let handle = self.handle.ok_or(UpdateServiceError::InvalidHandle(
211 0,
212 "[update_config] invalid service handle".to_string(),
213 ))?;
214
215 let display_name = U16CString::from_str(options.display_name.clone()).map_err(|_| {
216 UpdateServiceError::InvalidParameter(
217 0,
218 "[update_config] invalid display_name".to_string(),
219 )
220 })?;
221 let binary_path = U16CString::from_str(options.binary_path).map_err(|_| {
222 UpdateServiceError::InvalidParameter(
223 0,
224 "[update_config] invalid binary_path".to_string(),
225 )
226 })?;
227 unsafe {
228 if ChangeServiceConfigW(
229 handle,
230 options.service_type as u32,
231 options.start_type as u32,
232 options.error_control as u32,
233 binary_path.as_ptr(),
234 std::ptr::null(),
235 std::ptr::null_mut(),
236 std::ptr::null(),
237 std::ptr::null(),
238 std::ptr::null(),
239 display_name.as_ptr(),
240 ) == FALSE
241 {
242 return Err(UpdateServiceError::from((
243 get_last_error(),
244 "[update_config] failed".to_string(),
245 )));
246 }
247 }
248 Ok(())
249 }
250
251 pub fn get_start_type(&self) -> Result<ServiceStartType, QueryServiceError> {
257 let config = self.get_config()?;
258
259 ServiceStartType::try_from(config.dwStartType)
260 }
261
262 pub fn set_start_type(&self, start_type: ServiceStartType) -> Result<(), UpdateServiceError> {
268 let handle = self.handle.ok_or(UpdateServiceError::InvalidHandle(
269 0,
270 "[set_start_type] invalid service handle".to_string(),
271 ))?;
272 let config = self.get_config().map_err(|_| UpdateServiceError::AccessDenied(get_last_error(), "[set_start_type] failed to get service config".to_string()))?;
273
274 unsafe {
275 let mut tag_id = config.dwTagId;
276 if ChangeServiceConfigW(
277 handle,
278 config.dwServiceType,
279 start_type as u32,
280 config.dwErrorControl,
281 config.lpBinaryPathName,
282 config.lpLoadOrderGroup,
283 &mut tag_id,
284 config.lpDependencies,
285 config.lpServiceStartName,
286 std::ptr::null(),
287 config.lpDisplayName,
288 ) == FALSE
289 {
290 return Err(UpdateServiceError::from((
291 get_last_error(),
292 "[set_start_type] ChangeServiceConfig failed".to_string(),
293 )));
294 }
295 }
296 Ok(())
297 }
298 pub fn delete(&self) -> Result<(), DeleteServiceError> {
299 let handle = self.handle.ok_or(DeleteServiceError::InvalidHandle(
300 0,
301 "[delete] invalid service handle".to_string(),
302 ))?;
303 unsafe {
304 if DeleteService(handle) == FALSE {
305 return Err(DeleteServiceError::from((
306 get_last_error(),
307 "[delete] DeleteService failed".to_string(),
308 )));
309 }
310 }
311 Ok(())
312 }
313
314 pub fn start_blocking(&self) -> Result<(), ControlServiceError> {
320 self.control_blocking(ServiceState::Running, || self.start())
321 }
322
323 pub fn stop_blocking(&self) -> Result<(), ControlServiceError> {
329 self.control_blocking(ServiceState::Stopped, || self.stop())
330 }
331
332 pub fn pause_blocking(&self) -> Result<(), ControlServiceError> {
338 self.control_blocking(ServiceState::Paused, || self.pause())
339 }
340
341 pub fn start(&self) -> Result<(), ControlServiceError> {
347 let handle = self.handle.ok_or(ControlServiceError::InvalidHandle(
348 0,
349 "[start] invalid service handle".to_string(),
350 ))?;
351 unsafe {
352 if StartServiceW(handle, 0, std::ptr::null()) == FALSE {
353 return Err(ControlServiceError::from((
354 get_last_error(),
355 "[start] StartServiceW failed".to_string(),
356 )));
357 }
358 }
359
360 Ok(())
361 }
362
363 pub fn stop(&self) -> Result<(), ControlServiceError> {
369 self.control(SERVICE_CONTROL_STOP)
370 }
371
372 pub fn pause(&self) -> Result<(), ControlServiceError> {
378 self.control(SERVICE_CONTROL_PAUSE)
379 }
380 #[doc(hidden)]
381 fn control(&self, control: u32) -> Result<(), ControlServiceError> {
382 let handle = self.handle.ok_or(ControlServiceError::InvalidHandle(
383 0,
384 "[control] invalid service handle".to_string(),
385 ))?;
386
387 unsafe {
388 let mut service_status = std::mem::zeroed::<SERVICE_STATUS>();
389
390 if ControlService(handle, control, &mut service_status) == FALSE {
391 return Err(ControlServiceError::from((
392 get_last_error(),
393 "[control] ControlService failed".to_string(),
394 )));
395 }
396 }
397
398 Ok(())
399 }
400 #[doc(hidden)]
401 fn control_blocking<F>(
402 &self,
403 service_state: ServiceState,
404 control_fn: F,
405 ) -> Result<(), ControlServiceError>
406 where
407 F: Fn() -> Result<(), ControlServiceError>,
408 {
409 control_fn()?;
410
411 loop {
412 if let Ok(status) = self.state() {
413 if status == service_state {
414 break;
415 }
416 } else {
417 return Err(ControlServiceError::Unknown(
418 get_last_error(),
419 "[control_blocking] failed to get service state".to_string(),
420 ));
421 }
422
423 std::thread::sleep(std::time::Duration::from_millis(100))
424 }
425
426 Ok(())
427 }
428 #[doc(hidden)]
429 fn get_config(&self) -> Result<QUERY_SERVICE_CONFIGW, QueryServiceError> {
430 let handle = self.handle.ok_or(QueryServiceError::InvalidHandle(
431 0,
432 "[get_config] invalid service handle".to_string(),
433 ))?;
434 unsafe {
435 let mut bytes_needed: u32 = 0;
436
437 if QueryServiceConfigW(handle, std::ptr::null_mut(), 0, &mut bytes_needed) == FALSE
438 && get_last_error() != ERROR_INSUFFICIENT_BUFFER
439 {
440 return Err(QueryServiceError::from((
441 get_last_error(),
442 "[get_config] QueryServiceConfig failed".to_string(),
443 )));
444 }
445
446 let config_buffer = vec![0u8; bytes_needed as usize];
447 let config = config_buffer.as_ptr() as *mut QUERY_SERVICE_CONFIGW;
448
449 if QueryServiceConfigW(
450 handle,
451 config,
452 config_buffer.len() as u32,
453 &mut bytes_needed,
454 ) == FALSE
455 {
456 return Err(QueryServiceError::from((
457 get_last_error(),
458 "[get_config] QueryServiceConfig failed".to_string(),
459 )));
460 }
461 Ok(*config)
462 }
463 }
464 #[doc(hidden)]
465 fn get_status(&self) -> Result<SERVICE_STATUS, QueryServiceError> {
466 let handle = self.handle.ok_or(QueryServiceError::InvalidHandle(
467 0,
468 "[get_status] invalid service handle".to_string(),
469 ))?;
470 unsafe {
471 let mut status = std::mem::zeroed::<SERVICE_STATUS>();
472 if QueryServiceStatus(handle, &mut status) == FALSE {
473 return Err(QueryServiceError::from((
474 get_last_error(),
475 "[get_status] QueryServiceConfig failed".to_string(),
476 )));
477 }
478 Ok(status)
479 }
480 }
481}