Skip to content

Commit

Permalink
Merge branch 'citreae535-change_delete'
Browse files Browse the repository at this point in the history
  • Loading branch information
Andrej Mihajlov committed Feb 17, 2023
2 parents 75a4613 + 9f0da3d commit ac6c4e7
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 8 deletions.
37 changes: 31 additions & 6 deletions examples/uninstall_service.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,50 @@
#[cfg(windows)]
fn main() -> windows_service::Result<()> {
use std::{thread, time::Duration};
use std::{
thread::sleep,
time::{Duration, Instant},
};

use windows_service::{
service::{ServiceAccess, ServiceState},
service_manager::{ServiceManager, ServiceManagerAccess},
};
use windows_sys::Win32::Foundation::ERROR_SERVICE_DOES_NOT_EXIST;

let manager_access = ServiceManagerAccess::CONNECT;
let service_manager = ServiceManager::local_computer(None::<&str>, manager_access)?;

let service_access = ServiceAccess::QUERY_STATUS | ServiceAccess::STOP | ServiceAccess::DELETE;
let service = service_manager.open_service("ping_service", service_access)?;

let service_status = service.query_status()?;
if service_status.current_state != ServiceState::Stopped {
// The service will be marked for deletion as long as this function call succeeds.
// However, it will not be deleted from the database until it is stopped and all open handles to it are closed.
service.delete()?;
// Our handle to it is not closed yet. So we can still query it.
if service.query_status()?.current_state != ServiceState::Stopped {
// If the service cannot be stopped, it will be deleted when the system restarts.
service.stop()?;
// Wait for service to stop
thread::sleep(Duration::from_secs(1));
}
// Explicitly close our open handle to the service. This is automatically called when `service` goes out of scope.
drop(service);

// Win32 API does not give us a way to wait for service deletion.
// To check if the service is deleted from the database, we have to poll it ourselves.
let start = Instant::now();
let timeout = Duration::from_secs(5);
while start.elapsed() < timeout {
if let Err(windows_service::Error::Winapi(e)) =
service_manager.open_service("ping_service", ServiceAccess::QUERY_STATUS)
{
if e.raw_os_error() == Some(ERROR_SERVICE_DOES_NOT_EXIST as i32) {
println!("ping_service is deleted.");
return Ok(());
}
}
sleep(Duration::from_secs(1));
}
println!("ping_service is marked for deletion.");

service.delete()?;
Ok(())
}

Expand Down
9 changes: 7 additions & 2 deletions src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1455,8 +1455,13 @@ impl Service {
}
}

/// Delete the service from system registry.
pub fn delete(self) -> crate::Result<()> {
/// Mark the service for deletion from the service control manager database.
///
/// The database entry is not removed until all open handles to the service have been closed
/// and the service is stopped. If the service is not or cannot be stopped, the database entry
/// is removed when the system is restarted. This function will return an error if the service
/// has already been marked for deletion.
pub fn delete(&self) -> crate::Result<()> {
let success = unsafe { Services::DeleteService(self.service_handle.raw_handle()) };
if success == 0 {
Err(Error::Winapi(io::Error::last_os_error()))
Expand Down

0 comments on commit ac6c4e7

Please sign in to comment.